问题标签 [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.
c++ - 对双精度使用融合乘法累加有多大优势?
我试图通过查看生成的汇编代码来了解使用带有双参数的std::fma是否有利,我正在使用标志“-O3”,并且我正在比较这两个例程的程序集:
使用Compiler Explorer工具,这是为两个例程生成的程序集:
并且使用 icc 或 gcc 可用的最新版本不会更改程序集。关于这两个例程的性能让我感到困惑的是,虽然对于 test_1 只有一个内存操作(movsd),但对于 test_2 有三个,并且考虑到内存操作的延迟在一到两个数量级之间与浮点运算的延迟相比,test_1 的性能应该更高。因此,建议在哪些情况下使用 std::fma?我的假设有什么错误?
c++ - 如何在 gcc 中禁用 fma3 指令
我需要为 64 位系统禁用 FMA3 指令(出于向后兼容性问题)。_set_FMA3_enable(0)
我在我的windows环境中使用过。我需要使用什么选项(或宏)来禁用 gcc 中的 FMA3?
例如。
在 Visual C++ 上,它0.48674319998526994 4602440005894221058
使用_set_FMA3_enable(0)
. 0.48674319998526999 4602440005894221059
没有它(或使用 `_set_FMA3_enable(1))。
我在 gcc 环境中运行这段代码,g++ -g0 -march=x86-64 -O2 -mtune=generic -msse3 -mno-fma -DNDEBUG main.cpp
并且总是得到0.48674319998526999 4602440005894221059
.
如何_set_FMA3_enable(0)
使用 gcc 重现结果?
视觉工作室 16.7.4。gcc 版本 9.3.0(带 wsl)
c++ - 对 FMA 操作进行更积极的优化
我想构建一个表示多个(比如说N
)算术类型的数据类型,并使用运算符重载提供与算术类型相同的接口,这样我就得到了像 Agner Fog 的vectorclass这样的数据类型。
请看这个例子:Godbolt
对于一定数量的元素,这似乎工作得很好,gcc-10 为 6,clang-11 为 27。对于大量元素,编译器不再使用 FMA(例如vfmadd213pd
)操作。相反,它们分别进行乘法(例如vmulpd
)和加法(例如vaddpd
)。
问题:
- 这种行为有充分的理由吗?
- 是否有任何编译器标志可以让我可以为 gcc 增加 6 和为 clang 增加 27 的上述值?
谢谢!
math - 如何在支持 FMA 的 GPU 上改进浮点除法?
当使用通过 SPIR-V(特别是 Vulkan)转换计算着色器的 API 为 GPU 编写计算代码时,我保证浮点除法的 ULP 误差最多为 3。其他基本算术(加法、乘法)是正确舍入。
在这些情况下如何有效地实现正确的舍入划分?让我们假设 FMA 可用且已正确舍入。
非规范化会发生什么将取决于底层硬件。Vulkan API 允许查询设备是否可以保留非正规以及是否可以将它们刷新为零(因此不完全支持非正规的 GPU 将具有“canPreserve: false, canFlush: true”)。因此,让我们另外假设 GPU 可以生成和处理非规范化,而不会将它们刷新为零(否则尝试生成不正常的正确舍入结果似乎是徒劳的)。
cuda - 没有显式内在函数的 CUDA 半浮点运算
我正在使用 CUDA 11.2,我使用该__half
类型对 16 位浮点值进行操作。
我很惊讶 nvcc 编译器在我这样做时不会正确调用融合乘加指令:
它不是发出一个融合乘法加法,而是发出单独的 mul 和 add 指令。
请注意,尽管使用了--fmad=true
编译器选项。
而显式__hfma( a,b,c )
将发出:
是使用 16 位浮点乘加来使用显式内在函数的唯一方法吗?
math - 如何在GPU上找到除法的魔法乘数?
我正在考虑实现以下计算,其中divisor
非零且不是 2 的幂
以一种对缺乏 64 位整数和浮点指令但可能具有 32 位融合乘加(例如 GPU,它也将缺乏除法)的处理器有效的方式。
此计算对于查找优化除法所涉及的“魔术乘法器”很有用,当除数提前知道时,乘高指令后跟按位移位。与编译器中使用的代码和 libdivide 中的参考代码不同,它会找到最大的乘数。
另一个转折是,在我正在查看的应用程序中,我预计它divisor
几乎总是可以用float
类型表示。因此,有一个有效的“快速路径”来处理这些除数,以及一个大小优化的“慢路径”来处理其余部分是有意义的。
c++ - 用avx对整数'mul and add'有更好的实现吗?
我刚刚学会了如何GEMM
使用 x86 向量寄存器进行优化,我们得到了条目为 的矩阵, 32-bit int
为了简化而忽略了溢出。有一个_mm256_fmadd_pd
用于更新结果的双浮点数C = AB+C
,但对于整数,似乎没有这样的 FMA 指令。我首先尝试_mm256_mullo_epi32
忽略溢出,然后_mm256_add_epi32
将其总结为
实验室的服务器有一个 Cascade Lake Xeon(R) Gold 6226R
,带有GCC 7.5.0
.
Intel Guide告诉我mullo
CPI 的成本比mul
(几乎是两倍,延迟更高),这肯定会影响性能。在这种情况下是否有任何 FMA 指令或更好的实现?
c# - 为什么 Fma 代码的性能比 Avx 差?
我正在编写基本的线性代数子程序(BLAS)库。fma 代码的性能存在一个问题。
以下是基准测试结果。测试机为Intel Core i5-7200U(Skylake架构)。该代码是使用 .NET 5 在 x64 模式下编译的。
方法 | ñ | 意思是 | 错误 | 标准差 | 敏 | 最大限度 | 中位数 | 比率 |
---|---|---|---|---|---|---|---|---|
仿射变换Fma | 68 | 1.805 我们 | 0.0018 我们 | 0.0017 我们 | 1.802 我们 | 1.808 我们 | 1.805 我们 | 1.00 |
仿射变换Avx | 68 | 1.152 我们 | 0.0158 我们 | 0.0140 我们 | 1.137 我们 | 1.184 我们 | 1.150 我们 | 0.64 |
仿射变换Fma | 1159 | 25.966 我们 | 0.1048 我们 | 0.0929 我们 | 25.843 我们 | 26.114 我们 | 25.999 我们 | 1.00 |
仿射变换Avx | 1159 | 14.070 我们 | 0.0174 我们 | 0.0145 我们 | 14.051 我们 | 14.104 我们 | 14.066 我们 | 0.54 |
仿射变换Fma | 4101 | 90.094 我们 | 0.1041 我们 | 0.0974 我们 | 89.865 我们 | 90.214 我们 | 90.140 我们 | 1.00 |
仿射变换Avx | 4101 | 48.180 我们 | 0.0933 我们 | 0.0779 我们 | 48.089 我们 | 48.320 我们 | 48.149 我们 | 0.53 |
仿射变换Fma | 16389 | 360.215 我们 | 0.2143 我们 | 0.1789 我们 | 359.840 我们 | 360.456 我们 | 360.266 我们 | 1.00 |
仿射变换Avx | 16389 | 191.222 我们 | 0.3403 我们 | 0.3183 我们 | 190.660 我们 | 191.765 我们 | 191.170 我们 | 0.53 |
仿射变换Fma | 32773 | 725.299 我们 | 0.8294 我们 | 0.7758 我们 | 723.925 我们 | 726.415 我们 | 725.374 我们 | 1.00 |
仿射变换Avx | 32773 | 379.920 我们 | 0.8381 我们 | 0.6999 我们 | 378.887 我们 | 381.257 我们 | 379.776 我们 | 0.52 |
基准代码:
这有点奇怪。Fma 代码几乎比 avx 慢两倍!基于https://software.intel.com/sites/landingpage/IntrinsicsGuide/ Fma.MultiplyAdd
方法有latency=4和throughput=0.5这意味着可以在4x4x0.5=8个周期内执行4个独立操作(假设处理器只有一个fma 端口,这当然不是真的)。
该方法的 Fma 版本使用两个这样的块,因此加载(延迟 = 7 和吞吐量 = 0.5)和保存(延迟 = 5 和吞吐量 = 1)的一次迭代的总体性能是 4x7x0.5 + 2x4x4x0.5 + 4x5x1 = 50 个周期每 16 个浮点数。
Avx 版本的代码使用 4 个独立的乘法运算(延迟=4 和吞吐量=0.5)和两个独立的加法运算(延迟=4 和吞吐量=0.5)的两个块。因此,加载和保存的整体性能应该是:2x7x0.5 + 4x4x0.5 + 2x4x0.5 + 2x4x0.5 +2x5x1 = 每 8 个浮点数 33 个周期(每 16 个浮点数 66 个周期)。
理论上avx代码应该比fma代码慢。我究竟做错了什么?该代码使用的寄存器不超过 16 个 256 位。我还尝试在没有流水线的情况下测试 Fma 版本的代码 - 结果是相同的(avx 性能更好)。
更新 看起来这只是 BenchmarkDotNet 中的一个错误。在没有 BenchmarkDotNet 框架的情况下编写了几次基准代码后,我得到了以下结果:
方法 | ñ | 时间 | 比率 |
---|---|---|---|
仿射变换Avx | 68 | 27.24 纳秒 | 1.00 |
仿射变换Fma | 68 | 29.19 纳秒 | 1.07 |
仿射变换Avx | 1159 | 258.33 纳秒 | 1.00 |
仿射变换Fma | 1159 | 188.40 纳秒 | 0.73 |
仿射变换Avx | 4101 | 818.48 纳秒 | 1.00 |
仿射变换Fma | 4101 | 582.80 纳秒 | 0.71 |
仿射变换Avx | 16389 | 4,263.31 纳秒 | 1.00 |
仿射变换Fma | 16389 | 2,959.02 纳秒 | 0.69 |
仿射变换Avx | 32773 | 9,782.48 纳秒 | 1.00 |
仿射变换Fma | 32773 | 6,943.25 纳秒 | 0.71 |
是的——在大多数情况下,fma 版本的速度提高了 30%!基准测试的结果不取决于它们的顺序(先是 avx,然后是 fma,反之亦然)