OpenMP 4. は、「omp simd」と呼ばれる新しい構成を導入します。この「コンストラクト」を古い「並列for」よりも使用する利点は何ですか?それぞれが他よりも良い選択になるのはいつですか?
編集:ここに興味深い paper SIMDディレクティブに関連しています。
リンク先の標準は比較的明確です(p 13、19行目+ 20行目)
いずれかのスレッドがsimdコンストラクトに遭遇すると、そのコンストラクトに関連付けられているループの反復は、スレッドで使用可能なSIMDレーンによって実行できます。
SIMD
はサブスレッドです。具体的には、CPUでsimd
ディレクティブを使用して、個別に属するループ反復のチャンクのベクトル化を具体的に要求することを想像できます。同じthreadに。プラットフォームに依存しない方法で、単一のマルチコアプロセッサ内に存在する複数レベルの並列処理を公開しています。例えば、この intel blog post の議論(アクセラレータのスタッフと一緒に)を参照してください。
したがって、基本的には、omp parallel
作業を異なるスレッドに分散し、複数のコアに移行できます。そして、あなたはomp simd
各コア内でベクトルパイプライン(たとえば)を使用します。通常は omp parallel
は「外側」に進み、より粗い並列作業の分散とomp simd
は、細粒度の並列処理を活用するために、その内部のタイトなループを迂回します。
簡単な答え:
OpenMPは、複数のコアの複数のスレッドを悪用するためにのみ使用されていました。この新しいsimd
エクステンションにより、IntelのAVX/SSEやARMのNEONなどの最新のCPUでSIMD命令を明示的に使用できます。
(設計上、SIMD命令はシングルスレッドとシングルコアで実行されることに注意してください。ただし、SIMDの意味はGPGPUで大幅に拡張できますが、OpenMP 4.0でGPGPUを検討する必要はないと思います。 )
したがって、SIMD命令を知ったら、この新しい構成を使用できます。
最近のCPUには、おおよそ次の3種類の並列処理があります:(1)命令レベルの並列処理(ILP)、(2)スレッドレベルの並列処理(TLP)、および(3)SIMD命令(これはベクトルレベルと言えます)とか、ぐらい)。
ILPは、異常なCPUまたはコンパイラーによって自動的に実行されます。 OpenMPのparallel for
およびその他のスレッドライブラリを使用してTLPを活用できます。それでは、SIMDはどうですか?組み込み関数はそれらを使用する方法でした(コンパイラの自動ベクトル化と同様)。 OpenMPのsimd
は、SIMDを使用する新しい方法です。
非常に簡単な例を挙げます。
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)N
は8の倍数です。
8ウェイSIMD命令とは、1つのマシン命令でベクター内の8つのアイテムを実行できることを意味します。 Intelの最新のAVXは、このような8方向(32ビット* 8 = 256ビット)のベクトル命令を提供することに注意してください。
SIMDでは、引き続きシングルコアを使用します(これは、GPUではなく、従来のCPU専用です)。ただし、ハードウェアで非表示の並列処理を使用できます。最新のCPUはSIMD命令専用のハードウェアリソースを備えており、各SIMDlaneを並列に実行できます。
スレッドレベルの並列処理を同時に使用できます。上記の例は、parallel for
によってさらに並列化できます。
(ただし、実際にSIMD化されたループに変換できるループの数は疑問です。OpenMP4.0の仕様では、これについて少し不明瞭なようです。したがって、実際のパフォーマンスと実際の制限は実際のコンパイラの実装に依存します。)
要約すると、simd
コンストラクトを使用すると、SIMD命令を使用できるようになり、スレッドレベルの並列処理とともに、より多くの並列処理を利用できます。ただし、実際の実装は重要だと思います。
コンパイラーは、simd句の存在を条件に、並列領域でsimdの最適化を行う必要はありません。私が使い慣れているコンパイラは、以前と同じように、ネストされたループ、並列外部、ベクトル内部を引き続きサポートします。
これまで、OpenMPディレクティブは通常、外側の並列化ループ(折りたたみ句を含む複数のループ)を含むループ切り替えの最適化を防ぐために使用されていました。これは、いくつかのコンパイラで変更されたようです。 OpenMP 4は、omp parallel do [for] simdが設定されている場合に、ストリップマイニングのような方法で、ベクトル化できない内部ループを使用した並列外部ループの最適化など、新しい可能性を開きます。 ifortは、simd句なしで実行すると、外部ループのベクトル化として報告することがあります。その後、omp parallel do simdよりも少ないスレッド数に最適化される場合があります。これには、simdベクトル幅よりも多くのスレッドが必要になるようです。 simd句が無条件のsimd最適化を要求する一方で、コンパイラーは暗黙的に100または300などのループカウントの最適化を要求されるため、このような区別が推測される場合があります。 24コアプラットフォームを使用している場合、simdのgcc 4.9 omp parallelは非常に効果的でした。