问题标签 [fma]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
sse - 对于 Intel Haswell 上的 XMM/YMM FP 操作,可以使用 FMA 代替 ADD 吗?
这个问题适用于 Haswell 上带有 XMM/YMM 寄存器的打包单精度浮点运算。
因此,根据 Agner Fog 整理的令人敬畏的、令人敬畏的 表,我知道 MUL 可以在端口 p0 和 p1 上完成(recp thruput 为 0.5),而仅 ADD 仅在端口 p1 上完成(recp thruput 为 1 )。我可以排除这个限制,但我也知道 FMA 可以在端口 p0 或 p1 上完成(recp thruput 为 0.5)。因此,当 FMA 可以使用 p0 或 p1 并且它同时执行 ADD 和 MUL 时,为什么普通的 ADD 将仅限于 p1,这让我感到困惑。我误解了这张桌子吗?或者有人可以解释为什么会这样吗?
也就是说,如果我的阅读是正确的,英特尔为什么不直接使用 FMA 运算作为普通 MUL 和普通 ADD 的基础,从而增加 ADD 和 MUL 的吞吐量。或者,什么会阻止我使用两个同时的、独立的 FMA 操作来模拟两个同时的、独立的 ADD 操作?执行 ADD-by-FMA 的相关处罚是什么?显然,使用的寄存器数量更多(2 reg 用于 ADD,3 reg 用于 ADD-by-FMA),但除此之外呢?
x86 - 为什么 AVX512-IFMA 只支持 52 位整数?
从值我们可以推断它使用与双精度浮点硬件相同的组件。但是 double 有 53 位有效位,那么为什么 AVX512-IFMA 限制为 52 位呢?当然尾数只有 52 位,并且隐藏了一位,但它仍然对值有贡献,需要输入加法器/乘法器/除法器...
assembly - FMA(融合乘加)指令是否总是产生与 mul then add 指令相同的结果?
我有这个程序集(AT&T 语法):
我想将其替换为:
这种转换是否总是在所有涉及的寄存器和标志中留下相同的状态?或者结果浮动会以某种方式略有不同?(如果它们不同,为什么会这样?)
(关于 FMA 说明:http ://en.wikipedia.org/wiki/FMA_instruction_set )
c++ - FMA 性能与简单计算的比较
我正在尝试比较 FMA 性能(fma()
in math.h
)与浮点计算中的幼稚乘法和加法。测试很简单。我将对大迭代次数进行相同的计算。为了进行精确的检查,我必须完成两件事。
- 计算时间不应包括其他计算。
- 朴素的乘法和加法不应该针对 FMA 进行优化
- 迭代不应该被优化。即迭代应该完全按照我的意图进行。
为了实现上述目标,我做了以下工作:
- 函数是内联的,只包括所需的计算。
- 使用 g++
-O0
选项不优化乘法。(但是当我查看转储文件时,它似乎为两者生成几乎相同的代码) - 用过
volatile
。
但结果显示几乎没有差异,甚至fma()
比幼稚的乘法和加法更慢。这是我想要的结果(即它们在速度方面并没有真正不同)还是我做错了什么?
规格
- Ubuntu 14.04.2
- G++ 4.8.2
- Intel(R) Core(TM) i7-4770(3.4GHz,8MB 三级缓存)
我的代码
c++ - 使用 FMA(融合乘法)指令进行复数乘法
我想利用可用的融合乘法加/减 CPU 指令来帮助在一个适当大小的数组上进行复杂的乘法运算。本质上,基本数学如下所示:
正如您可能看到的那样,数据是结构化的,我们有单独的实数和虚数数组。现在,假设我有以下函数可用作分别执行b+c 和b-c 的单个指令的内在函数:
天真地,我可以看到我可以用一个 fmadd 和一个 fmsub 替换 2 个乘法、一个加法和一个减法,如下所示:
这导致了非常适度的性能改进,以及我认为的准确性,但我认为我真的错过了可以通过代数修改数学的东西,这样我就可以替换更多的 mult/add 或 mult/sub 组合。在每一行中,都有一个额外的加法和一个额外的乘法,我觉得我可以转换为单个 fma,但令人沮丧的是,如果不更改操作顺序并得到错误的结果,我无法弄清楚如何做到这一点。任何有想法的数学专家?
就这个问题而言,目标平台可能并不那么重要,因为我知道这些指令存在于各种平台上。
assembly - 优化快速乘法但慢加法:FMA 和 doubledouble
当我第一次得到一个 Haswell 处理器时,我尝试实现 FMA 来确定 Mandelbrot 集。主要算法是这样的:
这确定n
像素是否在 Mandelbrot 集中。因此,对于双浮点,它运行超过 4 个像素(floatn = __m256d
, intn = __m256i
)。这需要 4 个 SIMD 浮点乘法和 4 个 SIMD 浮点加法。
然后我修改了它以像这样使用 FMA
其中 mul_add 调用_mm256_fmad_pd
和 mul_sub 调用_mm256_fmsub_pd
。此方法使用 4 个 FMA SIMD 操作和两个 SIMD 乘法,这比没有 FMA 的算术操作少了两次。此外,FMA 和乘法可以使用两个端口,而加法只能使用一个。
为了使我的测试不那么有偏见,我放大了一个完全在 Mandelbrot 集中的区域,因此所有值都是maxiter
. 在这种情况下,使用 FMA 的方法大约快 27%。这当然是一个进步,但是从 SSE 到 AVX 使我的表现翻了一番,所以我希望 FMA 可能会再增加两倍。
但后来我找到了关于 FMA 的答案,上面写着
fused-multiply-add 指令的重要方面是中间结果的(实际上)无限精度。这有助于提高性能,但不是因为两个操作被编码在一条指令中 - 它有助于提高性能,因为中间结果的几乎无限精度有时很重要,并且在这种级别的普通乘法和加法中恢复非常昂贵精度确实是程序员所追求的。
后面给出了一个 double*double 到double-double乘法的例子
由此,我得出结论,我实施 FMA 的方式不是最优的,因此我决定实施 SIMD 双双。我根据论文Extended-Precision Floating-Point Numbers for GPU Computation实现了 double-double 。该纸是用于双浮动的,所以我将其修改为双双。此外,我没有在 SIMD 寄存器中打包一个 double-double 值,而是将 4 个 double-double 值打包到一个 AVX 高寄存器和一个 AVX 低寄存器中。
对于 Mandelbrot 集,我真正需要的是双倍乘法和加法。在那篇论文中,这些是df64_add
和df64_mult
函数。下图显示了我df64_mult
的软件 FMA(左)和硬件 FMA(右)功能的程序集。这清楚地表明,硬件 FMA 是对双倍乘法的一大改进。
那么硬件FMA在双双Mandelbrot集计算中表现如何呢?答案是这仅比使用软件 FMA 快 15%。这比我希望的要少得多。双双 Mandelbrot 计算需要 4 次双双加法和四次双双乘法(x*x
、y*y
、x*y
和2*(x*y)
)。但是,2*(x*y)
对于 double-double,乘法是微不足道的,因此可以在成本中忽略这种乘法。因此,我认为使用硬件 FMA 的改进如此之小的原因是计算以缓慢的双双加法为主(见下面的汇编)。
过去,乘法比加法慢(程序员使用了几种技巧来避免乘法),但在 Haswell 中,情况似乎正好相反。不仅因为 FMA,还因为乘法可以使用两个端口,而加法只能使用一个。
所以我的问题(最后)是:
- 当加法比乘法慢时如何优化?
- 有没有一种代数方法可以改变我的算法以使用更多的乘法和更少的加法?我知道有一些方法可以做相反的事情,例如
(x+y)*(x+y) - (x*x+y*y) = 2*x*y
使用两个加法来减少一个乘法。 - 有没有办法简单地使用 df64_add 函数(例如使用 FMA)?
如果有人想知道 double-double 方法比 double 慢十倍左右。我认为这还不错,就好像有一个硬件四精度类型一样,它的速度可能至少是双精度类型的两倍,所以我的软件方法比我对硬件的预期慢五倍(如果它存在的话)。
df64_add
部件
c++-amp - 我应该在 C++AMP 中为 GPU 内核显式使用 FMA 吗?
例如,我有一个像a = b * c + d * e + f * g + h * i + j
. 我应该写a = fma(a, c, fma(d, e, fma(f, g, fma(h, i, j))))
吗?
编译器会自动优化表达式吗?还是 fma 形式实际上比普通形式更好?
我发现很难知道内核在 C++AMP 中编译成什么......我应该切换到 OpenCL 吗?
simd - Haswell FMA 指令生成非规范化
我正在使用 Intel Haswell CPU 的 FMA 指令来优化一些计算。
但是,我发现即使我将 MXCSR 寄存器设置为 DNZ 和 FTZ 模式,这些指令也会产生异常。
如何强制这些 FMA 指令生成 0 而不是非正规指令?
我正在处理单精度浮点数据。
c++ - MSVC中自动生成FMA指令
MSVC 多年来一直支持 AVX/AVX2 指令,根据这篇 msdn 博客文章,它可以自动生成fused-multiply-add (FMA)指令。
然而,以下函数都不能编译为 FMA 指令:
更糟糕的是,std::fma 不是作为单个 FMA 指令实现的,它的执行非常糟糕,比普通指令慢得多x * y + z
(如果实现不依赖于 FMA 指令,那么 std::fma 的性能会很差)。
/arch:AVX2 /O2 /Qvec
我用标志编译。也试过了/fp:fast
,没有成功。
那么问题来了,MSVC如何强制自动发出FMA指令呢?
更新
有一个#pragma fp_contract (on|off)
,它(看起来)什么都不做。
performance - 英特尔 Broadwell 处理器出现明显的 FMA 性能异常
代码1:
/li>代码2:
/li>Code3(与 Code2 相同,但具有长 VEX 前缀):
/li>Code4(与 Code1 相同,但带有 xmm 寄存器):
/li>Code5(与 Code1 相同,但具有非归零 vpsubd`s):
/li>Code6b:(已修订,仅用于 vpaddds 的内存操作数)
/li>Code7:(与 Code1 相同,但 vpaddds 使用 ymm15)
/li>Code8:(与 Code7 相同,但使用 xmm 而不是 ymm)
/li>
在禁用 Turbo 和 C1E 的情况下测量的 TSC 时钟:
有人可以解释一下在 Broadwell 上 Code1 会发生什么吗?
我的猜测是 Broadwell 在 Code1 的情况下以某种方式用 vpaddds 污染了 Port1,但是 Haswell 只有在 Port0 和 Port1 已满时才能使用 Port5;你有什么想法用 FMA 指令完成 Broadwell 上的 ~5000000 clk 吗?
我试图重新排序。double 和 qword 的类似行为;
我使用的是 Windows 8.1 和 Win 10;
更新:
将 Code3 作为 Marat Dukhan 的想法添加了长 VEX;
使用 Skylake 体验扩展了结果表;
在这里上传了一个 VS2015 Community + MASM 示例代码
更新2:
我尝试使用 xmm 寄存器而不是 ymm(代码 4)。在 Broadwell 上的结果相同。
更新3:
我将 Code5 添加为 Peter Cordes 的想法(将 vpaddd 替换为其他指令(vpxor、vpor、vpand、vpandn、vpsubd))。如果新指令不是归零习惯用法(vpxor, vpsubd with same register),则在 BDW 上的结果相同。使用 Code4 和 Code5 更新的示例项目。
更新4:
我将 Code6 添加为 Stephen Canon 的想法(内存操作数)。结果是 ~8200000 时钟。使用 Code6 更新的示例项目;
我用 AIDA64 的系统稳定性测试检查了 CPU 频率和可能的节流。频率稳定,无节流迹象;
Intel IACA 2.1 Haswell 吞吐量分析:
/li>我按照 jcomeau_ictx 的想法,修改了 Agner Fog 的 testp.zip(2015-12-22 发布)BDW 306D4 上的端口使用情况:
港口分布与 Haswell 上的一样近乎完美。然后我检查了资源停止计数器(事件 0xa2)
在我看来,来自 RS 摊位的 Code1 和 Code2 差异。来自英特尔 SDM 的评论:“由于没有可用的符合条件的 RS 条目,周期停止。”
我怎样才能避免使用 FMA 的这种失速?
更新5:
Code6 发生了变化,正如 Peter Cordes 引起我的注意,只有 vpaddds 使用内存操作数。对 HSW 和 SKL 没有影响,BDW 变得更糟。
正如 Marat Dukhan 测量的那样,不仅 vpadd/vpsub/vpand/vpandn/vpxor 受到影响,还有其他 Port5 有界指令,如 vmovaps、vblendps、vpermps、vshufps、vbroadcastss;
正如 IwillnotexistIdonotexist 建议的那样,我尝试了其他操作数。一个成功的修改是 Code7,其中所有 vpaddd 都使用 ymm15。这个版本可以在 BDW 上产生约 5000000 个时钟,但只是一段时间。在约 600 万个 FMA 对之后,它达到通常的约 7730000 个时钟:
/li>我尝试了 Code7 的 xmm 版本作为 Code8。效果类似,但运行时间越快,持续时间越长。我没有发现 1.6GHz i5-5250U 和 3.7GHz i7-5775C 之间有显着差异。
16 和 17 是在禁用超线程的情况下制作的。启用 HTT 后效果会更小。