6

私はこれこれを認識していますが、最初のリンクは現在かなり古く、2番目のリンクは決定的な答えに達していないようです. コンセンサスは形成されましたか?

私の問題は簡単です:

同時に実行できる要素DOを持つループがあります。どの方法を使用しますか?

以下は、単純な立方格子上に粒子を生成するコードです。

  • npartは粒子の数です
  • npart_edgenpart_faceは、それぞれエッジと面に沿ったものです
  • spaceは格子間隔
  • RxRyRzは位置配列です
  • xyzは、格子上の位置を決定するための一時的な変数です

x、y、z は、CONCURRENT の場合は配列でなければならないが、OpenMP の場合は PRIVATE として定義できるため、そうではないという違いに注意してください。

だから私は使用しますかDO CONCURRENT(上記のリンクからわかるように、SIMDを使用します):

DO CONCURRENT (i = 1, npart)
    x(i) = MODULO(i-1, npart_edge)
    Rx(i) = space*x(i)
    y(i) = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y(i)
    z(i) = (i-1) / npart_face
    Rz(i) = space*z(i)
END DO

または、OpenMP を使用しますか?

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(x,y,z)
!$OMP DO
DO i = 1, npart
    x = MODULO(i-1, npart_edge)
    Rx(i) = space*x
    y = MODULO( ( (i-1) / npart_edge ), npart_edge)
    Ry(i) = space*y
    z = (i-1) / npart_face
    Rz(i) = space*z
END DO
!$OMP END DO
!$OMP END PARALLEL

私のテスト:

サイド 10 のボックスに 64 個のパーティクルを配置する:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  6.870000000000001E-003
Real time =  3.600000000000000E-003

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  6.699999999999979E-005
Real time =  0.000000000000000E+000

サイド 100 のボックスに 100000 個のパーティクルを配置する:

$ ifort -qopenmp -real-size 64 omp.f90
$ ./a.out 
CPU time =  8.213300000000000E-002
Real time =  1.280000000000000E-002

$ ifort -real-size 64 concurrent.f90 
$ ./a.out 
CPU time =  2.385000000000000E-003
Real time =  2.400000000000000E-003

コンストラクトを使用するDO CONCURRENTと、少なくとも 1 桁はパフォーマンスが向上するようです。これは i7-4790K で行われました。また、同時実行の利点は、サイズが大きくなるにつれて減少するようです。

4

1 に答える 1

6

DO CONCURRENT は、それ自体は並列化を行いません。コンパイラは、スレッドを使用して並列化するか、SIMD 命令を使用するか、GPU にオフロードすることさえ決定する場合があります。スレッドの場合、多くの場合、そうするように指示する必要があります。GPU オフロードには、特定のオプションを備えた特定のコンパイラが必要です。または (多くの場合!)、コンパイラは DO CONCURENT を通常の DO として扱い、通常の DO に SIMD を使用する場合は SIMD を使用します。

OpenMP は単なるスレッドではありません。必要に応じて、コンパイラは SIMD 命令を使用できます。ディレクティブもありますがomp simd、これは SIMD を使用するためのコンパイラへの提案に過ぎず、無視できます。

試して、測定して、見てください。唯一の決定的な答えはありません。特定のコンパイラでさえ、すべてのコンパイラで少なくなります。

とにかく OpenMP を使用しないDO CONCURRENT場合は、自動並列化がこの構造でより適切に機能するかどうかを確認してみてください。それが役立つ可能性は十分にあります。あなたのコードが既に OpenMP にある場合は、導入する意味がありませんDO CONCURRENT

私の実践では、OpenMP を使用して、コンパイラーができることをベクトル化 (SIMD) するようにしています。特に、とにかくプログラム全体で OpenMP を使用しているためです。DO CONCURRENT は、それが実際に役立つことを証明する必要があります。私はまだ確信が持てませんが、いくつかの GPU の例は有望に見えますが、実際のコードは多くの場合、はるかに複雑です。


具体的な例とパフォーマンス測定:

与えられたコードが少なすぎて、すべてのベンチマークに微妙なポイントがあります。ループの周りにいくつかの簡単なコードを書き、独自のテストを行いました。スレッドの作成を時限ブロックに含めないように注意しました。$omp parallelタイミングに含めるべきではありません。最初のテイクが長くなる場合があるため (確かに DO CONCURRENT を使用した場合)、複数の計算で最小のリアルタイムも取りました。CPU にはさまざまなスロットル モードがあり、スピンアップするのに時間がかかる場合があります。も追加しましSCHEDULE(STATIC)た。

npart=10000000
ifort -O3 concurrent.f90: 6.117300000000000E-002
ifort -O3 concurrent.f90 -parallel: 5.044600000000000E-002
ifort -O3 concurrent_omp.f90: 2.419600000000000E-002

npart=10000、デフォルト 8 スレッド (ハイパースレッディング)
ifort -O3 concurrent.f90: 5.430000000000000E-004
ifort -O3 concurrent.f90 -parallel: 8.899999999999999E-005
ifort -O3 concurrent_omp.f90: 1.890000000000000E-004

npart=10000, OMP_NUM_THREADS=4(ハイパースレッディングを無視)
ifort -O3 concurrent.f90: 5.410000000000000E-004
ifort -O3 concurrent.f90 -parallel: 9.200000000000000E-005
ifort -O3 concurrent_omp.f90: 1.070000000000000E-004

ここでは、小さなケースでは DO CONCURRENT の方がいくらか速いように見えますが、適切な数のコアを確実に使用すれば、それほど速くはありません。大きなケースでは明らかに遅くなります。この-parallelオプションは、自動並列化に明らかに必要です。

于 2016-07-24T07:59:20.400 に答える