GCC中的FMA3:如何启用

我有一个有AVX2和FMA3的i5-4250U。 我正在测试我编写的Linux上GCC 4.8.1中的一些密集矩阵乘法代码。 以下是我编译的三种不同方式的列表。

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,我获得了超过80%的CPU峰值触发器,但我认为我应该能够使用FMA做得更好。 矩阵乘法应直接受益于FMA。 我基本上是在AVX中一次完成八个点的产品。 当我检查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(110%的没有FMA的峰值触发器)。 如果有人不相信我的峰值触发器计算,这是我所做的。

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处于turbo模式,频率为2.3 GHz。 因为Ivy Bridge可以同时完成一个AVX乘法和一个AVX加法(我已经展开几次循环来确保这一点),所以我得到了2个ILP。

我只有55%的高峰失败(与FMA)。 我不知道为什么,但至少我现在看到了一些东西。

一个副作用是当我比较我知道我信任的简单矩阵乘法算法时,我现在得到一个小错误。 我认为这是由于FMA只有一种舍入模式,而不是通常是两种模式(即使它可能更好,但是它们讽刺地破坏了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.38 GFLOPS。 对于单浮点,我需要加倍,所以这是138.76 SP GFLOPS。 我计算我的峰值是146.2 SP GFLOPS。 这是高峰的95%! 换句话说,我应该能够提高我的GEMM代码(虽然它已经比Eigen快了很多)。


只回答这个问题的一小部分。 如果您编写_mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0) ,gcc-4.9几乎就像内联asm一样处理它,并且不会对其进行优化。 如果用areg0*breg0+tmp0和clang支持的语法areg0*breg0+tmp0替换,则gcc开始优化并可能使用FMA(如果可用)。 我改进了gcc-5,例如_mm256_add_ps现在作为一个简单使用+的内联函数实现,所以带有内在函数的代码也可以被优化。


以下编译器选项足以将_mm256_add_ps(_mm256_mul_ps(a, b), c)现在vfmadd213ps到单个fma指令(例如vfmadd213ps ):

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

我尝试了/O2 /arch:AVX2 /fp:fast使用MSVC的/O2 /arch:AVX2 /fp:fast ,但它仍然没有收缩(惊喜)。 尽管MSVC将收缩标量操作。

GCC至少从GCC 5.1开始这样做。

链接地址: http://www.djcxy.com/p/85655.html

上一篇: FMA3 in GCC: how to enable

下一篇: Fused multiply add and default rounding modes