0

以下のコードでは、OpenMP の標準parallel for節を使用して並列化しています。

#pragma omp parallel for private(i, j, k, d_equ) shared(cells, tmp_cells, params)
for(i=0; i<some_large_value; i++)
{
   for(j=0; j<some_large_value; j++)
   {
       ....
       // Some operations performed over here which are using private variables
       ....

       // Accessing a shared array is causing False Sharing
       for(k=0; k<10; k++)
       {
          cells[i * width + j].speeds[k] = some_calculation(i, j, k, cells);
       }
   }
}

これにより、ランタイムが大幅に改善されました (~140 秒から~40 秒) が、実際に遅れていることに気付いた領域がまだ 1 つあります。それは、上記でマークした最も内側のループです。

上記の配列が False Sharing を引き起こしていることは確かです。なぜなら、以下の変更を加えると、パフォーマンスがさらに大幅に向上する (~40 秒から ~13 秒) ためです。

 for(k=0; k<10; k++)
 {
     double somevalue = some_calculation(i, j);
 }

つまり、メモリの場所をプライベート変数に書き込むように変更するとすぐに、速度が大幅に向上しました。

今説明したシナリオで False Sharing を回避することでランタイムを改善する方法はありますか? 問題自体は何度も言及されていますが、この問題に役立つと思われる多くのリソースをオンラインで見つけることができないようです.

非常に大きな配列 (必要なものの 10 倍) を作成して、各要素の間に十分なマージン スペースを確保し、キャッシュ ラインに入ったときに他のスレッドがそれを取得しないようにするというアイデアがありました。ただし、これは目的の効果を生み出すことができませんでした。

そのループで見つかった False Sharing を削減または削除する簡単な (または必要に応じて難しい) 方法はありますか?

どんな形の洞察や助けも大歓迎です!

EDIT : some_calculation() が次のことを行うと仮定します:

 (tmp_cells[ii*params.nx + jj].speeds[kk] + params.omega * (d_equ[kk] - tmp_cells[ii*params.nx + jj].speeds[kk]));

反復ごとに計算される d_equ に依存しているため、この計算を for ループの外に移動することはできません。

4

1 に答える 1

1

あなたの質問に答える前cellsに、関数の入力として全体を使用すると、本当に偽の共有状況になるのsome_calcutation()でしょうか? 実際に配列全体を共有しているようです。この機能に関する詳細情報を提供することをお勧めします。

はいの場合は、次の手順に進みます。

プライベート変数double somevalueがパフォーマンスを向上させることは既に示しました。このアプローチを使用しないのはなぜですか?

単一のdouble変数を使用する代わりに、ループprivate_speed[10]の直前にプライベート配列を定義し、ループでそれらを計算し、ループの後にfor kコピーして戻すことができます。cells

 memcpy(cells[i*width+j].speed, private_speed, sizeof(...));
于 2013-10-13T18:58:32.277 に答える