将 FPU 异常或 INF 投入工作是否可能/有效

is it possible/efficient to put fpu exception or inf into work?

本文关键字:是否 有效 工作 异常 FPU INF      更新时间:2023-10-16

我得到了这样的代码

环路 10 M:

 if( fz != 0.0)     
 { 
  fhx += hx/fz; 
 } 

这被称为 10 M 次循环需要非常快 - 我需要捕捉 fz 不为零的情况,而不是使div 由零错误,但这是非常罕见的情况,确实在 10M 的情况下它应该是零,我不知道一次、两次或更新

我可以以某种方式摆脱这 10M 的 ifs 并使用"nan/inf",或者可能捕获异常并继续吗?(如果 fz 为零,我需要 fhx += 0.0,我的意思是什么都没有继续?将 FPU 异常或 INF 投入工作是否可能/有效?

(我使用 c++/mingw32(

你可以,但它可能不是那么有用。在这种情况下,遮罩也没有用。

异常发生

时非常慢,首先必须在CPU进入内核级异常处理程序之前发生许多微编码的复杂事情,然后它也必须以复杂而缓慢的方式将其移交给您的进程。另一方面,当它们不发生时,它们不会花费任何费用。

但是比较和分支实际上也不会花费任何费用,只要分支是可预测的,而基本上从未被采用的分支可预测的。当然,要使它们发生需要一点吞吐量,但它们不在关键路径中......但即使是这样,这里真正的问题是每次迭代中的分裂。

无论如何,该除法的通量是每 14 个循环 1 个(在 Haswell 上 - 在其他 μarchs 上更糟(,除非fz特别"好",即使这样,它也是每 8 个周期 1 个(同样在 Haswell 上(。在 Core2 上,它更像是 19 和 5,在 P4 上,它更像(以典型的 P4 方式(每 71 个周期一个除法。

一个预测良好的分支和一个比较就消失在其中。在我的 4770K 上,有比较和分支之间的差异消失在噪音中(也许如果我运行它足够多的次数,我最终会获得统计上显着的差异,但它会很小(,他们俩都随机获胜大约一半时间。我用于此基准测试的代码是

global bench
proc_frame bench
    push r11
[endprolog]
    xor ecx, ecx
    mov rax, rcx
    mov ecx, -10000000
    vxorps xmm1, xmm1
    vxorps xmm2, xmm2
    vmovapd xmm3, [rel doubleone]
_bench_loop:
    imul eax, ecx, -0xAAAAAAAB  ; distribute zeroes somewhat randomly
    shr eax, 1                  ; increase to make more zeroes
    vxorps xmm0, xmm0
    vcvtsi2sd xmm0, eax
    vcomisd xmm0, xmm1          ; #
    jz _skip                    ; #
    vdivsd xmm0, xmm3, xmm0
    vaddsd xmm2, xmm0
_skip:
    add ecx, 1
    jnz _bench_loop
    vmovapd xmm0, xmm2
    pop r11
    ret
endproc_frame

另一个函数是相同的,但用#标记的两行被注释掉了。

当零数增加时,最终始终获胜的版本是带有分支的版本,表明除以零比分支错误预测要慢得多。这甚至没有使用异常机制来创建程序员可见的异常,它只是来自微编码的"奇怪案例修复"运行的成本。但是你没有那么多零,所以,

TL;DR 实际上没有区别。