12

これは私のコードです:

double res1[NNN];  
#pragma omp parallel for collapse(3) schedule(dynamic) 
for (int i=0; i<NNN; i++)
{
    for (int j=0;j<NNN;j++)
    {
        for (int k=0;k<NNN;k++)
        {
            res1[i] = log(fabs(i*j*k));
        }
    }
}
std::cout<< res1[10] << std::endl;

私が使用する場合collapse(3)、それは約50秒かかります。collapse(3)たった6〜7秒なしで。「折りたたみ」を使用しない場合よりも「折りたたみ」を使用した場合の方がパフォーマンスが向上することを期待していたため、この動作には非常に戸惑っています。

私は何かが足りないのですか?


私はいくつかの実験を行い、さまざまな構成で遊んだ:

(NNN = 2500および24コア)

  1. schedule(STATIC)&& collapse(3)->〜54秒
  2. schedule(STATIC)&& collapse(2)->〜8秒
  3. schedule(STATIC)&& collapse(1)->〜8秒

スケジュールも試してみましDYNAMICたが、かなりの時間(数分)かかります。


私の元の問題では、4つのDIM「for-loops」(4D配列)があります:51x23x51x23。

OpenMP / MPIを使用して実行時間を最小限に抑えるための最良の方法は何ですか?合計で約300個のCPUコアがあります。これらのコアにアレイを広げるための最良の方法は何ですか?配列の長さは柔軟です(なんらかの方法でCPUの数に合わせることができます)。

助言がありますか?

4

1 に答える 1

25

OpenMPオーバーヘッドで動的スケジューリングを使用することの影響についての概念が欠けています。

動的スケジューリングは、各ループの反復に異なる時間がかかる可能性があるロードバランスの問題を解決するために使用する必要があります、および静的反復分散は、異なるスレッド間で作業の不均衡を引き起こす可能性があります。作業の不均衡により、CPU時間が無駄になります。これは、先に終了したスレッドが他のスレッドが終了するのを待つだけだからです。動的スケジューリングは、先着順でループチャンクを分散することにより、これを克服します。ただし、OpenMPランタイムシステムは、反復が実行された場合と実行されなかった場合の簿記を実装する必要があり、ある種の同期を実装する必要があるため、オーバーヘッドが追加されます。また、各スレッドは、反復ブロックを終了して別のスレッドを探しに行くたびに、OpenMPランタイムを少なくとも1回呼び出す必要があります。静的スケジューリングでは、すべての反復ブロックが最初に事前計算され、その後、OpenMPランタイム環境との相互作用なしに各スレッドがその部分を実行します。

静的スケジューリングと動的スケジューリングの最も重要な違いは、反復チャンクサイズ(つまり、反復空間の別の部分で作業を行う前に各スレッドが実行する連続ループ反復の数)です。省略した場合、静的スケジューリングのチャンクサイズはデフォルトでになりますが、#_of_iterations/#_of_threads動的スケジューリングのデフォルトのチャンクサイズはです。つまり、各スレッドは、分散ループの各反復1についてOpenMPランタイムに要求する必要があります。

あなたの場合に起こることは、外側のループの反復チャンクがなくcollapse(3)NNN各スレッドがNNN*NNNOpenMPランタイムに別の反復を要求する前に(内側のループの)反復を実行することです。ループを折りたたむと、反復チャンクの数がに増えますNNN*NNN*NNN。つまり、さらに多くのチャンクがあり、各スレッドは、各反復後にOpenMPランタイムにチャンクを要求します。

これは、内側のループが最も外側で折りたたまれている場合に別の問題を引き起こします。多くのスレッドが同じ値の反復を取得することが発生しますi。これにより、実行の順序が保証されないため、計算が中断され、最後のスレッドが発生する可能性があります。書き込み先res1[i]は、両方の内部ループの最後の反復を実行するものではありません。

于 2013-03-01T15:26:08.297 に答える