在现代处理器(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 OR 11个滴答中不时变化。我无法决定“谁是谁”。
UPD 根据{{3}},我的代码片段在AMD K10微体系结构上至少需要10个时钟周期。因此,每次迭代不可能有3个滴答是由测量中的错误引起的。
解决
@Atom注意到,现代处理器中的周期频率不是恒定的。当我在BIOS中禁用了三个选项 - Core Performance Boost
,AMD C1E Support
和AMD K8 Cool&Quiet Control
时,我的“六条指令”的消耗在 3时钟刻度上稳定了: - )
答案 0 :(得分: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
阻止两者并行运行。但实际上,这是 false依赖,因为第二条指令实际上并不存在
取决于第一条指令的输出。现代处理器能够重命名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个周期,可能有很多原因:分支错误预测,一些随机管道泡沫......
答案 1 :(得分:2)
在英特尔,Dr. David Levinthal's "Performance Analysis Guide"非常详细地研究了这些问题的答案。