gpt4 book ai didi

c++ - GCC 中的 FMA3 : how to enable

转载 作者:IT老高 更新时间:2023-10-28 21:48:11 25 4
gpt4 key购买 nike

我有一个 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 版本好。我不明白这一点。假设没有 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 应该允许宽松的浮点模型 How to use Fused Multiply-Add (FMA) instructions with SSE/AVX

编辑:

根据 Mysticial 的评论,我继续使用 _mm256_fmadd_ps,现在 AVX2+FMA 版本更快。 我不确定为什么编译器不会为我执行此操作。我现在在超过 1000x1000 的矩阵中获得了大约 80 GFLOPS(没有 FMA 的峰值 flops 的 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 浮点规则,尽管它可能更好)。

编辑:

有人需要重做 How do I achieve the theoretical maximum of 4 FLOPs per cycle?但是使用 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 几乎像内联汇编一样处理它,并没有对其进行太多优化。如果您将其替换为 areg0*breg0+tmp0(一种 gcc 和 clang 都支持的语法),则 gcc 开始优化并可能使用 FMA(如果可用)。我 improved that例如,对于 gcc-5,_mm256_add_ps 现在实现为仅使用 + 的内联函数,因此也可以优化具有内在函数的代码。

关于c++ - GCC 中的 FMA3 : how to enable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21001388/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com