CMP + JE比单个MUL消耗更多的时钟周期吗?

时间:2013-05-29 18:54:33

标签: c performance optimization assembly x86

我正在运行 x86 处理器,但我相信我的问题非常普遍。我很好奇CMP + JE序列与单MUL操作消耗的时钟周期的理论差异。

在C伪代码中:

unsigned foo = 1;    /* must be 0 or 1 */
unsigned num = 0;

/* Method 1: CMP + JE*/
if(foo == 1){
    num = 5;
}

/* Method 2: MUL */
num = foo*5;    /* num = 0 if foo = 0 */

不要过分深入研究伪代码,它纯粹是为了阐明这两种方法背后的数学逻辑。

我实际比较的是以下两个指令序列:

方法1:CMP + JE

    MOV EAX, 1    ; FOO = 1 here, but can be set to 0
    MOV EBX, 0    ; NUM = 0

    CMP EAX, 1    ; if(foo == 1)
    JE  SUCCESS   ; enter branch
    JMP FINISH    ; end program

SUCCESS:
    MOV EBX, 5    ; num = 5

FINISH:

方法2:MUL

    MOV EAX, 1    ; FOO = 1 here, but can be set to 0

    MOV ECX, EAX  ; save copy of FOO to ECX
    MUL ECX, 5    ; result = foo*5
    MOV EBX, ECX  ; num = result = foo*5

似乎单个MUL(总共4个指令)比CMP + JE(总共6个指令)效率更高,但是指令消耗的时钟周期同样 - - 即完成与任何其他指令相同的指令所需的时钟周期数是多少?

如果消耗的实际时钟周期取决于机器,单个MUL通常比大多数处理器上的分支方法更快,因为它需要更少的总指令?

2 个答案:

答案 0 :(得分:10)

现代CPU性能远远超过计算每条指令的周期数更复杂。您需要考虑以下所有因素(至少):

  • 分支预测
  • 指令重新排序
  • 注册重命名
  • 指令缓存命中/未命中
  • 数据缓存命中/未命中
  • TLB未命中/页面错误

所有这些都会受到周围代码的严重影响。

基本上,几乎不可能像这样执行微基准并获得有用的结果!

然而,如果我不得不猜测,我会说没有JE的代码通常会更有效,因为它消除了分支,这简化了分支预测行为。

答案 1 :(得分:1)

通常,在现代x86处理器上,CMPMUL指令将占用整数执行单元一个周期(CMP基本上是SUB抛弃结果,只修改标志寄存器)。然而,现代x86处理器也是流水线,超标量和无序的,这意味着性能不仅仅取决于这个底层周期成本。

如果无法很好地预测分支,那么分支误预测惩罚将淹没其他因素,MUL版本将表现得更好。

另一方面,如果分支可以预测,您可以在后续计算中立即使用num,那么分支版本就可以了在一般情况下表现更好。那是因为当它正确地预测分支时,它可以在比较结果可用之前使用预测值num开始推测性地执行下一条指令(而在MUL情况下,后续使用num将对MUL的结果具有数据依赖性 - 在该结果退役之前,它将无法执行。