2017-11-15 3 views
0

私はopenMPについて少し学び、ここで2つの行列を掛け合わせようとしています。Matrix Multiply(OpenMP)の最適化 - C

void matrix_multiply(matrix *A, matrix *B, matrix *C) { 

    #pragma omp parallel 
    { 
     #pragma omp for 
     for(int i = 0; i < A->dim.rows; i++) { 
      for(int j = 0; j < B->dim.cols; j++) { 
       C->data[i][j] = 0; 
       for (int k = 0; k < A->dim.cols; k++) { 
       C->data[i][j] += A->data[i][k] * B->data[k][j]; 
       } 
      } 
     } 
    } 
} 

typedef struct shape { 
    int rows; 
    int cols; 
} shape; 

typedef struct matrix { 
    shape dim; 
    float** data; 
} matrix; 

まだ少し新しくなっていますので、パフォーマンスを改善するための簡単な変更はありますか、すでに行っていますか?また、削減を使わないことでデータレースに参加していますか?

答えて

2

あなたの現在の実装を改善することはできません。この時点で、コンパイラとキャッシュの使用法になります。興味深い点は、GCCが乗算をベクトル化する(すなわちSIMDを使用する)ために2つのループを入れ替えることを必要とするという興味深い点が作られている。非常に大きな行列の場合、行列をストライプではなくブロックで分割することを検討することができます。これにより、複雑さとオーバーヘッドが発生しますが、キャッシュ使用率が向上します。

還元節は、単一の変数を複数のスレッドで合計する場合にのみ必要です。これは、k以上の合計であるため、ここでは該当しません。

は、最後に私の意見では、ややきれいに見えたあなたは、単一の1

#pragma omp parallel for 

によって2つのディレクティブを置き換えることができます(ただし、これは完全に個人的です)。

+0

これは教育的練習問題(つまり、OpenMPを使用する方法を学ぶ)の場合は問題ありません。高性能行列の乗算が必要な場合は、今すぐ停止してください。代わりに、より多くの最適化を持つインテル®MKLなどのライブラリ(キャッシュ・ブロッキングなど)を探してください。確かに、あなたの素朴な並列化のパフォーマンスをMKLのものと比較することは興味深いかもしれません... –