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