65

OpenMP 4.0では、「omp simd」と呼ばれる新しい構造が導入されています。古い "parallel for" よりもこの構造を使用する利点は何ですか? それぞれが他の選択肢よりも優れているのはいつですか?

編集: これは、SIMD ディレクティブに関連する興味深い論文です。

4

3 に答える 3

52

簡単な答え:

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

(SIMD 命令は、設計上、シングル スレッドおよびシングル コアで実行されることに注意してください。ただし、SIMD の意味は、GPGPU ではかなり拡張できます。ただし、OpenMP 4.0 では GPGPU を考慮する必要はないと思います。 )

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


最新の CPU では、大まかに次の 3 種類の並列処理があります。(1) 命令レベルの並列処理 (ILP)、(2) スレッドレベルの並列処理 (TLP)、および (3) SIMD 命令 (これはベクトル レベルと言えます)とか、ぐらい)。

ILP は、順不同の CPU またはコンパイラによって自動的に実行されます。parallel forOpenMPやその他のスレッド ライブラリを使用して TLP を活用できます。では、SIMD はどうでしょうか。組み込み関数は、それらを使用する方法でした (コンパイラーの自動ベクトル化と同様)。OpenMPsimdは、SIMD を使用する新しい方法です。

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

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

上記のコードは、2 つの N 次元ベクトルの合計を計算します。簡単にわかるように、 array には(ループで運ばれる) データの依存関係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)Nは 8 の倍数です。

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

SIMD では、まだシングル コアを使用します (繰り返しますが、これは GPU ではなく、従来の CPU のみを対象としています)。ただし、ハードウェアで隠れた並列処理を使用できます。最新の CPU はハードウェア リソースを SIMD 命令専用に割り当てており、各 SIMDレーンを並行して実行できます。

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

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


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

于 2013-02-05T21:54:21.460 に答える
50

リンク先の標準は比較的明確です(p 13、19 + 20行目)

いずれかのスレッドがsimdコンストラクトに遭遇すると、そのコンストラクトに関連付けられたループの反復は、スレッドで使用可能なSIMDレーンによって実行できます。

SIMDサブスレッドのものです。より具体的には、CPUで、simdディレクティブを使用して、同じスレッドに個別に属するループ反復のチャンクのベクトル化を具体的に要求することを想像できます。プラットフォームに依存しない方法で、単一のマルチコアプロセッサ内に存在する複数レベルの並列処理を公開しています。たとえば、このインテルのブログ投稿のディスカッション(アクセラレーターに関するものと一緒に)を参照してください。

したがって、基本的には、omp parallel作業を異なるスレッドに分散するために使用する必要があります。その後、スレッドは複数のコアに移行できます。そして、omp simd各コア内で(たとえば)ベクトルパイプラインを利用するために使用する必要があります。通常omp parallelは、作業の粗い並列分散を処理するために「外部」にomp simd行き、その内部のタイトなループを回って、細かい並列処理を利用します。

于 2013-02-03T18:05:24.877 に答える
2

コンパイラは、simd 句の存在を条件として、並列領域で simd の最適化を行う必要はありません。私がよく知っているコンパイラは、以前と同じ方法で、ネストされたループ、並列外部、ベクトル内部を引き続きサポートしています。
これまで、OpenMP ディレクティブは通常、外側の並列化されたループ (collapse 句を含む複数のループ) を含むループ切り替えの最適化を防ぐために使用されていました。これは、いくつかのコンパイラで変更されたようです。OpenMP 4 は、omp parallel do [for] simd が設定されている場合に、一種のストリップ マイニングによって、ベクトル化できない内側ループを持つ並列外側ループの最適化など、新しい可能性を開きます。ifort は、simd 句なしで行われると、外部ループのベクトル化として報告することがあります。次に、omp parallel do simd よりも少数のスレッド用に最適化される可能性があります。これには、simd ベクトル幅よりも多くのスレッドが必要なようです。simd 節がない場合、コンパイラーは 100 や 300 などのループ回数を最適化するように暗黙的に要求されるため、このような違いが推測される可能性があります。一方、simd 句は無条件の simd 最適化を要求します。gcc 4.9 omp parallel for simd は、24 コアのプラットフォームを使用していたときに非常に効果的であるように見えました。

于 2014-01-21T13:07:49.797 に答える