1

次のコードの実行が openmp で遅くなるという問題が発生しました。

chunk = nx/nthreads;
int i, j;
for(int t = 0; t < n; t++){
     #pragma omp parallel for default(shared) private(i, j) schedule(static,chunk) 
     for(i = 1; i < nx/2+1; i++){
        for(j = 1; j < nx-1; j++){
            T_c[i][j] =0.25*(T_p[i-1][j] +T_p[i+1][j]+T_p[i][j-1]+T_p[i][j+1]);
            T_c[nx-i+1][j] = T_c[i][j];
        }
    }
    copyT(T_p, T_c, nx);
}
print2file(T_c, nx, file);

問題は、複数のスレッドを実行すると、計算時間がはるかに長くなることです。

4

2 に答える 2

2

まず、外側のループの反復ごとに並列領域が再起動されるため、大きなオーバーヘッドが追加されます。

次に、スレッドの半分は何もせずに座っているだけです。これは、チャンク サイズが本来の 2 倍になっているためです。これnx/nthreadsは、並列ループの反復回数が であるため、合計でチャンクnx/2が存在するためです。(nx/2)/(nx/nthreads) = nthreads/2あなたが達成しようとしたことに加えて、の動作を複製することですschedule(static)

#pragma omp parallel
for (int t = 0; t < n; t++) {
   #pragma omp for schedule(static) 
   for (int i = 1; i < nx/2+1; i++) {
      for (int j = 1; j < nx-1; j++) {
         T_c[i][j] = 0.25*(T_p[i-1][j]+T_p[i+1][j]+T_p[i][j-1]+T_p[i][j+1]);
         T_c[nx-i-1][j] = T_c[i][j];
      }
   }
   #pragma omp single
   copyT(T_p, T_c, nx);
}
print2file(T_c, nx, file);

copyTparallel も使用するように変更する場合forは、single構成を削除する必要があります。default(shared)これがデフォルトなので必要ありません。並列ループのループ変数を宣言しないでください。privateこの変数が外側のスコープから来る場合でも (したがって、リージョン内で暗黙的に共有されます)、OpenMP は自動的にそれを非公開にします。ループ コントロールですべてのループ変数を宣言するだけで、デフォルトの共有ルールが適用されて自動的に機能します。

2 秒半後、(おそらく) 内部ループにエラーがあります。2 番目の割り当てステートメントは次のようになります。

T_c[nx-i-1][j] = T_c[i][j];

(またはT_c[nx-i][j]下側にハローを保持しない場合)それ以外の場合、iが等しい場合、の境界外にある which1にアクセスすることになります。T_c[nx][...]T_c

3 番目に、一般的なヒント: ある配列を別の配列にコピーする代わりに、それらの配列へのポインターを使用し、各反復の最後に 2 つのポインターを交換するだけです。

于 2012-11-13T08:45:07.133 に答える
1

あなたが投稿したスニペットには、パフォーマンスの低下につながる可能性のある問題が少なくとも 3 つあります。

  1. チャンクのサイズが小さすぎて、スレッド間で分割した場合に利益が得られません。
  2. parallelループ内でリージョンを開いたり閉じたりすると、パフォーマンスが低下する可能性があります。
  3. 最も内側の 2 つのループは独立しているように見え、そのうちの 1 つだけを並列化します (より広い反復空間を利用する可能性を失います)。

コードで行ういくつかの変更の痕跡を以下に示します。

// Moving the omp parallel you open/close the parallel 
// region only one time, not n times
#pragma omp parallel default(shared)
for(int t = 0; t < n; t++){
     // With collapse you parallelize over an iteration space that is 
     // composed of (nx/2+1)*(nx-1) elements not only (nx/2+1)
     #pragma omp for collapse(2) schedule(static)
     for(int i = 1; i < nx/2+1; i++){
        for(int j = 1; j < nx-1; j++){
            T_c[i][j] =0.25*(T_p[i-1][j] +T_p[i+1][j]+T_p[i][j-1]+T_p[i][j+1]);
            T_c[nx-i+1][j] = T_c[i][j];
        }
    }
    // As the iteration space is very small and the work done 
    // at each iteration is not much, static schedule will likely be the best option
    // as it is the one that adds the least overhead for scheduling
    copyT(T_p, T_c, nx);
}
print2file(T_c, nx, file);
于 2012-11-13T08:15:21.430 に答える