2012-05-02 15 views
1

入れ子のforループを並列化するのに問題があります。コードは、この入れ子になったループを減らすためにompを使う

for(k = 0; k < m; k++) { 
    for(i = 0; i < k; i++) { 
     s = 0.0; 
#pragma omp parallel for default(none) shared(i, k, q, m, n) private(j) reduction(+:s) 
     for(j = 0; j < n; j++) { 
     s += q[ i ][ j ] * q[ k ][ j ]; 
     } 
    } 
    } 

このコードの作品のようになりますが、「K」と「I」のループの下に何回ものスレッドを作成し、破棄する際によるオーバーヘッドのために非常に遅い実行されます。

理想的には私は、並列領域は一度だけ作成され、この

#pragma omp parallel default(none) shared(i, k, q, m, n, s) private(j) 
    for(k = 0; k < m; k++) { 
    for(i = 0; i < k; i++) { 
     s = 0.0; 
#pragma omp for reduction(+:s) 
     for(j = 0; j < n; j++) { 
     s += q[ i ][ j ] * q[ k ][ j ]; 
     } 
    } 
    } 

ような何かをしたいです。しかし、私は間違った結果を得ています。私はこれが変数 's'が共有されているためだと思います。

's'を共有して引き続き削減を行う方法はありますか?

ありがとうございます!

P.S.以前の反復に依存するので、私は 'k'または 'i'ループを並列化できません。

+0

並列化できる内部ループだけの場合は、並列化を高速化する可能性は低いです。余りにも計算が少なく、 'n 'が大きければメモリに束縛されます。 – Mysticial

+0

ループの順序を変更しましたか?あなたのコードでは、 'k'と' i'のループの前に、 'j'のループを最初に置くことができます。これを行うと、q [k] [j]の値は 'i'以上のループの定数になるので、安全にループから抜け出します。 –

+0

うん、ここではうまくいかないのは分かりません。各 'i'-iterationで' s'をリセットしていますか? –

答えて

1

あなたが省略したiのループ内にコードがありますか、それともありますか?そのコードは多くのドット積を計算するだけなので、最後にq[m-1][]q[m-2][]のドット積がsに格納されます。また、与えられたように、あなたのコードはループ反復間のデータ依存性を持たないが、静的スケジューリングを使用して他のループを並列化すると、むしろ負荷不均衡を示すだろう。

#pragma omp parallel default(none) shared(q, m, n) \ 
      private(i, k, j) lastprivate(s) schedule(dynamic,1) 
for(k = 0; k < m; k++) { 
    for(i = 0; i < k; i++) { 
    s = 0.0; 
    for(j = 0; j < n; j++) { 
     s += q[ i ][ j ] * q[ k ][ j ]; 
    } 
    } 
} 

コンパイラがバージョン3.0以上の標準をサポートしている場合は、OpenMPタスクを使用することもできます。

@Zhenyaの場合、jループが最も外側にある場合、q[i][j]q[i+1][j]はC/C++のメモリ内に隣接していないため、キャッシュの利点は失われます。

+0

スケジュール(ダイナミック、1)とスケジュール(ガイド付き)の違いは何ですか? – Azrael3000

+0

'schedule(dynamic、1)'は、各反復が現在アイドル状態のスレッドに割り当てられていることを意味します。 'schedule(dynamic、10)'は10反復のブロックが割り当てられることを意味します。 'schedule(guided)'は** dynamic **のように動作しますが、大きな反復ブロックから始まり、指数関数的にブロックサイズを縮小します。実際、その場合は**ガイド付き**がより良いスケジュール設定オプションかもしれません。 –