4

SIMD を使用して高速累乗結果を計算しています。タイミングを非simdコードと比較します。累乗は、二乗および乗算アルゴリズムを使用して実装されます。

コードの通常の (非 simd) バージョン:

b = 1;  
for (i=WPE-1; i>=0; --i){  
    ew = e[i];  
    for(j=0; j<BPW; ++j){  
        b = (b * b) % p;  
        if (ew & 0x80000000U)  b = (b * a) % p;  
        ew <<= 1;  
    }  
}  

SIMD バージョン:

   B.data[0] = B.data[1] = B.data[2] = B.data[3] = 1U;  
   P.data[0] = P.data[1] = P.data[2] = P.data[3] = p;  
   for (i=WPE-1; i>=0; --i) {  
      EW.data[0] = e1[i]; EW.data[1] = e2[i]; EW.data[2] = e3[i]; EW.data[3] = e4[i];  
      for (j=0; j<BPW;++j){  
         B.v *= B.v; B.v -= (B.v / P.v) * P.v;  
         EWV.v = _mm_srli_epi32(EW.v,31);  
         M.data[0] = (EWV.data[0]) ? a1 : 1U;  
         M.data[1] = (EWV.data[1]) ? a2 : 1U; 
         M.data[2] = (EWV.data[2]) ? a3 : 1U; 
         M.data[3] = (EWV.data[3]) ? a4 : 1U;  
         B.v *= M.v; B.v -= (B.v / P.v) * P.v;  
         EW.v = _mm_slli_epi32(EW.v,1);  
      }  
   } 

問題は、正しく計算されているにもかかわらず、simd バージョンが非 simd バージョンよりも時間がかかっていることです。

理由のデバッグを手伝ってください。SIMD コーディングに関する提案も大歓迎です。

よろしくお願いします、Anup。

4

2 に答える 2

4

for ループ内のすべての関数は、2 つだけでなく、SIMD 関数である必要があります。2つの関数の引数を設定するのにかかる時間は、元の例よりも最適ではありません(コンパイラによって最適化される可能性が最も高い)

于 2010-10-25T07:43:57.180 に答える
1

32 ビット int データの SIMD ループは通常、次のようになります。

for (i = 0; i < N; i += 4)
{
    // load input vector(s) with data at array index i..i+3
    __m128 va = _mm_load_si128(&A[i]);
    __m128 vb = _mm_load_si128(&B[i]);

    // process vectors using SIMD instructions (i.e. no scalar code)
    __m128 vc = _mm_add_epi32(va, vb);

    // store result vector(s) at array index i..i+3
    _mm_store_si128(&C[i], vc);
}

ループ内でスカラー コードと SIMD コードの間を移動する必要があることがわかった場合、おそらく SIMD 最適化からは何も得られません。

SIMD プログラミングのスキルの多くは、特定の SIMD アーキテクチャーが提供する限られた数のサポートされる命令とデータ型でアルゴリズムを機能させる方法を見つけることから生まれます。多くの場合、可能な限り最高のパフォーマンスを得るために、データセットのアプリオリな知識を活用する必要があります。たとえば、32 ビット整数値が実際に 16 ビット以内に収まる範囲を持っていることが確実にわかっている場合、乗算は実装がはるかに簡単なアルゴリズム。

于 2010-10-25T10:49:06.720 に答える