我的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个周期
我已经测试了10000000个元素阵列。根据Agners'每次迭代需要6.7个循环(根据perf)和每次迭代5.9个循环。工具。
请解释为什么它需要6/7周期而不是仅仅5个周期?
答案 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)。