3

iこれは、1 つのループが並列化され、もう1 つのループが並列化された行列乗算コードjです。両方のバージョンで、C配列の値は正しいです (小さな行列サイズでテストしました)。また、一方から他方へのパフォーマンスの向上もありません。

これらの 2 つのバージョンの違いを教えてください。C行列のサイズに関係なく、配列は両方のバージョンで正確ですか? 前もって感謝します

void mat_multiply ( void )
{
    int t;
    int i, j, k;    
    #pragma omp parallel for private(k) // parallelize i loop
    for(i = 0; i < dimension; i++)
    {
        for(j = 0; j < dimension; j++) 
        {
            for(k = 0; k < dimension; k++)
            {
                C[dimension*i+j] += A[dimension*i+k] *  B[dimension*k+j];       
            }
        }
    }
 }

 void mat_multiply ( void )
 {
     int t;
     int i, j, k;   

     for(i = 0; i < dimension; i++)
     {
         #pragma omp parallel for private(k) // parallelize j loop
         for(j = 0; j < dimension; j++) 
         {
             for(k = 0; k < dimension; k++)
             {
                 C[dimension*i+j] += A[dimension*i+k] *  B[dimension*k+j];      
             }
         }
     }
 }
4

1 に答える 1

5

最初は、最初のバージョンはスレッドを 1 回しか作成しないため、スレッド作成のオーバーヘッドが少ないように見えます。2番目のバージョンでは、スレッドが作成されるようですdimension

しかし、これによる

内側のループ内で新しいスレッドが作成されることを心配する人がいるかもしれません。心配しないでください。GCC の libgomp は、実際にはスレッドを 1 回しか作成しないほどスマートです。チームが作業を完了すると、スレッドは「ドック」に戻され、新しい作業が行われるのを待ちます。

つまり、クローン システム コールが実行される回数は、同時スレッドの最大数とまったく同じです。parallel ディレクティブは、pthread_create と pthread_join の組み合わせと同じではありません。

j最初のバージョンでは、変数もプライベートであることを保証する必要があります。

2 つのアプローチを使用する代わりに、入れ子になったループを並列化する方法を 1 つだけ使用できます。OpenMP 3.0では、ネストされたループの並列化は、forディレクティブのcollapse 句によって処理できます。つまり、次のようになります。

void mat_multiply ( void ) {
   
    #pragma omp parallel for collapse(2)
    for(int i = 0; i < dimension; i++)
      for(int j = 0; j < dimension; j++)
        for(int k = 0; k < dimension; k++)
            C[dimension*i+j] += A[dimension*i+k] *  B[dimension*k+j];        
  }

ところで: ブロック アプローチを調べてみてください。ここで例を確認できます(スライド 62 から)。

于 2012-11-27T01:11:33.323 に答える