当我运行以下功能时,我得到了一些意想不到的结果。
在我的机器上,下面的代码一直需要大约6秒才能运行。但是,如果我取消注释“;dec [variable + 24]
”行,因此执行更多代码,则运行大约需要4.5秒。为什么呢?
.DATA
variable dq 0 dup(4)
.CODE
runAssemblyCode PROC
mov rax, 2330 * 1000 * 1000
start:
dec [variable]
dec [variable + 8]
dec [variable + 16]
;dec [variable + 24]
dec rax
jnz start
ret
runAssemblyCode ENDP
END
我注意到Stack Overflow上已经存在类似的问题,但他们的代码示例并不像这样简单,我找不到这个问题的任何简洁答案。
我尝试使用 nop 指令填充代码以查看它是否是对齐问题,并且还将关联设置为单个处理器。没有任何区别。
答案 0 :(得分:3)
简单的答案是,因为现代CPU非常复杂。在引擎盖下有很多事情对观察者来说是不可预测或随机的。
插入额外的指令可能会导致它以不同的方式安排指令,这样的紧密循环可能会产生影响。但这只是猜测。
据我所知,它触及与前一条指令相同的缓存行,因此它似乎不是一种预取。我真的不能想到一个合乎逻辑的解释,但是再一次,CPU利用了大量未经证实的启发式方法并猜测尽可能快地执行代码,有时,这意味着它们失败的奇怪角落情况,代码变为比你想象的慢。
您是否在不同的CPU型号上进行了测试?有趣的是看看这是在你的特定CPU上,还是其他x86 CPU表现出同样的东西。
答案 1 :(得分:1)
bob.s
.data
variable:
.word 0,0,0,0
.word 0,0,0,0
.word 0,0,0,0
.word 0,0,0,0
.word 0,0,0,0
.word 0,0,0,0
.text
.globl runAssemblyCode
runAssemblyCode:
mov $0xFFFFFFFF,%eax
start_loop:
decl variable+0
decl variable+8
decl variable+16
;decl variable+24
dec %eax
jne start_loop
retq
ted.c
#include <stdio.h>
#include <time.h>
void runAssemblyCode ( void );
int main ( void )
{
volatile unsigned int ra,rb;
ra=(unsigned int)time(NULL);
runAssemblyCode();
rb=(unsigned int)time(NULL);
printf("%u\n",rb-ra);
return(0);
}
gcc -O2 ted.c bob.s -o ted
这是额外的指示:
00000000004005d4 <runAssemblyCode>:
4005d4: b8 ff ff ff ff mov $0xffffffff,%eax
00000000004005d9 <start_loop>:
4005d9: ff 0c 25 28 10 60 00 decl 0x601028
4005e0: ff 0c 25 30 10 60 00 decl 0x601030
4005e7: ff 0c 25 38 10 60 00 decl 0x601038
4005ee: ff 0c 25 40 10 60 00 decl 0x601040
4005f5: ff c8 dec %eax
4005f7: 75 e0 jne 4005d9 <start_loop>
4005f9: c3 retq
4005fa: 90 nop
我没有看到差异,也许你可以纠正我的代码或其他人可以尝试他们的系统看看他们看到的......
这是一个非常痛苦的指令加上如果你做的事情不是基于字节的内存减少,这是一种未对齐的内存系统会让你感到痛苦。所以这个例程应该对缓存行以及核心数等敏感。
在有或没有额外指令的情况下花了大约13秒。
amd phenom 9950四核处理器
在
上Intel(R)Core(TM)2 CPU 6300
无论是否有额外的指示,花了大约9-10秒。
双处理器: 英特尔(R)Xeon(TM)CPU
无论是否有额外的指示,花了大约13秒钟。
关于这个: 英特尔(R)酷睿(TM)2 Duo CPU T7500
有或没有8秒。
所有正在运行Ubuntu 64位10.04或10.10,可能是11.04。
更多机器,64位,ubuntu
Intel(R)Xeon(R)CPU X5450(8核)
带或不带额外指令的6秒钟。
Intel(R)Xeon(R)CPU E5405(8核)
有或没有9秒。
系统中DDR / DRAM的速度是多少?你正在运行什么样的处理器(如果在linux上,则为cat / proc / cpuinfo)。
Intel(R)Xeon(R)CPU E5440(8核)
带或不带的6秒
啊,发现了一个核心,但是xeon: 英特尔(R)Xeon(TM)CPU
15秒,无论是否有额外指令
答案 2 :(得分:0)
这并不坏。平均而言,完整的循环需要2.6 ns才能执行,而另一个需要1.9 ns。假设一个2GHz的CPU,周期为0.5 ns,每个循环的差异大约为(2.6 - 1.9) / 0.5 = 1 clock cycle
,这一点都不令人惊讶。
但是,由于您请求的周期数0.5 ns * 2330000000 = 1.2 seconds
,您观察到的差异,时间差异变得非常明显。