6

在现代处理器 (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

问题是,当我对此类代码执行多次迭代时,每次迭代的结果不时变化接近 3 或 11 个滴答声。我无法决定“谁是谁”。

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

已解决 @Atom注意到,现代处理器 中的循环频率不是恒定的。当我在 BIOS 中禁用三个选项时 -和Core Performance Boost,我的“六条指令”的消耗稳定在3 个时钟周期:-)AMD C1E SupportAMD K8 Cool&Quiet Control

4

2 回答 2

8

我不会试图肯定地回答每次迭代需要多少个周期(3 或 10 个),但我会解释每次迭代如何获得3 个周期。

(请注意,这是针对一般处理器的,我没有针对 AMD 处理器做任何参考。)

关键概念:

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

让我们分解你的例子:

label:
    mov (%rsi), %rax
    adc %rax, (%rdx)
    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx
    jnz label

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

    lea 8(%rdx), %rdx
    lea 8(%rsi), %rsi
    dec %ecx

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

另一件事是这样的:

adc %rax, (%rdx)
lea 8(%rdx), %rdx

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

同样适用于以下rsi之间的寄存器:

mov (%rsi), %rax
lea 8(%rsi), %rsi

所以最后,(可能)可以实现 3 个周期,如下所示(这只是几个可能的顺序之一):

1:   mov (%rsi), %rax        lea 8(%rdx), %rdx        lea 8(%rsi), %rsi
2:   adc %rax, (%rdx)        dec %ecx
3:   jnz label

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

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

于 2011-12-30T06:39:35.320 回答
2

在英特尔,David Levinthal 博士的“性能分析指南”非常详细地调查了这些问题的答案。

于 2011-12-29T22:41:54.597 回答