两个循环携带的依赖链。哪一个很重要?

时间:2016-05-19 21:30:03

标签: performance optimization x86

我的CPU是IvyBridge。 让我们考虑来自Agner的Fog optimization_assembly的例子,我的意思是。 12.6章和12.10a例子:

    movsd xmm2, [x] 
    movsd xmm1, [one] 
    xorps xmm0, xmm0  
    mov eax, coeff    

    L1:
        movsd xmm3, [eax] ; c[i]
        mulsd xmm3, xmm1  ; c[i]*x^i
        mulsd xmm1, xmm2  ; x^(i+1)
        addsd xmm0, xmm3  ; sum += c[i]*x^i
        add   eax, 8
        cmp eax, coeff_end
        jb L1

并且前端不是瓶颈(很明显,因为乘法的延迟)。

我们有两个循环携带的依赖项(我跳过了add eax, 8): 1. mulsd xmm1, xmm2潜伏期为5个周期 2. addsd xmm0, xmm3潜伏期为3个周期

顺便说一下,我有一个问题需要决定:我应该总结(5 + 3 = 8)还是得到最大的,即5个周期?

我已经测试了10000000个元素阵列。根据Agners'每次迭代需要6.7个循环(根据perf)和每次迭代5.9个循环。工具。

请解释为什么它需要6/7周期而不是仅仅5个周期?

1 个答案:

答案 0 :(得分:1)

可能资源冲突有时会延迟循环携带的mulsd。 uop调度选择最早的(从准备好输入的uops中),而不是关键路径优先,因此mulsd xmm3, xmm1可能会窃取执行端口并将循环携带的mulsd xmm1, xmm2延迟一个周期偶尔

由于硬件预取在页面边界不起作用,因此可能还会偶尔出现缓存未命中的管道停顿。通过在~128kiB数据(1/2 L2缓存大小)上的内部循环周围放置一个外部重复循环来测试。

预取应该没有问题正常跟上你的循环:每5个循环一个64b负载大约是主内存带宽的1/5。

您也可以使用float代替double

您的数据是否有任何非正规数?这些都很慢(but NaN isn't, with SSE)