现代处理器的性能

lev*_*tov 6 performance assembly x86-64 amd-processor

在现代处理器(AMD Phenom II 1090T)上执行,以下代码消耗的时钟节拍数量有多少:3或11?

label:  mov (%rsi), %rax
        adc %rax, (%rdx)
        lea 8(%rdx), %rdx
        lea 8(%rsi), %rsi
        dec %ecx
        jnz label
Run Code Online (Sandbox Code Playgroud)

问题是,当我执行此类代码的多次迭代时,结果会不时地在每次迭代的3 OR 11个滴答中变化.我无法决定"谁是谁".

UPD 根据指令延迟表(PDF),我的代码片段在AMD K10微体系结构上至少需要10个时钟周期.因此,每次迭代不可能有3个滴答是由测量中的错误引起的.

解决 @Atom注意到,在现代处理器中,循环频率不是恒定的.当我在BIOS中禁用三个选项 - Core Performance Boost,AMD C1E Support并且AMD K8 Cool&Quiet Control,我的"六条指令"的消耗稳定在3个时钟滴答 :-)

Mys*_*ial 8

我不会尝试肯定回答它有多少个周期(3或10)取来运行每次迭代,但我会解释怎么可能可以得到每次迭代的3个周期.

(请注意,这适用于一般的处理器,我没有提供特定于AMD处理器的参考.)

关键概念:

今天大多数现代(非嵌入式)处理器都是超标量和无序处理器.不仅可以并行执行多个(独立)指令,而且可以重新排序指令以破坏依赖性等.

让我们打破你的榜样:

label:
    mov (%rsi), %rax
    adc %rax, (%rdx)
    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx
    jnz label
Run Code Online (Sandbox Code Playgroud)

首先要注意的是分支前的最后3条指令都是独立的:

    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx
Run Code Online (Sandbox Code Playgroud)

因此,处理器可以并行执行所有这三个.

另一件事是:

adc %rax, (%rdx)
lea 8(%rdx), %rdx
Run Code Online (Sandbox Code Playgroud)

似乎存在依赖性,rdx这阻止了两者并行运行.但实际上,这是错误依赖,因为第二条指令实际上并不依赖于第一条指令的输出.现代处理器能够重命名rdx寄存器以允许这两个指令被重新排序或并行完成.

同样适用于以下rsi注册:

mov (%rsi), %rax
lea 8(%rsi), %rsi
Run Code Online (Sandbox Code Playgroud)

所以最终,(可能)可以实现3个循环,如下所示(这只是几种可能的排序之一):

1:   mov (%rsi), %rax        lea 8(%rdx), %rdx        lea 8(%rsi), %rsi
2:   adc %rax, (%rdx)        dec %ecx
3:   jnz label
Run Code Online (Sandbox Code Playgroud)

*当然,为了简单起见,我过度简化了事情.实际上,延迟可能更长,并且循环的不同迭代之间存在重叠.

无论如何,这可以解释如何获得3个周期.至于为什么你有时会得到10个周期,可能有很多原因:分支错误预测,一些随机的管道泡沫......