> 백엔드 개발 > C++ > 본문

Intel CPU에서 빠른 접두사 합계 알고리즘을 개발하기 위해 SSE SIMD 명령어를 어떻게 사용할 수 있습니까?

DDD
풀어 주다: 2024-11-27 11:52:09
원래의
855명이 탐색했습니다.

How Can SSE SIMD Instructions Be Used to Develop a Fast Prefix Sum Algorithm on Intel CPUs?

Intel CPU의 SIMD 접두사 합계

질문:

SSE SIMD CPU를 사용하여 빠른 접두사 합 알고리즘 개발 지침.

답변:

최적의 솔루션에는 두 개의 병렬 패스가 ​​포함됩니다.

패스 1:

  • SSE를 사용하여 부분합을 병렬로 계산합니다. SIMD.
  • 각 부분 합에 대한 총합을 저장합니다.

패스 2:

  • 다음 부분합으로 이전 부분합을 사용합니다. SIMD.

이점:

  • 병렬화는 두 패스 모두에서 계산 시간을 줄여줍니다.
  • 패스 2의 SIMD 최적화는 더욱 향상됩니다. 성능.

구현 참고 사항:

  • 알고리즘의 시간 비용은 (n/m)*(1 1/w)로 추정됩니다. , 여기서 n은 배열 크기, m은 코어 수, w는 SIMD 너비입니다.
  • 이 알고리즘은 순차 구현보다 빠르며 쿼드 코어 시스템에서 약 7배의 속도 향상 요소를 제공합니다.
  • 대규모 어레이의 경우 데이터를 캐시에 유지하면서 청크를 순차적으로 청크하고 실행하여 두 번째 패스를 더욱 최적화할 수 있습니다.

코드 예:

__m128 scan_SSE(__m128 x) {
    x = _mm_add_ps(x, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 4)));
    x = _mm_add_ps(x, _mm_shuffle_ps(_mm_setzero_ps(), x, 0x40));
    return x;
}

float pass1_SSE(float *a, float *s, const int n) {
    __m128 offset = _mm_setzero_ps();
    #pragma omp for schedule(static) nowait
    for (int i = 0; i < n / 4; i++) {
        __m128 x = _mm_load_ps(&a[4 * i]);
        __m128 out = scan_SSE(x);
        out = _mm_add_ps(out, offset);
        _mm_store_ps(&s[4 * i], out);
        offset = _mm_shuffle_ps(out, out, _MM_SHUFFLE(3, 3, 3, 3));
    }
    float tmp[4];
    _mm_store_ps(tmp, offset);
    return tmp[3];
}

void pass2_SSE(float *s, __m128 offset, const int n) {
    #pragma omp for schedule(static)
    for (int i = 0; i<n/4; i++) {
        __m128 tmp1 = _mm_load_ps(&s[4 * i]);
        tmp1 = _mm_add_ps(tmp1, offset);
        _mm_store_ps(&s[4 * i], tmp1);
    }
}

void scan_omp_SSEp2_SSEp1_chunk(float a[], float s[], int n) {
    float *suma;
    const int chunk_size = 1<<18;
    const int nchunks = n%chunk_size == 0 ? n / chunk_size : n / chunk_size + 1;

    #pragma omp parallel
    {
        const int ithread = omp_get_thread_num();
        const int nthreads = omp_get_num_threads();

        #pragma omp single
        {
            suma = new float[nthreads + 1];
            suma[0] = 0;
        }

        float offset2 = 0.0f;
        for (int c = 0; c < nchunks; c++) {
            const int start = c*chunk_size;
            const int chunk = (c + 1)*chunk_size < n ? chunk_size : n - c*chunk_size;
            suma[ithread + 1] = pass1_SSE(&a[start], &s[start], chunk);
            #pragma omp barrier
            #pragma omp single
            {
                float tmp = 0;
                for (int i = 0; i < (nthreads + 1); i++) {
                    tmp += suma[i];
                    suma[i] = tmp;
                }
            }
            __m128 offset = _mm_set1_ps(suma[ithread]+offset2);
            pass2_SSE(&s[start], offset, chunk);
            #pragma omp barrier
            offset2 = s[start + chunk-1];
        }
    }
    delete[] suma;
}
로그인 후 복사

위 내용은 Intel CPU에서 빠른 접두사 합계 알고리즘을 개발하기 위해 SSE SIMD 명령어를 어떻게 사용할 수 있습니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿