明示的なタスク バージョンを実装した次のコードがあります。
int waves = N_a + N_b +1; /*considering N_a == N_b */
#pragma omp parallel firstprivate(a, gap, waves) private(temp, wave, ii, i) shared(np, mp, elements)
{
#pragma omp master
{
for(wave = 0; wave < waves; ++wave) {
// 0 <= wave < n-1
if(wave < N_a-1) {
elements = wave+1;
np = wave+1;
mp = 0+1;
}
// n-1 <= wave < m
else if(wave < N_b) {
elements = N_a;
np = N_a-1+1;
mp = wave-(N_a-1)+1;
}
// m <= wave < m+n-1
else {
elements = N_a-1-(wave-N_b);
np = N_a-1+1;
mp = wave-(N_a-1)+1;
}
for(ii = 0; ii < elements; ii+=chunk) {
min = MIN(elements,ii + chunk);
#pragma omp task firstprivate(ii, np, mp, chunk, elements)
{
for (i = ii; i < min; i++)
{
temp[0] = H[(np-i)-1][(mp+i)-1] + similarity(seq_a[a][(np-i)-1],seq_b[a][(mp+i)-1]);
temp[1] = H[(np-i)-1][(mp+i)]-gap;
temp[2] = H[(np-i)][(mp+i)-1]-gap;
temp[3] = 0;
H[(np-i)][(mp+i)] = find_array_max(temp,4);
}
} // task
} //for loop
#pragma omp taskwait
}
}
}
奇妙なことに、コードを実行すると、1 スレッドのパフォーマンスが 2、4、8、16 スレッドのパフォーマンスよりもはるかに優れています。並列領域は 1 つしかなく、内側の for ループをストリップマイニングして、すべての「チャンク」数の要素がタスクの作成に寄与するようにしました。
タスクの実装を作成することを強く主張します。これは、この要素の値が常に変化し、コードが効率的なタスクの実装で構造化されていない並列処理に対抗できる可能性があると感じているためです。
Intel xe12 バージョンのコンパイラでこれを試しています。以下は、私が観察しているサンプル チャンク サイズの測定値です: 256 および N_a = N_b = 4096:
1 スレッド: 1.237560 2 スレッド: 7.223232 4 スレッド: 4.579173 8 スレッド: 3.663661 16 スレッド: 4.425525
gcc コンパイラの同様の動作に気付きました。1 つのスレッドのコードが複数のスレッドよりも優れている理由を教えてください。N_a = N_b = 1024、2048、8192 でも同様の結果が得られます。
ありがとう。