Parallel for と OMP SIMD: それぞれいつ使うべきでしょうか? 質問する

Parallel for と OMP SIMD: それぞれいつ使うべきでしょうか? 質問する

OpenMP 4.0「omp simd」という新しい構造が導入されました。この構造を従来の「parallel for」よりも使用することの利点は何でしょうか? それぞれが他のものよりも優れた選択となるのはどのような場合でしょうか?

編集:これは興味深いSIMD 指令に関連します。

ベストアンサー1

簡単な答え:

OpenMPは複数のコアで複数のスレッドを利用するためだけに使用されていました。この新しいsimd拡張機能により、明示的にSIMD命令Intel の AVX/SSE や ARM の NEON などの最新の CPU 上で動作します。

(SIMD 命令は設計上、単一のスレッドと単一のコアで実行されることに注意してください。ただし、SIMD の意味は GPGPU ではかなり拡張される可能性があります。ただし、OpenMP 4.0 では GPGPU を考慮する必要はないと思います。)

したがって、SIMD 命令を理解すれば、この新しい構造を使用できます。


現代のCPUには、大まかに言って3種類の並列処理があります。(1)命令レベルの並列処理(ILP)、(2)スレッドレベルの並列処理(TLP)、(3)SIMD命令(これはベクターレベルとも言えます)です。

ILP は、アウトオブオーダー CPU またはコンパイラによって自動的に実行されます。TLP は、OpenMPparallel forやその他のスレッド ライブラリを使用して利用できます。では、SIMD はどうでしょうか。組み込み関数は、SIMD を使用する方法の 1 つでした (コンパイラの自動ベクトル化も同様です)。OpenMP は、simdSIMD を使用する新しい方法です。

非常に簡単な例を見てみましょう。

for (int i = 0; i < N; ++i)
  A[i] = B[i] + C[i];

上記のコードは2つのN次元ベクトルの合計を計算します。簡単にわかるように、(ループキャリー)データ依存性配列上のA[]ループは恥ずかしいほど似ている

このループを並列化する方法には複数の方法があります。たとえば、OpenMP 4.0 までは、コンストラクトのみを使用して並列化できます。各スレッドは複数のコアで反復処理parallel forを実行します。N/#thread

しかし、このような単純な加算に複数のスレッドを使用するのはやりすぎだと思うかもしれません。そのためにベクトル化があり、これは主に SIMD 命令によって実装されます。

SIMD を使用すると次のようになります。

for (int i = 0; i < N/8; ++i)
  VECTOR_ADD(A + i, B + i, C + i);

このコードでは、(1) SIMD命令( VECTOR_ADD)が256ビットまたは8ウェイ(8 * 32ビット)であること、(2) がN8の倍数であることを前提としています。

8 ウェイ SIMD 命令は、ベクトル内の 8 つの項目を 1 つのマシン命令で実行できることを意味します。Intel の最新の AVX は、このような 8 ウェイ (32 ビット * 8 = 256 ビット) ベクトル命令を提供していることに注意してください。

SIMDでは、依然として単一のコアを使用します(繰り返しますが、これは従来のCPUのみで、GPUには適用されません)。しかし、ハードウェアの隠れた並列処理を使用することができます。現代のCPUは、SIMD命令にハードウェアリソースを割り当てており、各SIMDはレーン並列実行できます。

同時にスレッドレベルの並列処理も使用できます。上記の例は、 によってさらに並列化できますparallel for

(ただし、実際にどれだけのループを SIMD 化されたループに変換できるかは疑問です。OpenMP 4.0 仕様では、この点が少し不明確であるようです。そのため、実際のパフォーマンスと実用的な制限は、実際のコンパイラの実装に依存することになります。)


要約すると、simdコンストラクトを使用すると SIMD 命令を使用できるため、スレッド レベルの並列処理とともに、より多くの並列処理を活用できます。ただし、実際の実装が重要になると思います。

おすすめ記事