首页 文章

GCC中的FMA3:如何启用

提问于
浏览
17

我有一个i5-4250U,它有AVX2和FMA3 . 我正在测试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版本好 . 我基本上在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 应该允许放松的浮点模型How to use Fused Multiply-Add (FMA) instructions with SSE/AVX

Edit:

基于Mysticial的评论我继续使用_mm256_fmadd_ps,现在AVX2 FMA版本更快 . I'm not sure why the compiler won't do this for me. 我现在获得超过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处于turbo模式是2.3 GHz . 我为ILP得到2,因为Ivy Bridge可以同时进行一次AVX乘法和一次AVX加法(我已经多次展开循环以确保这一点) .

我只有大约55%的峰值失误(使用FMA) . 我不确定为什么,但至少我现在看到的东西 .

一个副作用是,当我比较一个我知道我信任的简单矩阵乘法算法时,我现在得到一个小错误 . 我认为这是因为FMA只有一种舍入模式而不是通常的两种舍入模式(具有讽刺意味的是它违反了IEEE浮点规则,即使它可能更好) .

Edit:

有人需要重做How do I achieve the theoretical maximum of 4 FLOPs per cycle?但是每个周期用Haswell做8个双浮点FLOPS .

Edit

实际上,Mysticial更新了他的项目以支持FMA3(参见上面链接中的答案) . 我在Windows8中使用MSVC2012运行他的代码(因为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

那's 69.38 GFLOPS for FMA3 for double floating point. For single floating point I need to double it so that' s 138.76 SP GFLOPS . 我计算我的峰值是146.2 SP GFLOPS . That's 95% of the peak! 换句话说,我应该能够相当多地改进我的GEMM代码(尽管它已经比Eigen快得多) .

2 回答

  • 3

    这里只回答问题的一小部分 . 如果你写 _mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0) ,gcc-4.9几乎像内联asm一样处理它并且不会对它进行太多优化 . 如果用 areg0*breg0+tmp0 (gcc和clang都支持的语法)替换它,则gcc开始优化,如果可用,可以使用FMA . 我improved that对于gcc-5, _mm256_add_ps 现在实现为内联函数,只使用 + ,因此具有内在函数的代码也可以进行优化 .

  • 7

    以下编译器选项足以将 _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
    

    我尝试了 /O2 /arch:AVX2 /fp:fast 与MSVC,但它仍然没有收缩(惊喜) . MSVC will contract scalar operations though .

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

相关问题