AVX2 と FMA3 を搭載した i5-4250U を持っています。私が書いたLinux上のGCC 4.8.1でいくつかの密な行列乗算コードをテストしています。以下は、私がコンパイルする 3 つの異なる方法のリストです。
SSE2: gcc matrix.cpp -o matrix_gcc -O3 -msse2 -fopenmp
AVX: gcc matrix.cpp -o matrix_gcc -O3 -mavx -fopenmp
AVX2+FMA: gcc matrix.cpp -o matrix_gcc -O3 -march=native -fopenmp -ffast-math
SSE2版とAVX版は明らかに性能が違います。ただし、AVX2+FMA は AVX バージョンより優れているわけではありません。私はこれを理解していません。FMA がないと仮定すると、CPU のピーク フロップの 80% を超える値を取得できますが、FMA を使用するとさらに改善できるはずです。行列乗算は、FMA から直接恩恵を受けるはずです。私は基本的に、AVX で一度に 8 つのドット積を実行しています。チェックすると、次のmarch=native
ようになります。
cc -march=native -E -v - </dev/null 2>&1 | grep cc1 | grep fma
...-march=core-avx2 -mavx -mavx2 -mfma -mno-fma4 -msse4.2 -msse4.1 ...
したがって、有効になっていることがわかります(追加し-mfma
たことを確認するためですが、違いはありません)。 ffast-math
緩和された浮動小数点モデルを許可する必要がありますSSE/AVX で融合積和 (FMA) 命令を使用する方法
編集:
Mysticial のコメントに基づいて、_mm256_fmadd_ps を使用したところ、AVX2+FMA バージョンの方が高速になりました。 なぜコンパイラがこれをしないのかわかりません。 現在、1000x1000 を超える行列で約 80 GFLOPS (FMA を使用しない場合のピーク フロップの 110%) を取得しています。誰かが私のピーク フロップ計算を信用しない場合のために、ここで私が行ったことを示します。
peak flops (no FMA) = frequency * simd_width * ILP * cores
= 2.3GHZ * 8 * 2 * 2 = 73.2 GFLOPS
peak flops (with FMA) = 2 * peak flops (no FMA) = 146.2 GFLOPS
両方のコアを使用するときのターボ モードの CPU は 2.3 GHz です。Ivy Bridge は 1 つの AVX 乗算と 1 つの AVX 加算を同時に実行できるため、ILP は 2 になります (これを確実にするためにループを数回展開しました)。
ピーク フロップの約 55% しか得られません (FMA を使用)。理由はわかりませんが、少なくとも今は何かが見えています。
副作用の 1 つは、信頼できるとわかっている単純な行列乗算アルゴリズムと比較すると、小さなエラーが発生するようになったことです。これは、FMA の丸めモードが通常は 2 つではなく 1 つしかないためだと思います (皮肉なことに、IEEE の浮動小数点の規則に違反している可能性があります)。
編集:
誰かがやり直す必要が ある 1 サイクルあたり 4 FLOP という理論上の最大値を達成するにはどうすればよいですか? ただし、Haswell では、1 サイクルあたり 8 つの倍精度浮動小数点 FLOPS を実行します。
編集
実際、Mysticial は FMA3 をサポートするようにプロジェクトを更新しました (上記のリンクで彼の回答を参照してください)。MSVC2012 を使用して Windows8 で彼のコードを実行しました (Linux バージョンは FMA サポートでコンパイルされなかったため)。これが結果です。
Testing AVX Mul + Add:
Seconds = 22.7417
FP Ops = 768000000000
FLOPs = 3.37705e+010
sum = 17.8122
Testing FMA3 FMA:
Seconds = 22.1389
FP Ops = 1536000000000
FLOPs = 6.938e+010
sum = 333.309
これは、二重浮動小数点の FMA3 で 69.38 GFLOPS です。単一の浮動小数点の場合、2 倍にする必要があるため、138.76 SP GFLOPS になります。私の計算では、ピークは 146.2 SP GFLOPS です。 それはピークの 95% です! 言い換えれば、GEMM コードをかなり改善できるはずです (ただし、Eigen よりもかなり高速です)。