4

私は最近、Linux 用の Intel C++ コンパイラ、Composer XE 2013 をダウンロードしてインストールしました。これは、非商用の開発に自由に使用できます。 http://software.intel.com/en-us/non-commercial-software-development

私はアイビーブリッジシステム(AVXを搭載)で実行しています。同じことを行う関数の 2 つのバージョンがあります。1 つは SSE/AVX を使用しません。他のバージョンは AVX を使用します。GCC では、AVX コードはスカラー コードよりも約 4 倍高速です。ただし、Intel C++ コンパイラを使用すると、パフォーマンスが大幅に低下します。GCCで私はこのようにコンパイルします

gcc m6.cpp -o m6_gcc -O3 -mavx -fopenmp -Wall -pedantic

Intelでは、このようにコンパイルします

icc m6.cpp -o m6_gcc -O3 -mavx -fopenmp -Wall -pedantic

omp_get_wtime()この時点では、OpenMP のみをタイミング (と) に使用しています。奇妙なことに、avx オプションを変更してmsse2、コードが GCC ではコンパイルに失敗するが、ICC では問題なくコンパイルされるということです。実際、すべてをまとめてドロップしmavxてもコンパイルできます。どのオプションを試してもコンパイルはできますが、AVX コードを最適に使用していないようです。ICC で SSE/AVX を有効化/無効化する際に何か間違ったことをしているのだろうか?

これが私が使用しているAVXの機能です。

inline void prod_block4_unroll2_AVX(double *x, double *M, double *y, double *result) {
    __m256d sum4_1 = _mm256_set1_pd(0.0f);
    __m256d sum4_2 = _mm256_set1_pd(0.0f);

    __m256d yrow[6];
    for(int i=0; i<6; i++) {
        yrow[i] = _mm256_load_pd(&y[4*i]);
    }
    for(int i=0; i<6; i++) {
        __m256d x4 = _mm256_load_pd(&x[4*i]);
        for(int j=0; j<6; j+=2) {
            __m256d brod1 = _mm256_set1_pd(M[i*6 + j]);
            sum4_1 = _mm256_add_pd(sum4_1, _mm256_mul_pd(_mm256_mul_pd(x4, brod1), yrow[j]));
            __m256d brod2 = _mm256_set1_pd(M[i*6 + j+1]);
            sum4_2 = _mm256_add_pd(sum4_2, _mm256_mul_pd(_mm256_mul_pd(x4, brod2), yrow[j+1]));
        }
    }
    sum4_1 = _mm256_add_pd(sum4_1, sum4_2);
    _mm256_store_pd(result, sum4_1);
}

これは秒単位のタイミング情報です。L1、L2、および L3 キャッシュ範囲に対応する 3 つの範囲を実行します。L1 リージョンでは 4x しか得られません。ICC のスカラー コードははるかに高速ですが、AVX コードは低速です。

GCC:
nvec 2000, repeat 100000
time scalar 5.847293
time SIMD 1.463820
time scalar/SIMD 3.994543

nvec 32000, repeat 10000
time scalar 9.529597
time SIMD 2.616296
time scalar/SIMD 3.642400
difference 0.000000

nvec 5000000, repeat 100
time scalar 15.105612
time SIMD 4.530891
time scalar/SIMD 3.333917
difference -0.000000

ICC:
nvec 2000, repeat 100000
time scalar 3.715568
time SIMD 2.025883
time scalar/SIMD 1.834049

nvec 32000, repeat 10000
time scalar 6.128615
time SIMD 3.509130
time scalar/SIMD 1.746477

nvec 5000000, repeat 100
time scalar 9.844096
time SIMD 5.782332
time scalar/SIMD 1.702444
4

1 に答える 1

1

2 つのポイント:

(1) コードで intel 組み込み関数を使用しているようです -- g++ と icpc は必ずしも同じ組み込み関数を実装しているわけではありません (ただし、それらのほとんどは重複しています)。インポートする必要があるヘッダー ファイルを確認します (g++ では、非芸術的なものを定義するためのヒントが必要になる場合があります)。g++ は失敗したときにエラー メッセージを表示しますか?

(2) コンパイラ フラグは、(icpc --help から) 命令が生成されることを意味するものではありません。 -msse3 May generate Intel(R) SSE3, SSE2, and SSE instructions

これらのフラグは通常、コンパイラへの単なるヒントです。-xHost と -fast を参照してください。

どのオプションを試してもコンパイルはできますが、AVX コードを最適に使用していないようです。

これはどうやって確認しましたか?他のボトルネック (メモリ帯域幅など) がある場合、4 倍の高速化が見られない場合があります。

編集(質問の編集に基づく):

icc scalar は gcc scalar よりも高速のようです。icc がスカラー コードをベクトル化している可能性があります。この場合、ベクトル化を手動でコーディングする場合、icc による 4 倍の高速化は期待できません。

5.782332 秒の icc と 3.509130 秒の gcc の違い (nvec 5000000 の場合)。これは予想外です。私が持っている情報に基づいて、2 つのコンパイラーの実行時間に違いがある理由を知ることはできません。両方のコンパイラから出力されたコード ( http://www.delorie.com/djgpp/v2faq/faq8_20.html ) を見ることをお勧めします。また、測定値が再現可能であることを確認してください (たとえば、マルチソケット マシンのメモリ レイアウト、ホット/コールド キャッシュ、バックグラウンド プロセスなど)。

于 2013-06-10T20:04:27.473 に答える