7

私はOpenMPを使用した行列乗算のプログラムを作成しています。これは、キャッシュの利便性のために、従来のA x B行x列ではなく、乗算A x B(転置)行X行を実装して、キャッシュ効率を向上させます。これを行うと、私にとっては非論理的であるという興味深い事実に直面しました。このコードでexternループを並列化すると、OpenMPディレクティブを最も内側のループに配置した場合よりもプログラムが遅くなります。私のコンピューターでは、時間は10.9秒対8.1秒です。

//A and B are double* allocated with malloc, Nu is the lenght of the matrixes 
//which are square

//#pragma omp parallel for
for (i=0; i<Nu; i++){
  for (j=0; j<Nu; j++){
    *(C+(i*Nu+j)) = 0.;
#pragma omp parallel for
    for(k=0;k<Nu ;k++){
      *(C+(i*Nu+j))+=*(A+(i*Nu+k)) * *(B+(j*Nu+k));//C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
  }
}
4

2 に答える 2

4

外側のループを並列化し、コンパイラがそれを把握できず、追加のロックを追加する場合、おそらくデータにいくつかの依存関係がある可能性があります。

おそらく、異なる外側のループ反復が同じループに書き込むことができると判断し、(C+(i*Nu+j))それを保護するためにアクセス ロックを追加します。

2 番目のループを並列化すると、コンパイラはおそらく依存関係がないことを理解できます。しかし、外側のループを並列化する依存関係がないことを理解することは、コンパイラにとってそれほど簡単ではありません。

アップデート

いくつかのパフォーマンス測定。

また会ったね。1000 double のように見え、スレッド同期のコストをカバーする*+は不十分です。

小さなテストをいくつか行ったことがありますが、単純なベクトルのスカラー乗算は、要素数が ~10'000 未満でない限り、openmp では効果がありません。基本的に、配列が大きいほど、openmp を使用してパフォーマンスが向上します。

したがって、最も内側のループを並列化するには、タスクを異なるスレッド間で分離し、データを 1'000'000 回収集する必要があります。

PS。Intel ICC を試してみてください。学生やオープンソース プロジェクトには無料で使用できます。10,000 要素未満の配列には openmp を使用していたことを覚えています。

更新 2: 削減の例

    double sum = 0.0;
    int k=0;
    double *al = A+i*Nu;
    double *bl = A+j*Nu;
    #pragma omp parallel for shared(al, bl) reduction(+:sum)
    for(k=0;k<Nu ;k++){
        sum +=al[k] * bl[k]; //C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
    C[i*Nu+j] = sum;
于 2011-01-18T17:00:07.667 に答える
4

結果をヒットする頻度を減らしてください。これにより、キャッシュラインの共有が誘導され、操作が並行して実行されなくなります。代わりにローカル変数を使用すると、ほとんどの書き込みを各コアの L1 キャッシュで行うことができます。

また、 を使用するとrestrict役立つ場合があります。そうしないと、コンパイラは、およびへの書き込みCが変更されていないことを保証できません。AB

試す:

for (i=0; i<Nu; i++){
  const double* const Arow = A + i*Nu;
  double* const Crow = C + i*Nu;
#pragma omp parallel for
  for (j=0; j<Nu; j++){
    const double* const Bcol = B + j*Nu;
    double sum = 0.0;
    for(k=0;k<Nu ;k++){
      sum += Arow[k] * Bcol[k]; //C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
    Crow[j] = sum;
  }
}

また、一番内側のループを並列化する場合はリダクションが必要だという Elalfer の意見は正しいと思います。

于 2011-01-18T18:57:20.373 に答える