1

我正在运行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 */

不要对伪代码看得太深,它纯粹是为了阐明这两种方法背后的数学逻辑。

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

方法一: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 条指令)比(总共 6 条指令)更有效CMP + JE,但是指令消耗的时钟周期相同- 即完成一条指令所需的时钟周期数与任何其他指令相同?

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

4

2 回答 2

10

现代 CPU 性能比仅仅计算每条指令的周期数要复杂得多您需要考虑以下所有因素(至少):

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

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

所以本质上,几乎不可能进行这样的微基准测试并获得有用的结果!

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

于 2013-05-29T18:56:04.863 回答
1

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

如果不能很好地预测分支,那么分支错误预测惩罚将淹没其他因素,并且MUL版本的性能会明显更好。

另一方面,如果可以很好地预测分支并且您立即num在后续计算中使用,那么分支版本可能在平均情况下表现更好。num这是因为当它正确预测分支时,它可以在比较结果可用之前使用 的预测值开始推测性地执行下一条指令(而在这种MUL情况下,后续使用的num结果将依赖于MUL- 在该结果退出之前它将无法执行)。

于 2013-05-30T00:20:07.963 回答