x86-64相对jmp性能

时间:2016-04-24 04:59:13

标签: performance assembly x86 x86-64 micro-optimization

我目前正在执行一项测量各种x86-64命令性能的任务(以及语法)。

我有点困惑的命令是“无条件的jmp”命令。这就是我实现它的方式:

    .global uncond
uncond:

.rept 10000
jmp . + 2
.endr


mov $10000, %rax
ret

这很简单。代码创建一个名为“uncond”的函数,该函数使用.rept指令调用jmp命令10000次,然后将返回值设置为调用jmp命令的次数。

“”。在at& t语法中表示当前地址,我将其增加2个字节以便考虑jmp指令本身(因此jmp。+ 2应该只是移动到下一条指令)。

我未显示的代码计算处理10000命令所需的周期数。

我的结果表明jmp非常慢(处理单个jmp指令需要10个周期) - 但根据我对流水线的理解,无条件跳转应该非常快(没有分支预测错误)。

我错过了什么吗?我的代码错了吗?

1 个答案:

答案 0 :(得分:1)

CPU未针对无操作jmp指令进行优化,因此它无法处理继续解码和管道jmp指令的特殊情况,只是跳转到下一个的insn。

但是,针对循环优化了CPU。 jmp .将在许多CPU上每个时钟运行一个insn,或者在某些CPU上每2个时钟运行一个。

跳转会在指令提取中产生气泡。单个预测良好的跳跃是可以的,但除了跳跃之外什么都不做是有问题的。我在core2 E6600(Merom / Conroe微架)上复制了你的结果:

# jmp-test.S
.globl _start
_start:

    mov $100000, %ecx
jmp_test:
    .rept 10000
    jmp . + 2
    .endr

    dec %ecx
    jg jmp_test


    mov $231, %eax
    xor %ebx,%ebx
    syscall          #  exit_group(0)

构建并运行:

gcc -static -nostartfiles jmp-test.S
perf stat -e task-clock,cycles,instructions,branches,branch-misses ./a.out

 Performance counter stats for './a.out':

       3318.616490      task-clock (msec)         #    0.997 CPUs utilized          
     7,940,389,811      cycles                    #    2.393 GHz                      (49.94%)
     1,012,387,163      instructions              #    0.13  insns per cycle          (74.95%)
     1,001,156,075      branches                  #  301.679 M/sec                    (75.06%)
           151,609      branch-misses             #    0.02% of all branches          (75.08%)

       3.329916991 seconds time elapsed

从另一场比赛开始:

 7,886,461,952      L1-icache-loads           # 2377.687 M/sec                    (74.95%)
     7,715,854      L1-icache-load-misses     #    2.326 M/sec                    (50.08%)
 1,012,038,376      iTLB-loads                #  305.119 M/sec                    (75.06%)
           240      iTLB-load-misses          #    0.00% of all iTLB cache hits   (75.02%)

(每行末尾的(%)中的数字是计数器处于活动状态的总运行时间的多少:perf当你要求它计算的数量超过HW时,它必须为你多路复用可以算一次)。

所以它实际上不是I-cache misses,它只是由持续跳转引起的指令获取/解码前端瓶颈。

我的SnB机坏了,所以我无法在其上测试数字,但是每个jmp持续吞吐量的8个周期非常接近你的结果(可能来自不同的微体系结构)。

有关详细信息,请参阅http://agner.org/optimize/以及代码wiki中的其他链接。