足し算や掛け算などの SSE/AVX 操作をアトミック操作にできるかどうか疑問に思っています。私がこれを尋ねる理由は、OpenMP では、アトミック コンストラクトが限られた一連の演算子でのみ機能するためです。たとえば、SSE/AVX の追加では機能しません。
SSE レジスターに対応するデータ型float4
があり、float4 に対して SSE 加算を行うための加算演算子が定義されていると仮定します。OpenMP では、次のコードを使用して配列を削減できます。
float4 sum4 = 0.0f; //sets all four values to zero
#pragma omp parallel
{
float4 sum_private = 0.0f;
#pragma omp for nowait
for(int i=0; i<N; i+=4) {
float4 val = float4().load(&array[i]) //load four floats into a SSE register
sum_private4 += val; //sum_private4 = _mm_addps(val,sum_private4)
}
#pragma omp critical
sum4 += sum_private;
}
float sum = horizontal_sum(sum4); //sum4[0] + sum4[1] + sum4[2] + sum4[3]
しかし、アトミックは一般的にクリティカルよりも高速であり、私の本能は、SSE/AVX 操作はアトミックであるべきだと教えてくれます (たとえ OpenMP がサポートしていなくても)。これは OpenMP の制限ですか? たとえば、Intel Threading Building Blocks や pthreads などを使用して、これをアトミック操作として実行できますか?
編集: Jim Cownie のコメントに基づいて、最適なソリューションである新しい関数を作成しました。正しい結果が得られることを確認しました。
float sum = 0.0f;
#pragma omp parallel reduction(+:sum)
{
Vec4f sum4 = 0.0f;
#pragma omp for nowait
for(int i=0; i<N; i+=4) {
Vec4f val = Vec4f().load(&A[i]); //load four floats into a SSE register
sum4 += val; //sum4 = _mm_addps(val,sum4)
}
sum += horizontal_add(sum4);
}
編集: コメント Jim Cownie と Mystical によるこのスレッド OpenMP atomic _mm_add_pdのコメントに基づいて、OpenMP のリダクション実装は必ずしもアトミック オペレーターを使用するわけではなく、OpenMP のリダクション実装に依存するのが最善であることに気付きました。