2
#pragma omp parallel
{
 for (i=1; i<1024; i++)
  #pragma omp for
  for (j=1; j<1024; j++)
   A[i][j] = 2*A[i-1][j];
}

このコードを実行するために 12 個のスレッドを使用しています。スピードアップするために何をしなければならないか提案はありますか?

4

2 に答える 2

1

A の型が 64 バイトより小さいと仮定すると、この方法で内側のループを並列化しようとすると、キャッシュ ラインで誤った共有が発生する可能性が高くなります。

A が 4 バイト int のアラインされた配列であるとします。同じキャッシュ ラインに A[i][0] から A[i][15] があります。これは、12 個のスレッドすべてが必要な部分ごとに同時に行を読み取ろうとすることを意味します。これをそのままにしておくと、複数のコア間で行が共有される可能性がありますが、書き込もうとすると戻ってきます。それを変更するために、各コアが回線の所有権を取得しようとします。

CPU キャッシュは通常、MESI ベースのプロトコルに基づいており、ストアの試行により所有権の読み取りが発行され、リクエスターを除く他の各コアのラインが無効になります。12 並列 (または、6 コア * それぞれ 2 スレッドの場合は 6) を発行すると、競合が発生し、最初にラインを獲得したラインが、それを変更する前に詮索によって彼からプリエンプトされる可能性が非常に高くなります(その可能性は低いですが)。結果は非常に厄介で、回線が順番に各コアに移動し、変更され、別のコアによってスヌープされるまでに時間がかかる場合があります。これは、次の連続する 16 要素のグループごとに繰り返されます (ここでも、int を想定しています)。

あなたができることは次のとおりです。

  • 個々のスレッドが独自のキャッシュラインで動作していることを確認しますが、行ごとに必要な数の要素を実行する内部ループを追加し、この数の要素をスキップするループを並列化します。

ただし、これにより、コードの空間的局所性とストリーミング プロパティが失われるため、CPU の可能性を最大限に引き出すことができなくなります。代わりに、次のことができます。

  • 各スレッドが数行にわたって動作するように外側のループを並列化して、連続するメモリ ストリーム全体を所有できるようにします。ただし、行間で順序を付ける必要があるため、ここで少し調整する必要がある場合があります (転置など)。

スレッドがあまりにも多くのストリームに遭遇すると、それらを追跡できなくなる可能性があるため、ここにはまだ欠点があります。したがって、3番目のアプローチは-

  • 配列を並べて表示 - たとえば 48 行のセットに分割し、それらをスレッド間で分散して、それぞれが数行で実行されるようにし (ここでも転置のトリックが適用されます)、次のグループに進みます。
于 2013-10-06T19:05:22.083 に答える
0

1) コアはいくつありますか? それ以上の並列処理の高速化は得られません。他の人が言ったように、おそらくはるかに少ないでしょう。

2) 内部インデックスjは 1 ではなく 0 から開始する必要があるようです。

3) その内側のループは、次のように、ポインターと展開を求めて叫びます。

double* pa = &A[i][0];
double* pa1 = &A[i-1][0];
for (j = 0; j < 1024; j += 8){
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
    *pa++ = 2 * *pa1++;
}

また...

double* pa = &A[i][0];
double* paEnd = &A[i][1024];
double* pa1 = &A[i-1][0];
for (; pa < paEnd; pa += 8, pa1 += 8){
    pa[0] = 2 * pa1[0];
    pa[1] = 2 * pa1[1];
    pa[2] = 2 * pa1[2];
    pa[3] = 2 * pa1[3];
    pa[4] = 2 * pa1[4];
    pa[5] = 2 * pa1[5];
    pa[6] = 2 * pa1[6];
    pa[7] = 2 * pa1[7];
}

どちらか速い方。

于 2013-10-06T19:58:54.613 に答える