2

足し算や掛け算などの 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 のリダクション実装に依存するのが最善であることに気付きました。

4

1 に答える 1

3

一般に、SSE と AVX はアトミック操作ではありません (ただし、マルチワード CAS は確かに便利です)。

tbb または ppl で結合可能なクラス テンプレートを使用して、より汎用的なリダクションとスレッド ローカルの初期化を行うことができます。これは、スレッド ID でインデックス付けされた同期ハッシュ テーブルと考えることができます。これは OpenMP で問題なく動作し、独自に余分なスレッドを起動することはありません。

tbb サイトと msdn で例を見つけることができます。

コメントについては、次のコードを検討してください。

x = x + 5

特に複数のスレッドが関係している場合は、次のように考える必要があります。

while( true ){
    oldValue = x
    desiredValue = oldValue + 5
    //this conditional is the atomic compare and swap
    if( x == oldValue )
       x = desiredValue
       break;
}

わかる?

于 2013-05-14T22:55:24.403 に答える