2016-09-19 4 views
1

私はこの質問をFortranの観点から書いていますが、質問はFortranだけに限定されていません(したがってC++タグ)。openmp並列待ち時間を緩和するための対策

私には2つの質問があります。私は、OpenMP並列ループhereの開始と停止時にレイテンシが存在することを読んだ。私の質問は次のとおりです:

Q1)OpenMPの待ち時間を緩和するための実践的な措置はありますか?

Q2次のいずれの方法が優れていますか?

方法1

x = 1.0; y = 2.0 
!$OMP PARALLEL DO 
do k=1,Nz; do j=1,Ny; do i=1,Nx 
x(i,j,k) = x(i,j,k)+y(i,j,k) 
enddo; enddo; enddo 
!$OMP END PARALLEL DO 

!$OMP PARALLEL DO 
do k=1,Nz; do j=1,Ny; do i=1,Nx 
x(i,j,k) = x(i,j,k)*y(i,j,k) 
enddo; enddo; enddo 
!$OMP END PARALLEL DO 
! (x should = 6.0 at this point) 

方法2

x = 1.0; y = 2.0 
!$OMP PARALLEL DO 
do k=1,Nz; do j=1,Ny; do i=1,Nx 
x(i,j,k) = x(i,j,k)+y(i,j,k) 
x(i,j,k) = x(i,j,k)*y(i,j,k) 
enddo; enddo; enddo 
!$OMP END PARALLEL DO 
! (x should = 6.0 at this point) 

方法3

1)手順

の配列を含むオブジェクトを作成します

2)

x = 1.0; y = 2.0 
!$OMP PARALLEL DO 
do k=1,Nz; do j=1,Ny; do i=1,Nx 
do t=1,procedure_array%N 
call procedure_array%single_procedure(t)%P(x(i,j,k),y(i,j,k)) 
enddo 
enddo; enddo; enddo 
!$OMP END PARALLEL DO 
! (x should = 6.0 at this point) 

はのは、サブルーチンaddx=x+y)とそれぞれmultiplyx=x*y)にそのprocedure_array%N = 2

procedure_array%single_procedure(1) 
procedure_array%single_procedure(2) 

ポイントを仮定しよう、次のような手順の配列を呼び出します。

3)クリーンアップ(DEALLOCATE)

コメント

まず、それは方法2は、方法1よりも優れていることは明らかですので、私は方法3方法2との比較では、本当に興味があります。第2に、「試してみる」というのは有効な答えですが、方法3が具体的な例が実際に使用されているかどうか、または方法2が方法2に比べて劣っている概念的理由があるかどうかを知りたい(例えば、多くのプロシージャコールによるオーバーヘッド)。最後に、方法2と3を実質的に同等にするために(例えば、特定のスレッドを具体的に指定することによって)何らかの特別な注意が払われる場合、それらは何ですか?

ご協力いただきありがとうございます。コメントの光で

アップデート

、私は次の修正を加えました。

  • は、MPIに関連するすべてのものを削除
  • (、@Gillesをありがとう)、これは本当にOpenMPの質問(、@Vladimirをありがとうございました)(私自身の実現)以下
  • 追加の明確化
  • ある操作を修正しました

キャッシュメモリー(およびキャッシュフォルト)についてのご質問、ありがとうございました。非常に参考になりました。

明確化最後に

、コメントから、私はこの質問の焦点は、プロシージャ・コールについて、実際には厳密OpenMP並列に関連していないことに気づきました。つまり、私はopenmpステートメントを残しました。これは、もっと複雑なアプリケーションで起こっていることであり、可能な限り保存したいからです。 @ Chaositのコメントから、プロシージャコールにはオーバーヘッドが必要であり、メソッド3を遅らせるようです。これを回避する方法はありますか?

また、私が間違っている場合は私を修正してください。しかし、方法2の2つの操作は書面による順序で実行され、正しい最終xの値になります。

+1

スニペットの両方の計算が意味をなさないことを除いて(OK、ちょうど私たちが何らかの計算を行うことを示しています)、**メソッド1 **と**メソッド2 **は同等ではないことが判明しています。注文事項(この場合は多く)。したがって、メソッド2が**メソッド1 **から得られた結果であれば、メソッド2 **が間違っているので、「メソッド2がメソッド1よりも優れている」というあなたの主張は非常に疑わしいです( 'a = b = 0'を除いて)。私は知っている、これはあなたのポイントではありませんが、私は効率の前にすべて正しいです。 – Gilles

+1

*「MPI並列化ループ」*とはどういう意味ですか?そのようなことはありません。 –

答えて

4

あなたが探している相違点(方法2と方法3)は、並列化に依存しないことを理解しています。

私に説明してみましょう:

方法3は、おそらく方法2に存在しないプロシージャ・コールに別のオーバーヘッドを持っています、私は私が手続きポインタに慣れていないですので、しかし、私の推測では、ということである可能性が言っていますプロシージャ・ポインタを使用している場合、コンパイラによる最適化はプロシージャ・コールをインライン化しません。

プロシージャコールによるオーバーヘッドは、並列化とはまったく独立しています。あなたはまだシーケンシャルコードでそれを持っています。これは並列化待ち時間の一部ではありません。

今、私はあなたが好きではないオプションに戻るリスクを抱えています。試してみてください。私は、あなたが示したことはあなたの問題のイラストだけであり、あなたの実際のケースはより複雑であると信じているので、このリスクを冒しています。複雑なケースに入ると、方法1と2の結論はもはや有効ではないことに驚くかもしれません。あなたが手にしている問題に強く依存することがあります。あるケースの結論は、別のケースの結論は成立しません。現在のところ、コンパイラーほど知的であるため、すべてをキャッチしません。コンピュータサイエンスでは、このキャッシュメモリの概念は、あまり理解されていないこともありますが、詳細には触れません。ケース2の結合ループがキャッシュメモリに保持されていないときに、方法1の各単一ループ(データおよび/またはコード)がキャッシュメモリに保持されるケースを持つことができます。単純化した例は、方法1が内部ループ内でキャッシュ障害を経験し、方法1が内部ループ内でキャッシュ障害を経験する場合である。その場合、メソッド1はメソッド2が大きなループ境界に対して非常に優れていることがわかります。

これは、Try and seeが標準となるところであり、実際のケースではほとんどの場合それが起こります。

+1

3つ目の方法については正しいですが、プロシージャポインタがコンパイル時ではなく実行時に解決されるため、最初の2つに比べて処理速度が遅くなる可能性があります。したがって、コンパイラはコードのこの部分を最適化するために何もできません。そのまま使用する必要があります。最初の2つの方法の比較に関しては、これはコンパイラに大きく依存しますが、現代のコンパイラでは、どちらも同等に高速に実行できることが期待されます – Chaosit

関連する問題