OpenMP を使用しているからといって、プログラムが高速に実行されるわけではありません。ここでいくつかのことが起こっている可能性があります。
各スレッドの生成にはコストがかかります。スレッドを生成して少量の計算を行うと、スレッド自体の生成に計算よりも多くの時間がかかります。
デフォルトでは、OpenMP は CPU がサポートする最大数のスレッドを生成します。コアごとに 2 つ以上のスレッドをサポートする CPU では、スレッドは各コアのリソースをめぐって競合します。を使用omp_get_num_threads()
すると、デフォルトで生成されるスレッドの数を確認できます。を使用して、その半分の値でコードを実行することをお勧めしますomp_set_num_threads()
。
OpenMP の有無にかかわらず、結果が同じであることを確認しましたか? 変数 j と c2 には依存関係があるようです。それらを各スレッドに対してプライベートに宣言する必要があります。
#pragma omp parallel for private(j,c2)
もう 1 つ付け加えておきたいことがあります。並列化を試みる前に、コードが既に最適化されていることを確認する必要があります。
コンパイラ、コンパイラ フラグ、および命令の複雑さに応じて、コンパイラはコードを最適化する場合としない場合があります。
// avoid calculation nnoib-2 every iteration
int t_nnoib = nnoib - 2;
for (i=2; i< t_nnoib; ++i){
// avoid calculation nnojb-2 every iteration
int t_nnojb = nnojb - 2;
// avoid loading absi[i] every iteration
int t_absi = absi[i];
for (j=2; j< t_nnojb; ++j) {
C[i][j]= t_absi * absj[j] *
(2.0f*B[i][j] + t_absi * absj[j] *
(VEL[i][j] * VEL[i][j] * fat *
(16.0f * (B[i][j-1] + B[i][j+1] + B[i-1][j] + B[i+1][j])
-1.0f * (B[i][j-2] + B[i][j+2] + B[i-2][j] + B[i+2][j])
-60.0f * B[i][j]
) - A[i][j]));
// c2 is a useless variable
if (abs(C[i][j]) > Amax[i][j]) {
Amax[i][j] = abs(C[i][j]);
Ttra[i][j] = t;
}
}
}
大したことではないように思えるかもしれませんが、コードに大きな影響を与える可能性があります。コンパイラは、ローカル変数をレジスタに配置しようとします (アクセス時間がはるかに高速です)。レジスタの数が限られているため、この手法を無期限に適用することはできないことに注意してください。これを悪用すると、コードでレジスタ スピルが発生します。
array の場合、ループabsi
の実行中にシステムがその配列の一部をキャッシュに保持することを回避できます。j
この手法の一般的な考え方は、内側のループの変数に依存しない配列アクセスを外側のループに移動することです。