>我无法理解为什么第一个代码每次迭代有~1个循环,第二个代码每次迭代有2个循环.我用Agner的工具和perf测量.根据IACA,我的理论计算也需要1个周期.
每次迭代需要1个周期.
; array is array defined in section data
%define n 1000000
xor rcx, rcx
.begin:
movnti [array], eax
add rcx, 1
cmp rcx, n
jle .begin
这每次迭代需要2个周期.但为什么?
; array is array defined in section data
%define n 1000000
xor rcx, rcx
.begin:
movnti [array], eax
nop
add rcx, 1
cmp rcx, n
jle .begin
这个最终版本每次迭代需要大约27个周期.但为什么?毕竟,没有依赖链.
.begin:
movnti [array], eax
mov rbx, [array+16]
add rcx, 1
cmp rcx, n
jle .begin
我的CPU是IvyBridge.
最佳答案 根据
Agner Fog’s tables对于IvyBridge来说,movnti是2 uops,并且不能微熔丝.
所以你的第一个循环是4个融合域uops,并且每个时钟可以发出一次迭代.
nop是第5个融合域uop(即使它不占用任何执行端口,因此它是0个未融合域uop).这意味着前端只能每2个时钟发出一个循环.
另请参阅x86标记wiki,以获取有关CPU工作方式的更多链接.
第三个循环可能很慢,因为mov rbx,[array 16]可能是从movnti驱逐的同一个缓存行加载的.每次刷新它所存储的填充缓冲区时都会发生这种情况. (不是每个movnti,显然它可以在同一个填充缓冲区中重写一些字节.)