如何执行更多指令可以加快执行速度

时间:2011-10-05 09:01:12

标签: assembly intel timing

当我运行以下功能时,我得到了一些意想不到的结果。

在我的机器上,下面的代码一直需要大约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 指令填充代码以查看它是否是对齐问题,并且还将关联设置为单个处理器。没有任何区别。

3 个答案:

答案 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,您观察到的差异,时间差异变得非常明显。