-1

次のループは何百回も実行されます。
elma and elmc are both unsigned long (64-bit) arrays, so is res1 and res2.

unsigned long simdstore[2];  
__m128i *p, simda, simdb, simdc;  
p = (__m128i *) simdstore;  

for (i = 0; i < _polylen; i++)  
{  

    u1 = (elma[i] >> l) & 15;  
    u2 = (elmc[i] >> l) & 15;  
    for (k = 0; k < 20; k++)  
    {     

    1.  //res1[i + k] ^= _mulpre1[u1][k];  
    2.  //res2[i + k] ^= _mulpre2[u2][k];               
    3.        _mm_prefetch ((const void *) &_mulpre2[u2][k], _MM_HINT_T0);
    4.        _mm_prefetch ((const void *) &_mulpre1[u1][k], _MM_HINT_T0);
    5.        simda = _mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]);
    6.        _mm_prefetch ((const void *) &res2[i + k], _MM_HINT_T0); 
    7.        _mm_prefetch ((const void *) &res1[i + k], _MM_HINT_T0); 
    8.        simdb = _mm_set_epi64x (res2[i + k], res1[i + k]);  
    9.        simdc = _mm_xor_si128 (simda, simdb);  
    10.        _mm_store_si128 (p, simdc);  
    11.        res1[i + k] = simdstore[0];  
    12.        res2[i + k] = simdstore[1];                      
    }     
}  

for ループ内では、スカラー バージョンのコード (コメント付き) は、simd コードよりも 2 倍速く実行されます。上記の行の cachegrind 出力 (命令読み取り) を以下に示します。

行1:668,460,000 2 2 2
行目2行目:668,460,000 1 1
行3:89,985,000 1 1
行4:89,985,000 1 1 行 5
:617,040,000 2 2 2
行6:44,992,500 0 0
行7:44,992,500 0 : 128,550,000 0 0 行 10: 。. . 11 行目: 205,680,000 0 0 12 行目: 205,680,000 0 0




上の図から、コメント化された (スカラー コード) は、simd コードよりもはるかに少ない数の命令を必要とするように見えます。

このコードを高速化するにはどうすればよいですか?

4

2 に答える 2

3

組み込み関数を取り出してください_mm_prefetch。これらはこのコンテキストでは何も達成しておらず、パフォーマンスを低下させている可能性さえあります。プリフェッチは、(a) 帯域幅に余裕があり、(b) データが実際に必要になる数百クロック サイクル前にプリフェッチ ヒントを発行できる場合にのみ役立ちます。あなたの場合、(a)も(b)も当てはまらないと思います。

于 2010-12-15T14:37:18.387 に答える
1

あなたのパフォーマンスの問題はこれです:

_mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]);

組み込み関数の mm_set(a,b,c,d) クラスは非常に低速です。単一のパラメーター セット組み込み関数 (別名ブロードキャスト) のみが高速です。

アセンブリ コードでの動作を調べました。

基本的に、スタック上に配列を作成し、通常のメモリ移動 (mov DWORD) を使用して、現在存在する多次元配列から 2 つの整数をスタック配列に移動します。次に、XMM メモリ移動 (mov XMWORD) を使用してスタック配列から。

スカラー バージョンは、メモリからレジスタに直接移動します。もっと早く!

XMM レジスターは一度に 128 ビットしか通信できないため、オーバーヘッドが発生することがわかります。そのため、プログラムは最初に 128 ビットをメモリの別の領域に並べてからロードします。

64 ビット値を通常のレジスターとの間で直接 XMM レジスターに移動する方法がある場合、私はまだそれを探しています。

SSE/XMM レジスターを使用して速度を向上させるには、おそらくデータがメモリー内で適切に配置されている必要があります。順不同のデータを XMM レジスタにロードする価値があるのは、順不同のロードごとに複数の XMM 操作を実行できる場合のみです。ここでは、単一の XOR 操作を実行しています。

于 2011-02-04T14:00:36.913 に答える