0

Xeon Phi Intel コプロセッサで (512 ビット長のベクトル) を使用して KNC 命令を使用して 2 つの配列を追加するコードを作成しました。ただし、インライン アセンブリ パーツにセグメンテーション パーツがあります。

ここに私のコードがあります:

int main(int argc, char* argv[])
{
    int i;
    const int length = 65536;
    const int AVXLength = length / 16;
    float *A = (float*) aligned_malloc(length * sizeof(float), 64);
    float *B = (float*) aligned_malloc(length * sizeof(float), 64);
    float *C = (float*) aligned_malloc(length * sizeof(float), 64);
    for(i=0; i<length; i++){
            A[i] = 1;
            B[i] = 2;
    }

    float * pA = A;
    float * pB = B;
    float * pC = C;
    for(i=0; i<AVXLength; i++ ){
         __asm__("vmovaps %1,%%zmm0\n"
                    "vmovaps %2,%%zmm1\n"
                    "vaddps %%zmm0,%%zmm0,%%zmm1\n"
                    "vmovaps %%zmm0,%0;"
            : "=m" (pC) : "m" (pA), "m" (pB));

            pA += 512;
            pB += 512;
            pC += 512;
    }
    return 0;
}

gcc をコンパイラとして使用しています (Intel コンパイラを購入するお金がないため)。そして、これはこのコードをコンパイルするための私のコマンドラインです:

k1om-mpss-linux-gcc add.c -o add.out

問題はインライン アセンブリにありました。次のインラインアセンブリで修正されました。

__asm__("vmovaps %1,%%zmm1\n"
        "vmovaps %2,%%zmm2\n"
        "vaddps %%zmm1,%%zmm2,%%zmm3\n"
        "vmovaps %%zmm3,%0;"
        : "=m" (*pC) : "m" (*pA), "m" (*pB));
4

1 に答える 1

4

すでに説明したように、Knights Corner (KNC) には AVX512 はありません。ただし、似たようなものがあります。 KNC 対 AVX512 の問題は、ここではニシンであることが判明しました。問題は OP のインライン アセンブリにあります。

インライン アセンブリを使用する代わりに、組み込み関数を使用することをお勧めします。KNC 組み込み関数については、Intel Intrinsic Guide onlineで説明されています。

さらに、 CERN の Przemysław Karpiński は Agner Fog の Vector Class Library を拡張して KNC を使用していますここで git リポジトリを見つけることができます。ファイルvectorf512_mic.hを見ると、KNC 組み込み関数について多くを学ぶことができます。

これらの組み込み関数を使用するようにコードを変換しました (この場合、AVX512 組み込み関数と同じであることがわかります)。

int main(int argc, char* argv[])
{
    int i;
    const int length = 65536;
    const int AVXLength = length /16;
    float *A = (float*) aligned_malloc(length * sizeof(float), 64);
    float *B = (float*) aligned_malloc(length * sizeof(float), 64);
    float *C = (float*) aligned_malloc(length * sizeof(float), 64);
    for(i=0; i<length; i++){
        A[i] = 1;
        B[i] = 2;
    }
    for(i=0; i<AVXLength; i++ ){
        __m512 a16 = _mm512_load_ps(&A[16*i]);
        __m512 b16 = _mm512_load_ps(&B[16*i]);
        __m512 s16 = _mm512_add_ps(a16,b16);
        _mm512_store_ps(&C[16*i], s16);
    }
    return 0;
}

KNC 組み込み関数は、ICC でのみサポートされています。ただし、KNC には、特別なバージョンの gcc が付属するManycore Platform Software Stack (MCSS)k1om-mpss-linux-gccが付属しており、インライン アセンブリを使用して KNC の AVX512 のような機能を使用できます。


この場合、KNC と AVX512 のニーモニックは同じです。したがって、AVX512 組み込み関数を使用して、使用するアセンブリを検出できます。

void foo(int *A, int *B, int *C) {
    __m512i a16 = _mm512_load_epi32(A);
    __m512i b16 = _mm512_load_epi32(B);
    __m512i s16 = _mm512_add_epi32(a16,b16);
    _mm512_store_epi32(C, s16);
}

そしてgcc -O3 -mavx512 knc.c生産する

vmovaps (%rdi), %zmm0
vaddps  (%rsi), %zmm0, %zmm0
vmovaps %zmm0, (%rdx)

インラインアセンブリを使用したこの1つのソリューションから、

__asm__("vmovaps   (%1), %%zmm0\n"
        "vpaddps   (%2), %%zmm0, %%zmm0\n"
        "vmovaps   %%zmm0, (%0)"
        :
        : "r" (pC), "r" (pA), "r" (pB)
        :
);

前のコードでは、GCC は配列ごとに加算命令を生成します。これは、追加を 1 つだけ生成するインデックス レジスタを使用した、より優れたソリューションです。

for(i=0; i<length; i+=16){
    __asm__ __volatile__ (
            "vmovaps   (%1,%3,4), %%zmm0\n"
            "vpaddps   (%2,%3,4), %%zmm0, %%zmm0\n"
            "vmovaps   %%zmm0, (%0,%3,4)"
            :
            : "r" (C), "r" (A), "r" (B), "r" (i)
            : "memory"
     );
 }

MPSS (3.6) の最新バージョンには、AVX512 組み込み関数をサポートする GCC 5.1.1 が含まれています。したがって、AVX512 組み込み関数が KNC 組み込み関数と同じ場合はいつでも使用でき、それらが一致しない場合にのみインライン アセンブリを使用できると思います。Intel Intrinsic ガイドを見ると、ほとんどの場合同じであることがわかります。

于 2015-12-11T10:27:46.907 に答える