Performance 在循环中插入nop和在movnti存储区附近读取导致意外减速 我无法理解为什么第一个代码每次迭代有~1个周期,而第二个代码每次迭代有2个周期。我用Agner的工具和性能测量。根据IACA,从我的理论计算来看,它应该需要1个周期
每次迭代需要1个周期。Performance 在循环中插入nop和在movnti存储区附近读取导致意外减速 我无法理解为什么第一个代码每次迭代有~1个周期,而第二个代码每次迭代有2个周期。我用Agner的工具和性能测量。根据IACA,从我的理论计算来看,它应该需要1个周期,performance,optimization,x86,micro-optimization,Performance,Optimization,X86,Micro Optimization,每次迭代需要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
; 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。
movnti
是2个uops,不能微熔合,根据IvyBridge的说法
因此,您的第一个循环是4个融合域UOP,并且可以在每个时钟的一次迭代中发出
nop
是第五个融合域uop(即使它不接受任何执行端口,所以它是0个未融合域uop)。这意味着前端只能以每2个时钟发出一个循环
有关CPU工作方式的更多链接,请参见TagWiki
第三个循环可能很慢,因为
mov rbx、[array+16]
可能是从moventi
退出的同一缓存线加载的。每次刷新它存储到的填充缓冲区时都会发生这种情况。(不是每个movnti
,显然它可以在同一个填充缓冲区中重写某些字节。)如果您打算很快读取它,请避免非临时存储。非时态存储的全部要点是只写突发,不会导致行被“写分配”(读)到缓存中。指令的使用告诉CPU“不要把它放在缓存中,只要把它写到内存中,我保证不会很快使用它”来自同一个用户的相关问题。什么是填充缓冲区?是的,当mov-rbx、[array+64]
代替mov-rbx、[array+16]
时,循环再次变快。缓存线只有64个字节。@J.Doe。查看我对您的另一个movinti
问题的回答;我包括了一个链接,指向一篇英特尔文章,该文章讨论了写组合填充缓冲区。是的,我看到了:)谢谢