簡體   English   中英

OpenMP減少同步錯誤

[英]OpenMP reduction synchronization error

我試圖用相互依賴的循環並行化一個循環,我嘗試了減少和代碼工作,但結果是錯誤的,我認為減少適用於總和但不適用於右邊的數組更新循環,有一種方法可以獲得正確的結果並行循環?

#pragma omp parallel for reduction(+: sum)
for (int i = 0; i < DATA_MAG; i++)
{
    sum += H[i];

    LUT[i] = sum * scale_factor;
}

reduction子句為團隊中的每個線程創建sum私有副本,就好像private子句已用於sum 在for循環之后,每個私有副本的結果與sum的原始共享值組合。 由於共享sum僅在for循環之后更新,因此您不能在for循環內部依賴它。

在這種情況下,您需要做一個前綴和。 不幸的是, 使用線程並行前綴和是大型DATA_MAG綁定的內存帶寬,而小型DATA_MAG的OpenMP開銷DATA_MAG主導地位。 但是,在小型和大型之間可能存在一些最佳位置,您可以使用線程看到一些好處。

但在你的情況下, DATA_MAG只有256,非常小,無論如何都不會從OpenMP中受益。 你能做的就是使用SIMD。 但是,就我所知,OpenMP的simd結構對於前綴sum來說還不夠強大。 但是,您可以手動執行這樣的內在函數

#include <stdio.h>
#include <x86intrin.h>

#define N 256

inline __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_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 8)));
  return x;
}

void prefix_sum_SSE(float *a, float *s, int n, float scale_factor) {
  __m128 offset = _mm_setzero_ps();
  __m128 f = _mm_set1_ps(scale_factor);
  for (int i = 0; i < n; i+=4) {
    __m128 x = _mm_loadu_ps(&a[i]);
    __m128 out = scan_SSE(x);
    out = _mm_add_ps(out, offset);
    offset = _mm_shuffle_ps(out, out, _MM_SHUFFLE(3, 3, 3, 3));
    out = _mm_mul_ps(out, f); 
    _mm_storeu_ps(&s[i], out);
  }
}

int main(void) {
  float H[N], LUT[N];
  for(int i=0; i<N; i++) H[i] = i;
  prefix_sum_SSE(H, LUT, N, 3.14159f);
  for(int i=0; i<N; i++) printf("%.1f ", LUT[i]); puts("");
  for(int i=0; i<N; i++) printf("%.1f ", 3.14159f*i*(i+1)/2); puts("");

}

有關使用SSE和AVX的SIMD預修和的更多詳細信息,請參見此處

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM