每个浮点运算是否需要同一时间?

时间:2016-08-23 08:24:15

标签: performance floating-point cpu-architecture micro-optimization alu

我相信无论操作数有多大,整数加法或减法总是占用相同的时间。 ALU输出稳定所需的时间可能会因输入操作数而异,但利用ALU输出的CPU组件将等待足够长的时间,以便在SAME周期中处理任何整数操作。 (ADD,SUB,MUL和DIV所需的周期会有所不同,但我认为无论输入操作数如何,ADD都会采用相同的周期。)

这也适用于浮点运算吗?

我正在尝试实现一个包含大量浮点运算的程序。我想知道为了快速运行时间缩放我正在处理的数字是否有帮助。

1 个答案:

答案 0 :(得分:3)

TL:DR:避免非正常数字,你很好。如果您不需要逐渐下溢,请在x86 MXCSR中设置Denormals Are Zero和Flush To Zero位,或者为其他架构设置等效位。在大多数CPU中,产生非正规结果陷阱到微码,因此它需要数百个周期而不是5个。

有关x86 CPU详细信息,请参阅Agner Fog's insn tables,以及标记wiki。

这取决于你的CPU,但典型的现代FPU在这方面都很相似。

除了非正规操作数之外,添加/子/ mul操作的延迟/吞吐量不依赖于典型的现代FP (包括x86,ARM和其他)。它们通常是完全流水线化的,但具有多周期延迟(即,如果其输入准备就绪,则每个周期都可以开始执行新的MUL),这使得可变延迟对于无序调度不方便。

可变延迟意味着两个输出将在同一周期内准备就绪,从而无法完全流水线化,并使调度程序无法像处理已知但混合的延迟指令时那样可靠地避免冲突/微指令。 (These lecture notes about in-order pipelines show how that's a structural hazard for write-back (WB),但同样的想法适用于ALU本身需要一个额外的缓冲区,直到它可以传递它准备好的所有结果。)

作为高性能端的一个例子: Intel Haswell

  • mulpd(标量,128b或256b双精度向量):5c延迟,每1c吞吐量两个(两个独立的ALU)。
  • FMA:5c延迟,每1c吞吐量两次
  • addpd / subpd:3c延迟,每1c吞吐量一个。 (但添加单元与mul / FMA单元之一在同一端口上)
  • divpd(标量或128b向量):10-20c延迟,每8-14c吞吐量一个。 (也与mul / FMA单元之一在同一端口上)。 256b向量较慢(div ALU不是全宽)。 {/ 1}}的速度稍快,与add / sub / mul不同。
  • float:16c延迟,每8-14c吞吐量一个。同样不是全宽,sqrtpd更快。
  • float(快速非常近似,仅适用于rsqrtps):5c延迟,每1c吞吐量一个。

div / sqrt是个例外:它们的吞吐量和延迟是数据相关的

div或sqrt没有快速并行算法even in hardware。需要进行某种迭代计算,因此完全流水线操作需要为每个流水线阶段复制许多非常相似的硬件。尽管如此,现代的英特尔x86 CPU还是部分流水线的div和sqrt,其吞吐量相当于延迟。

与mul相比,div / sqrt具有更低的吞吐量(~1 / 10或更差),以及显着更高的延迟(~2x到4x)。现代FPU中div / sqrt单元的非完全流水线特性意味着它可以是可变延迟,而不会在ALU输出端口引起太多冲突。

SSE / AVX不会将sin / cos / exp / log实现为单个指令;数学库应该自己编写代码。

许多优秀的数学图书馆甚至在SSE存在之前都没有使用x87 fsin;它在所有现有实现上进行了微编码,因此内部实现使用相同的80位add / sub / mul / div / sqrt硬件,您可以使用简单的指令进行编程;没有专用的float硬件(或至少不多;可能是查找表)。大多数其他trig / transcendental x87函数也是如此,例如fsin

如果有一些专用的fyl2x硬件会很好,因为范围减小到+/- Pi / 2可以真正受益于非常接近Pi / 2倍数的输入的更高精度。 fsin使用与fsin相同的80位Pi常量(64位尾数)。这是与Pi的精确值最接近的可表示fldpi,并且接下来的两个二进制数字偶然为零,因此它实际上精确到66位。但它仍导致a worst-case maximum error of 1.37 quintillion units in the last place, leaving fewer than four bits correct。 ( Bruce Dawson关于浮点的一系列文章优秀,如果您要编写一些浮点代码,就一定要阅读它们。 Index in this one.

英特尔无法在不破坏与现有CPU的数字兼容性的情况下提高x87 long double的范围缩减精度。它对于不同的x86 CPU来说非常有用,当使用相同的输入运行相同的指令时,会给出数字相同的结果。在软件中,您可以使用扩展精度浮点自行进行范围缩减,例如所谓的double double以获得四倍精度(但仍然只有fsin的指数范围)。使用SSE2打包双指令可以相当有效地实现double double。 double的SSE2库实现可能需要速度超过精度,并与x87硬件进行相同的权衡;仅使用常规fsin Pi常数来减少范围,导致最坏情况下的大错误。对于某些用例来说,这将是一个有效的选择,这是软件的一大优势:您可以为您的用例选择合适的软件实现。

IDK关于x87 exp或日志指令,如fyl2x。他们进行了微编码,所以他们对速度没有什么特别之处,但对于准确性来说可能还不错。尽管如此,现代数学库不会仅仅为该指令将xmm寄存器中的值复制到x87。 x87指令可能比使用普通SSE数学指令要慢。 (而且几乎肯定不会更快。)

有关快速倒数和快速倒数sqrt的更多信息,请参阅Why is SSE scalar sqrt(x) slower than rsqrt(x) * x?

使用Newton-Raphson迭代的

rsqrtps比普通sqrtps略精确。在Intel Haswell / Skylake上,它涉及相同的延迟IIRC,但可能具有更好的吞吐量。没有NR迭代,对于大多数用途来说它太不准确了。

无论如何,这已经具有x86特定性。 mul与sqrt的相对性能在很大程度上取决于CPU微体系结构,但即使在x86与ARM相比,与大多数其他具有硬件FPU的现代CPU相比,你应该会发现doublemul性能不高。 ; t数据依赖。