2

粒子ベースのシミュレーションのコードを並列化しようとしていますが、OpenMP ベースのアプローチのパフォーマンスが低下しています。つまり、次のことを意味します。

  • Linux ツールを使用して CPU 使用率を表示するtopと、CPU を実行している OpenMP スレッドの平均使用率は 50% です。
  • スレッド数が増えると、速度は約 1.6 倍に収束します。収束は非常に高速です。つまり、2 つのスレッドを使用して 1.5 の速度アップに達しました。

次の疑似コードは、実装されたすべての並列領域の基本テンプレートを示しています。1 つの時間ステップ中に、以下に示すように 5 つの並列領域が実行されることに注意してください。基本的に、粒子に作用する力i < Nは、隣接する粒子のいくつかのフィールド プロパティの関数ですj < NN(i)

omp_set_num_threads(ncpu);

#pragma omp parallel shared( quite_a_large_amount_of_readonly_data, force )
{
   int i,j,N,NN;

   #pragma omp for 
    for( i=0; i<N; i++ ){             // Looping over all particles
       for ( j=0; j<NN(i); j++ ){     // Nested loop over all neighbors of i
          // No communtions between threads, atomic regions,
          // barriers whatsoever.
          force[i] += function(j);
       }
    }
}

観察されたボトルネックの原因を整理しようとしています。説明のための私の素朴な最初の推測:

前述のように、読み取り専用アクセスのためにスレッド間で共有される大量のメモリがあります。異なるスレッドが同じメモリ位置を同時に読み取ろうとする可能性は十分にあります。これはボトルネックを引き起こしていますか? OpenMP にプライベート コピーを割り当てさせるべきでしょうか?

4

3 に答える 3

2

はどのくらいの大きさでN、どのくらい集中的ですNN(i)か?

あなたは何も共有していないと言いますが、force[i]おそらく の同じキャッシュライン内にありforce[i+1]ます。これは偽の共有と呼ばれるものであり、かなり有害な場合があります。OpenMP はこれを補うためにバッチ処理を行う必要があるため、十分な大きさNがあれば、これが問題になることはないと思います。

NN(i)CPU の使用率がそれほど高くない場合は、単純なメモリ ボトルネックが発生している可能性があります。この場合、より多くのコアを投入しても何も解決しません。

于 2012-12-27T21:17:35.320 に答える
1

force[i] が 4 バイトまたは 8 バイト データのプレーンな配列であると仮定すると、間違いなく偽共有が発生します。

function(j) が独立して計算されると仮定すると、次のようにすることができます。

    for( i=0; i<N; i+=STEP ){             // Looping over all particles
       for ( j=0; j<NN(i); j+=STEP ){     // Nested loop over all neighbors of i
          // No communtions between threads, atomic regions,
          // barriers whatsoever.
       calc_next(i, j);
       }
    }


void calc_next(int i, int j)
{
    int ii, jj;
    for(ii = 0; ii < STEP; ii++)
    {
        for(jj = 0; jj < STEP; jj++)
        {
            force[i+ii] = function(j+jj);
        }
    }
}

そうすれば、1 つのスレッドで一連のことを計算し、次のスレッドで一連のことを計算できます。各束は十分に離れているため、誤った共有が発生することはありません。

このようにできない場合は、別の方法で分割して、毎回より大きなセクションが計算されるようにしてください。

于 2012-12-27T21:46:23.213 に答える
0

As the others stated that, false sharing on force could be a reason. Try in this simple way,

#pragma omp for 
for( i=0; i<N; i++ ){
   int sum = force[i];
   for ( j=0; j<NN(i); j++ ){
      sum += function(j);
   }
   force[i] = sum;
}

Technically, it's possible that force[i] = sum still makes a false sharing. But, it's highly unlikely to happen because the other thread would access force[i + N/omp_num_threads()*omp_thread_num()], which is pretty far from force[i].

If still scalability is poor, try to use a profiler such as Intel Parallel Amplifier (or VTune) to see how much memory bandwidth is needed per thread. If so, put some more DRAMs in your computer :) That will really boost memory bandwidth.

于 2013-01-11T00:11:31.580 に答える