webdevqa.jp.net

GCCのFMA3:有効にする方法

私はAVX2とFMA3を搭載したi5-4250Uを持っています。私が書いたLinux上のGCC4.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でFusedMultiply-Add(FMA)命令を使用する方法

編集:

Mysticialのコメントに基づいて、先に進んで_mm256_fmadd_psを使用しましたが、AVX2 + FMAバージョンの方が高速です。 コンパイラがこれを行わない理由がわかりません。現在、約80 GFLOPS(ピークフロップの110%がない場合)を取得しています。 FMA)1000x1000以上のマトリックス用。誰かが私のピークフロップ計算を信用しない場合に備えて、ここで私がしたことです。

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.3GHzです。 Ivy Bridgeは1つのAVX乗算と1つのAVX加算を同時に実行できるため、ILPで2を取得します(これを確実にするために、ループを数回展開しました)。

ピークフロップの約55%しか取得していません(FMAを使用)。理由はわかりませんが、少なくとも今何かを見ています。

副作用の1つは、信頼できる単純な行列乗算アルゴリズムと比較すると、小さなエラーが発生することです。これは、FMAの丸めモードが通常の2つではなく1つしかないためだと思います(皮肉なことに、IEEE浮動小数点ルールの方が優れているとはいえ)。

編集:

誰かがやり直す必要があります サイクルごとに理論上の最大4 FLOPを達成するにはどうすればよいですか? しかし、Haswellを使用してサイクルごとに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.38GFLOPSです。単精度浮動小数点の場合は、2倍にして138.76 SP GFLOPS。ピークは146.2 SP GFLOPS。これはピークの95%です!言い換えると、GEMMコードをかなり改善できるはずです(ただし、すでにEigenよりもかなり高速です)。

22
Z boson

ここでは、質問のごく一部にのみ回答します。 _mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0)と書くと、gcc-4.9はインラインasmのように処理し、あまり最適化しません。 gccとclangの両方でサポートされている構文であるareg0*breg0+tmp0に置き換えると、gccは最適化を開始し、可能な場合はFMAを使用できます。 I 改善 gcc-5の場合、たとえば_mm256_add_psは、単に+を使用するインライン関数として実装されるようになったため、組み込み関数を含むコードも最適化できます。

9
Marc Glisse

_mm256_add_ps(_mm256_mul_ps(a, b), c)を単一のfma命令に縮小するには、次のコンパイラオプションで十分です(例:vfmadd213ps)。

GCC 5.3:   -O2 -mavx2 -mfma
Clang 3.7: -O1 -mavx2 -mfma -ffp-contract=fast
ICC 13:    -O1 -march=core-avx2

MSVCで/O2 /Arch:AVX2 /fp:fastを試しましたが、それでも収縮しません(驚きです)。 MSVCはスカラー演算を縮小します

GCCは、少なくともGCC5.1以降これを開始しました。


一部のコンパイラでは、この最適化には-O1十分ですが、全体的なパフォーマンスには常に少なくとも-O2を使用します、できれば-O3 -march=native -fltoと、プロファイルに基づく最適化。

また、コードに問題がない場合は、-ffast-math

4
Z boson