0

knc (Xeon Phi) が提供する SIMD 512 を利用して、Intel 組み込み関数を使用して以下の C コードのパフォーマンスを向上させようとしています。ただし、組み込みの組み込みコードは、自動ベクトル化されたコードよりも遅く実行されます

Cコード

int64_t match=0;
int *myArray __attribute__((align(64)));
myArray = (int*) malloc (sizeof(int)*SIZE); //SIZE is array size taken from user
radomize(myArray); //to fill some random data
int searchVal=24;
#pragma vector always
for(int i=0;i<SIZE;i++) {
   if (myArray[i]==searchVal) match++;
return match;

組み込みコード: 以下のコードでは、最初に配列をロードし、それを検索キーと比較しています。組み込み関数は、_mm512_mask_reduce_add_epi32() を使用して削減された 16 ビットのマスク値を返します。

register int64_t match=0;
int *myArray __attribute__((align(64)));
myArray = (int*) malloc (sizeof(int)*SIZE); //SIZE is array size taken from user
const int values[16]=\
                {   1,1,1,1,\
                    1,1,1,1,\
                    1,1,1,1,\
                    1,1,1,1,\
                };
__m512i const flag = _mm512_load_epi32((void*) values);
__mmask16 countMask;

__m512i searchVal = _mm512_set1_epi32(16);
__m512i kV = _mm512_setzero_epi32();


for (int i=0;i<SIZE;i+=16)
{
   // kV = _mm512_setzero_epi32();
    kV = _mm512_loadunpacklo_epi32(kV,(void* )(&myArray[i]));
    kV = _mm512_loadunpackhi_epi32(kV,(void* )(&myArray[i + 16]));

    countMask = _mm512_cmpeq_epi32_mask(kV, searchVal);
    match += _mm512_mask_reduce_add_epi32(countMask,flag);
}
return match;

このコードには余分なサイクルが導入されているため、自動ベクトル化されたコードに比べて実行速度が遅いと思います。比較の値を 128 ビット レジスタに直接返す SIMD128 とは異なり、SIMD512 はマスク レジスタに値を返すため、コードがさらに複雑になります。ここで何か不足していますか? XOR ops などのマスクを使用するのではなく、成功した検索のカウントを直接比較して保持する方法が必要です。

最後に、組み込み関数を使用してこのコードのパフォーマンスを向上させる方法を教えてください。組み込み関数を使用して、より多くのパフォーマンスを引き出すことができると信じています。これは少なくとも SIMD128 には当てはまり、組み込み関数を使用することで 25% のパフォーマンスを得ることができました。

4

1 に答える 1

1

次の最適化を提案します。

  • プリフェッチを使用します。コードはほとんど計算を実行せず、ほぼ確実に帯域幅に制約されます。Xeon Phi には L2 キャッシュ専用のハードウェア プリフェッチがあるため、最適なパフォーマンスを得るには、プリフェッチ命令を手動で挿入する必要があります。
  • _mm512_load_epi32@PaulR で示唆されているように、整列読み取りを使用します。配列が実際に 64 バイトにアラインされていることを保証するmemalign代わりに、関数を使用します。mallocまた、ミスアライメントされた命令が必要になった場合は_mm512_undefined_epi32()、最初のミスアライメントされたロードのソースとして使用します。これは、(現在のコードで) への依存を壊しkV、コンパイラが追加の最適化を実行できるようにするためです。
  • 配列を 2 ずつアンロールするか、少なくとも 2 つのスレッドを使用して、命令のレイテンシを隠します。
  • int変数をインデックスとして使用しないでください。unsigned intsize_tまたはssize_tより良いオプションです。
于 2014-02-15T06:01:16.963 に答える