2016-04-24 100 views
1

我目前正在做一项测量各种x86-64命令(在& t语法)的性能的任务。x86-64相对jmp性能

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

.global uncond 
uncond: 

.rept 10000 
jmp . + 2 
.endr 


mov $10000, %rax 
ret 

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

“。”在& t语法意味着当前地址,我为了说明jmp指令本身而增加2个字节(所以jmp。+ 2应该简单地移到下一条指令)。

我没有显示的代码计算了处理10000条命令所需的周期数。我的结果说jmp非常慢(需要10个周期来处理单个jmp指令) - 但是从我对流水线的了解,无条件跳转应该非常快(没有分支预测错误)。

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

+0

[Slow jmp-instruction]的可能重复(http://stackoverflow.com/questions/38811901/slow-jmp-instruction)。这个更详细的问题有一个更好,更详细的答案。 –

回答

1

的CPU是不是无操作优化jmp说明,所以它不处理继续解码和管道JMP指令只是跳转到下一个insn的特殊情况。但是,CPU针对循环进行了优化。 jmp .将在许多CPU上以每个时钟一个insn运行,或者在某些CPU上每2个时钟运行一个insn。


跳转在指令读取中创建一个气泡。一个预测良好的跳跃是可以的,但没有任何运转,但跳跃是有问题的。我复制你在酷睿2 E6600的结果(Merom处理器/ Conroe的microarch):

# 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当您要求它计算比硬件可以一次计数更多的事情时,必须为您复用)。因此它实际上并不是I缓存未命中,它只是由不断跳转引起的取指/解码前端瓶颈。

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

有关更多详细信息,请参阅http://agner.org/optimize/以及标记wiki的其他链接。