我在 Stack Overflow 上阅读了这个非常有趣的问题:
其中一条评论说:
“在 Haswell 上,FP 乘法吞吐量是 FP 加法的两倍,这是毫无价值的。这是因为端口 0 和 1 都可以用于乘法,但只有端口 1 可以用于加法。也就是说,你可以用 fused 作弊-multiply 添加,因为两个端口都可以做到。”
为什么它们允许的同时乘法是加法的两倍?
我在 Stack Overflow 上阅读了这个非常有趣的问题:
其中一条评论说:
“在 Haswell 上,FP 乘法吞吐量是 FP 加法的两倍,这是毫无价值的。这是因为端口 0 和 1 都可以用于乘法,但只有端口 1 可以用于加法。也就是说,你可以用 fused 作弊-multiply 添加,因为两个端口都可以做到。”
为什么它们允许的同时乘法是加法的两倍?
如果不是正文,这可能会回答问题的标题:
浮点加法需要在添加它们之前对齐两个尾数(取决于两个指数之间的差异),可能需要在加法器之前进行大量可变的移位。然后可能需要对尾数加法的结果进行重新归一化,这可能需要另一个大量可变的移位才能正确格式化浮点结果。因此,两个尾数桶形移位器可能需要更多的门延迟、更大的线延迟或超过紧凑的进位保存加法器树乘法器前端延迟的额外周期。
为 OP 添加:请注意,添加 2 毫米和 2 公里的长度不是任何一个单位的 4。这是因为在添加之前需要将一种或另一种测量转换为相同的比例或单位表示。这种转换基本上需要乘以 10 的某个幂。在浮点加法期间通常需要发生同样的事情,因为浮点数是可变比例整数的一种形式(例如,有一个单位或比例因子,一个指数,与每个数字)。因此,在添加原始尾数位之前,您可能需要将其中一个数字按 2 的幂进行缩放,以使两者代表相同的单位或比例。这种缩放本质上是乘以 2 的幂的一种简单形式。 因此,浮点加法需要乘法(它是 2 的幂,可以通过可变位移或桶形移位器来完成,这可能需要与晶体管尺寸相关的相对较长的导线,这在深亚微米光刻电路中可能相对较慢)。如果这两个数字大部分取消(因为一个几乎是另一个的负数),那么可能需要重新调整加法的结果以及适当地格式化结果。因此,如果由于数字格式的性质(IEEE 浮点)。
添加 #2:此外,许多基准测试对 FMACS(乘法累加)的权重超过了裸添加。在融合 MAC 中,加数的对齐(移位)通常可以与乘法并行完成,并且尾数加法通常可以在最终进位传播之前包含在 CSA 树中。
在 FP 乘法中,指数处理变成了简单的加法(与对数域中的乘法只是加法的原因完全相同)。我希望你遇到过对数。
现在考虑以对数形式 将两个数字相加是多么困难......
浮点位于线性域和对数域之间的灰色区域,两者都有。每个 FP 数包括尾数(线性)和(对数)指数。要确定尾数中每一位的含义,您首先必须查看指数(它只是一个比例因子)。
在 FP 加法中,一般情况下的指数处理需要对尾数进行两次桶形移位,其中每个桶形移位实际上是稍微简化的乘法的特殊情况。
(第一次移位将两个输入对齐到相同的 2 次方,因此尾数位在每个操作数中具有相同的二进制权重。
十进制示例就足够了(尽管显然使用了二进制)...
第二个重新缩放输出......
因此自相矛盾的是,FP 加法涉及的东西非常类似于必须按顺序执行的两次乘法,它们之间有尾数加法。有鉴于此,报告的表现并不令人惊讶。
TL:DR:因为英特尔认为 SSE/AVX FP 添加延迟比吞吐量更重要,所以他们选择不在 Haswell/Broadwell 的 FMA 单元上运行它。
Haswell 在与 FMA ( Fused Multiply-Add )相同的执行单元上运行 (SIMD) FP 乘法,其中有两个,因为一些 FP 密集型代码可以主要使用 FMA 来执行每条指令 2 次 FLOP。mulps
与 FMA 和早期 CPU (Sandybridge/IvyBridge) 相同的 5 个周期延迟。Haswell 想要 2 个 FMA 单元,让乘法在其中任何一个上运行都没有缺点,因为它们与早期 CPU 中的专用乘法单元具有相同的延迟。
但它使早期 CPU 的专用 SIMD FP 添加单元仍然运行addps
/addpd
具有 3 个周期延迟。 我已经读到可能的原因可能是添加大量 FP 的代码往往会成为延迟而不是吞吐量的瓶颈。对于只有一个(向量)累加器的数组的简单求和,这当然是正确的,就像您经常从 GCC 自动向量化中得到的那样。但我不知道英特尔是否公开证实这是他们的推理。
Broadwell 是相同的(但在 FMA 保持在 5c 时加快了mulps
/到 3c 的延迟)。mulpd
也许他们能够缩短 FMA 单元并在对 进行虚拟加法之前得到乘法结果0.0
,或者可能是完全不同的东西,这太简单了。 BDW 主要是 HSW 的缩模,大多数变化都很小。
在 Skylake 中,所有 FP(包括加法)都在 FMA 单元上运行,具有 4 个周期延迟和 0.5c 吞吐量,当然除了 div/sqrt 和按位布尔值(例如,用于绝对值或否定)。英特尔显然认为不值得为低延迟 FP 添加额外的芯片,或者不平衡的addps
吞吐量是有问题的。并且标准化延迟也使得在 uop 调度中更容易避免回写冲突(当在同一周期中准备好 2 个结果时)。即简化调度和/或完成端口。
所以是的,英特尔确实在他们的下一个主要微架构修订版(Skylake)中改变了它。 对于延迟受限的情况,将 FMA 延迟减少 1 个周期使得专用 SIMD FP 添加单元的优势要小得多。
Skylake 还显示出英特尔为 AVX512 做好准备的迹象,其中将单独的 SIMD-FP 加法器扩展到 512 位宽将占用更多的芯片面积。据报道,Skylake-X(带有 AVX512)具有与常规 Skylake 客户端几乎相同的内核,除了更大的 L2 缓存和(在某些型号中)“固定”到端口 5 的额外 512 位 FMA 单元。
SKX 在 512 位微指令运行时关闭端口 1 SIMD ALU,但它需要一种随时执行的方法vaddps xmm/ymm/zmm
。这使得在端口 1 上有一个专用的 FP ADD 单元成为一个问题,并且是改变现有代码性能的另一个动机。
有趣的事实:Skylake、KabyLake、Coffee Lake 甚至 Cascade Lake 的所有东西在微架构上都与 Skylake 相同,只是 Cascade Lake 添加了一些新的 AVX512 指令。IPC 没有其他变化。不过,较新的 CPU 具有更好的 iGPU。Ice Lake(Sunny Cove 微架构)是几年来我们第一次看到真正的新微架构(除了从未广泛发布的 Cannon Lake)。
基于 FMUL 单元与 FADD 单元的复杂性的争论很有趣,但在这种情况下不相关。 FMA 单元包括所有必要的移位硬件,作为 FMA 1的一部分进行 FP 添加。
注意:我不是指 x87fmul
指令,我指的是支持 32 位单精度/float
和64 位double
精度(53 位有效位又称为尾数)的 SSE/AVX SIMD/标量 FP 乘法 ALU。例如mulps
或之类的指令mulsd
。实际的 80 位 x87fmul
在 Haswell 端口 0 上仍然只有 1/时钟吞吐量。
现代 CPU 有足够多的晶体管来解决问题,当它值得时,并且不会导致物理距离传播延迟问题。特别是对于仅在某些时候处于活动状态的执行单元。请参阅https://en.wikipedia.org/wiki/Dark_silicon和 2011 年会议论文:暗硅和多核扩展的终结. 这使得 CPU 可以拥有大量 FPU 吞吐量和大量整数吞吐量,但不能同时拥有两者(因为这些不同的执行单元位于相同的调度端口上,因此它们相互竞争)。在许多经过仔细调整且不会成为内存带宽瓶颈的代码中,限制因素的不是后端执行单元,而是前端指令吞吐量。(宽核非常昂贵)。另见http://www.lighterra.com/papers/modernmicroprocessors/。
在 HSW 之前,像 Nehalem 和 Sandybridge 这样的英特尔 CPU 在端口 0 上进行 SIMD FP 乘法运算,在端口 1 上进行 SIMD FP 加法运算。因此有单独的执行单元并且吞吐量是平衡的。(https://stackoverflow.com/questions/8389648/how-do-i-achieve-the-theoretical-maximum-of-4-flops-per-cycle
Haswell 在 Intel CPU 中引入了 FMA 支持(在 AMD 在 Bulldozer 中引入 FMA4 几年后,在Intel通过尽可能晚地等待公开他们将实现 3 操作数 FMA,而不是 4 操作数非-破坏性目的地 FMA4)。有趣的事实:AMD Piledriver仍然是第一款采用 FMA3 的 x86 CPU,比2013 年 6 月 Haswell 早一年
这需要对内部进行一些重大修改才能支持具有 3 个输入的单个 uop。但无论如何,英特尔全力以赴,利用不断缩小的晶体管安装两个 256 位 SIMD FMA 单元,使 Haswell(及其继任者)成为 FP 数学的野兽。
英特尔可能考虑的性能目标是 BLAS 密集 matmul 和矢量点积。两者都可以主要使用 FMA,不需要添加。
正如我之前提到的,一些主要或只是 FP 添加的工作负载在添加延迟方面遇到瓶颈,(主要)不是吞吐量。
脚注 1 : 乘以1.0
, FMA 字面上可用于加法,但延迟比addps
指令差。这对于像在 L1d 缓存中对热的数组求和这样的工作负载可能很有用,其中 FP 增加吞吐量比延迟更重要。当然,这只有在您使用多个向量累加器来隐藏延迟并在 FP 执行单元中保持 10 个 FMA 操作进行时才有帮助(5c 延迟 / 0.5c 吞吐量 = 10 个操作延迟 * 带宽积)。 在将 FMA 用于矢量点积时,您也需要这样做。
请参阅David Kanter 撰写的关于 Sandybridge 微体系结构的文章,其中有一个框图,说明了哪些 EU 位于 NHM、SnB 和 AMD Bulldozer 系列的哪个端口上。(另请参阅Agner Fog 的指令表和 asm 优化微架构指南,以及https://uops.info/,它还对多代英特尔微架构上几乎每条指令的微指令、端口和延迟/吞吐量进行了实验测试。)
我要看看这部分:
“为什么他们会允许”......
TL;DR - 因为他们是这样设计的。这是一个管理决策。当然有尾数和移位器的答案,但这些都是管理决策的内容。
他们为什么要这样设计?答案是规格是为了满足某些目标而制定的。这些目标包括性能和成本。性能不是针对操作的,而是针对孤岛危机中的 FLOPS 或 FPS 之类的基准。
这些基准测试将具有混合功能,其中一些可以同时处理。
如果设计者认为拥有两个小部件 A 的功能比小部件 B 的两个功能更快,那么他们会选择小部件 A。实现两个 A 和两个 B 将花费更多。
回顾当超标量和超流水线(在多核之前)首次在商业芯片上普及时,这些都是为了提高性能。Pentium 有两个管道,没有矢量单元。Haswell 有更多的管道、矢量单元、更深的管道、专用功能等等。为什么不是所有东西都有两个?因为他们是这样设计的。