大学のコースの一環として、OpenMP の使用方法を学び始めました。ラボの演習として、並列化する必要があるシリアル プログラムが与えられました。
False Sharingの危険性を最初に認識したことの 1 つは、特に for ループで並列に配列を更新する場合です。
ただし、False Sharing を発生させずに、次のコード スニペットを並列化可能なタスクに変換するのは難しいと思います。
int ii,kk;
double *uk = malloc(sizeof(double) * NX);
double *ukp1 = malloc(sizeof(double) * NX);
double *temp;
double dx = 1.0/(double)NX;
double dt = 0.5*dx*dx;
// Initialise both arrays with values
init(uk, ukp1);
for(kk=0; kk<NSTEPS; kk++) {
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] = uk[ii] + (dt/(dx*dx))*(uk[ii+1]-2*uk[ii]+uk[ii-1]);
}
temp = ukp1;
ukp1 = uk;
uk = temp;
printValues(uk,kk);
}
私の最初の反応は、ukp1を共有してみることでした:
for(kk=0; kk<NSTEPS; kk++) {
#pragma omp parallel for shared(ukp1)
for(ii=1; ii<NX-1; ii++) {
ukp1[ii] = uk[ii] + (dt/(dx*dx))*(uk[ii+1]-2*uk[ii]+uk[ii-1]);
}
temp = ukp1;
ukp1 = uk;
uk = temp;
printValues(uk,kk);
}
しかし、これは明らかにシリアル バージョンと比較して大幅な速度低下を示しています。明らかな理由は、 ukp1への書き込み操作中に False 共有が発生していることです。
リダクション句を使用できるのではないかという印象を受けましたが、これは配列では使用できないことがすぐにわかりました。
このコードを並列化してランタイムを改善するために使用できるものはありますか? 聞いたことのない使用できる条項はありますか? それとも、適切な並列化を可能にするためにコードを再構築する必要があるようなタスクですか?
あらゆる形式の入力をお待ちしております。
EDIT:私のコードに間違いがあったと指摘されました。私がローカルに持っているコードは正しいです。間違って編集しただけです (コードの構造が変更されました)。混乱して申し訳ありません!
EDIT2:
@Sergeyが私に指摘してくれたいくつかの情報は、私が役に立つと感じています:
uk または ukp1 をプライベートに設定すると、基本的に共有に設定するのと同じ効果があります。これは、両方とも同じメモリ位置へのポインターであるためです。
静的スケジューリングを使用すると、理論的には役立つはずですが、私はまだ同じ速度低下を経験しています。また、静的スケジューリングは、この問題を修正する最も移植性の高い方法ではないと感じています。