【问题标题】:x86-64 Relative jmp performancex86-64 相对 jmp 性能
【发布时间】:2016-08-17 14:19:53
【问题描述】:

我目前正在做一个测量各种 x86-64 命令(at&t 语法)性能的作业。

我有点困惑的命令是“无条件 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 个周期) - 但根据我对流水线的理解,无条件跳转应该非常快(没有分支预测错误)。

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

【问题讨论】:

  • Slow jmp-instruction 的可能重复项。那个更详细的问题有一个更好、更详细的答案。

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


【解决方案1】:

CPU 没有针对无操作 jmp 指令进行优化,因此它不处理继续解码和流水线 jmp 指令的特殊情况,这些指令只是跳转到下一个 insn。

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


跳转会在指令获取中产生气泡。一次良好预测的跳跃是可以的,但是除了跳跃什么都不跑是有问题的。我在 core2 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-cache 未命中,它只是不断跳转导致的指令获取/解码前端瓶颈。

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

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

【讨论】:

    猜你喜欢
    • 2019-07-10
    • 2019-01-20
    • 2023-03-22
    • 2014-06-22
    • 2011-02-18
    • 1970-01-01
    • 2014-03-06
    • 2011-08-24
    • 2012-05-06
    相关资源
    最近更新 更多