64 位跳跃的成本,第一次总是 10-22 个周期?
Cost of a 64bits jump, always 10-22 cycles the first time?
在x86_64中没有64位地址的直接跳转。只有一个 32 位的。
对于间接跳转,我知道在分支预测发挥作用之前必须解决一次管道。
我的问题是:在 64 位中是否没有办法在第一次执行时进行 1-3 个周期的跳跃?
即使没有 I-cache 未命中,直接跳转并不总是“第一次”那么便宜。他们仍然需要分支预测。
在长模式下,jcc rel32
和 jmp rel32
(以及 rel8 压缩版本)使用 RIP 的符号扩展相对位移。您可以跳转到任何 64 位地址,只要您来自 2GB 以内的地址。因此,请将您的代码与其他代码保持在 2GB 以内,以便您可以使用 rel32 位移。
长模式下没有绝对直接跳转。 32 位模式的 far JMP ptr16:32
(opcode 0xEA) 和 far CALL ptr16:32 根本没有 64 位版本。 (并且为了性能和方便,您无论如何都不想要 far jmp。)像 SYSCALL 和 INT 这样的指令是间接跳转(带有隐式目标),无论如何都没有用。
也没有 instruction-prefetch/predecode 指令使目标在 L1 I 高速缓存或 uop 高速缓存中变热,或者以任何方式提示流水线即将需要来自给定地址的解码指令。
参见 PREDECODE wishlist section in Darek Mihocka's article 关于模拟器中的间接跳转,其中让一个访客指令的处理程序直接跳转到下一个访客指令的处理程序很有用,而不是让一个间接调用调度指令几乎总是会预测错误。 (或者至少当 Mihocka 写下它 是 有用的,在 IT-TAGE 分支预测器或多或少地解决了这个问题之前(在 Intel Haswell 和后来的 AMD Zen 或 Zen2 中):分支预测和解释器的性能 -
不要相信民间传说 2015 年 Rohou、Swamy 和 Seznec。)
直接跳转
即使直接跳转也需要分支目标缓冲区来预测下一个提取块应该来自其他地方。比解码阶段更早需要此信息,因此必须对其进行预测以避免明显的前端气泡。最近提出了一个有趣的问题:. The replies on the Realworldtech forum thread 明确分支预测需要在获取块上工作,而不仅仅是指令,甚至在易于解码的固定宽度 ISA 上(与 x86 不同) ), 您需要在解码结果可用之前进行预测。
1-3 个周期对于新看到的直接 (rel32) 跳转的代码获取气泡的大小是不现实的。不过,该气泡的一部分可能会被解码的 uop 队列隐藏。
从取码到解码可能至少需要 5 或 6 个周期,甚至更多。假设 L1-I 命中时间为 4 个周期,与 Haswell 的 L1D 加载使用延迟相同。然后 Intel CPU 的预解码标记指令边界,然后解码阶段最多解码 4 微指令。 David Kanter's Haswell writeup has a diagram of the frontend.
来自 问题的 OP 数据表明 在 Intel Broadwell(有分支target=next insn),所以这是最坏的情况,其中 fetch/decode 气泡根本无法隐藏,因为您没有做任何其他事情让前端有时间赶上。
我假设我们正在谈论来自旧版解码器的 运行。 BTB miss while 运行 from the uop cache 可能会稍微短一些,因为解码的 uop 可用得更快。如果分支 target 也在 uop 缓存中命中,那么解码后的 uops 可以开始进入解码后的 uop 队列(用作循环缓冲区的同一缓冲区)之前的周期也更少。
如果解码的uop队列在代码获取气泡期间没有清空,那么在问题阶段可能没有任何气泡(将uops发送到[=91=的乱序部分) ]).
或者如果 OOO 部分有很多未执行的 uops 需要处理(即 CPU 正在执行一些具有瓶颈的代码,这些瓶颈将 IPC 限制在远小于前端带宽),前端-end bubble 可能不会影响太大。
不过,间接分支更糟糕。最多只能在几个周期后检测到正确的目标, 当 jmp uop 在后端执行 时,以检查预测。从错误预测中恢复涉及从已执行的错误路径回滚任何独立工作,这与在任何错误路径 instructions/uops 甚至发布之前重新引导前端不同。
您的基本前提是正确的:间接分支并不便宜,应尽可能避免。 (尽管一个间接分支可能比一小段条件分支成本更低,例如 。)
相关:
- Why did Intel change the static branch prediction mechanism over these years?
- Branch target prediction in conjunction with branch prediction?
- How has CPU architecture evolution affected virtual function call performance?
在x86_64中没有64位地址的直接跳转。只有一个 32 位的。 对于间接跳转,我知道在分支预测发挥作用之前必须解决一次管道。 我的问题是:在 64 位中是否没有办法在第一次执行时进行 1-3 个周期的跳跃?
即使没有 I-cache 未命中,直接跳转并不总是“第一次”那么便宜。他们仍然需要分支预测。
在长模式下,jcc rel32
和 jmp rel32
(以及 rel8 压缩版本)使用 RIP 的符号扩展相对位移。您可以跳转到任何 64 位地址,只要您来自 2GB 以内的地址。因此,请将您的代码与其他代码保持在 2GB 以内,以便您可以使用 rel32 位移。
长模式下没有绝对直接跳转。 32 位模式的 far JMP ptr16:32
(opcode 0xEA) 和 far CALL ptr16:32 根本没有 64 位版本。 (并且为了性能和方便,您无论如何都不想要 far jmp。)像 SYSCALL 和 INT 这样的指令是间接跳转(带有隐式目标),无论如何都没有用。
也没有 instruction-prefetch/predecode 指令使目标在 L1 I 高速缓存或 uop 高速缓存中变热,或者以任何方式提示流水线即将需要来自给定地址的解码指令。
参见 PREDECODE wishlist section in Darek Mihocka's article 关于模拟器中的间接跳转,其中让一个访客指令的处理程序直接跳转到下一个访客指令的处理程序很有用,而不是让一个间接调用调度指令几乎总是会预测错误。 (或者至少当 Mihocka 写下它 是 有用的,在 IT-TAGE 分支预测器或多或少地解决了这个问题之前(在 Intel Haswell 和后来的 AMD Zen 或 Zen2 中):分支预测和解释器的性能 - 不要相信民间传说 2015 年 Rohou、Swamy 和 Seznec。)
直接跳转
即使直接跳转也需要分支目标缓冲区来预测下一个提取块应该来自其他地方。比解码阶段更早需要此信息,因此必须对其进行预测以避免明显的前端气泡。最近提出了一个有趣的问题:
1-3 个周期对于新看到的直接 (rel32) 跳转的代码获取气泡的大小是不现实的。不过,该气泡的一部分可能会被解码的 uop 队列隐藏。
从取码到解码可能至少需要 5 或 6 个周期,甚至更多。假设 L1-I 命中时间为 4 个周期,与 Haswell 的 L1D 加载使用延迟相同。然后 Intel CPU 的预解码标记指令边界,然后解码阶段最多解码 4 微指令。 David Kanter's Haswell writeup has a diagram of the frontend.
来自
我假设我们正在谈论来自旧版解码器的 运行。 BTB miss while 运行 from the uop cache 可能会稍微短一些,因为解码的 uop 可用得更快。如果分支 target 也在 uop 缓存中命中,那么解码后的 uops 可以开始进入解码后的 uop 队列(用作循环缓冲区的同一缓冲区)之前的周期也更少。
如果解码的uop队列在代码获取气泡期间没有清空,那么在问题阶段可能没有任何气泡(将uops发送到[=91=的乱序部分) ]).
或者如果 OOO 部分有很多未执行的 uops 需要处理(即 CPU 正在执行一些具有瓶颈的代码,这些瓶颈将 IPC 限制在远小于前端带宽),前端-end bubble 可能不会影响太大。
不过,间接分支更糟糕。最多只能在几个周期后检测到正确的目标, 当 jmp uop 在后端执行 时,以检查预测。从错误预测中恢复涉及从已执行的错误路径回滚任何独立工作,这与在任何错误路径 instructions/uops 甚至发布之前重新引导前端不同。
您的基本前提是正确的:间接分支并不便宜,应尽可能避免。 (尽管一个间接分支可能比一小段条件分支成本更低,例如
相关:
- Why did Intel change the static branch prediction mechanism over these years?
- Branch target prediction in conjunction with branch prediction?
- How has CPU architecture evolution affected virtual function call performance?