首頁 >後端開發 >C++ >如何使用 SSE SIMD 指令在 Intel CPU 上開發快速前綴求和演算法?

如何使用 SSE SIMD 指令在 Intel CPU 上開發快速前綴求和演算法?

DDD
DDD原創
2024-11-27 11:52:09873瀏覽

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;
}

以上是如何使用 SSE SIMD 指令在 Intel CPU 上開發快速前綴求和演算法?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn