代码之家  ›  专栏  ›  技术社区  ›  codebomb

每个浮点运算的时间是否相同?

  •  3
  • codebomb  · 技术社区  · 8 年前

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

    浮点运算也是如此吗?

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

    1 回复  |  直到 8 年前
        1
  •  6
  •   Peter Cordes Steve Bohrer    6 年前

    TL:DR:避免非正规数字,你就没事了 。如果不需要逐渐下溢,请在x86 MXCSR中设置“Denormals Are Zero”和“Flush To Zero”位,或其他架构的等效值。在大多数CPU中,生成非正规结果陷阱到微码,因此需要数百个周期而不是5个周期。

    看见 Agner Fog's insn tables 有关x86 CPU的详细信息,以及 标记wiki。


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

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

    作为高性能端的一个例子: 处理器 :

    • 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不是全宽)。速度更快 float s、 与add/sub/mul不同。
    • sqrtpd 浮动 .
    • rsqrtps (速度非常接近,仅适用于 浮动 ):5c延迟,每1c吞吐量一个。

    div/sqrt是例外:它们的吞吐量和延迟依赖于数据 .

    div或sqrt没有快速并行算法, even in hardware 。需要某种迭代计算,因此完全流水线化需要为每个流水线阶段复制大量非常相似的硬件。不过,现代Intel x86 CPU具有部分流水线div和sqrt,互反吞吐量小于延迟。

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

    许多好的数学库没有使用 x87 fsin fsin型 fyl2x .

    如果有专门的 fsin型 硬件,因为对于非常接近Pi/2倍数的输入,范围缩小到+/-Pi/2可能真正受益于更高的精度。 fsin型 使用与您从中获得的相同的80位Pi常量(带有64位尾数) fldpi .这是最近的代表 long double 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. )

    英特尔无法提高x87的射程缩小精度 fsin型 不破坏与现有CPU的数字兼容性。当使用相同的输入运行相同的指令时,不同的x86 CPU会给出数字相同的结果,这一点非常有用。在软件中,您可以使用扩展精度浮点自己进行范围缩减,如所谓的 double double 以获得四元精度(但仍仅为 double ). 使用SSE2压缩double指令可以相当有效地实现double double。SSE2库实现 fsin型 可能会追求速度而非精度,并与x87硬件进行同样的权衡;只使用常规 双重的 Pi常数用于范围缩小,在最坏的情况下会导致较大的误差。对于某些用例来说,这是一个有效的选择,这也是软件的一大优势:您可以为您的用例选择正确的软件实现。

    IDK关于x87 exp或日志指令,如 fyl2x 。它们是微码的,所以它们在速度上没有什么特别之处,但在准确性上可能还可以。然而,现代数学库不会仅为该指令将值从xmm寄存器复制到x87。x87指令可能比普通SSE数学指令慢。(几乎肯定不会更快。)


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

    rsqrtps 使用Newton-Raphson迭代的精度略低于普通的sqrtps。在Intel Haswell/Skylake上,延迟IIRC大致相同,但吞吐量可能更好。如果没有NR迭代,对于大多数用途来说,它都太不准确了。

    无论如何,这已经变得非常特定于x86。mul与sqrt的相对性能在很大程度上取决于CPU微体系结构,但即使是在x86、ARM和大多数其他具有硬件FPU的现代CPU之间,您也应该发现 mul add 性能与数据无关。