【发布时间】:2023-03-31 09:16:01
【问题描述】:
Intel recommends 使用指令前缀来减轻 JCC Erratum 的性能影响。
如果使用/QIntel-jcc-erratum 编译,MSVC 会遵循建议,并插入前缀指令,如下所示:
3E 3E 3E 3E 3E 3E 3E 3E 3E 48 8B C8 mov rcx,rax ; with redundant 3E prefixes
They say MSVC 在前缀不可用时诉诸 NOP。
Clang 对此有 -mbranches-within-32B-boundaries 选项,它更喜欢 nop,如果需要,可以使用多字节(https://godbolt.org/z/399nc5Msq 通知 xchg ax, ax)
3E前缀的后果是什么,具体来说:
- 为什么英特尔推荐这个,而不是多字节 NOP?
- 不受影响的 CPU 会有什么后果?
- 据报道,一个程序在 AMD 上使用
/QIntel-jcc-erratum运行得更快,有什么可能的解释?
【问题讨论】:
-
NOP 是一条单独的指令,必须单独解码并通过管道。 What methods can be used to efficiently extend instruction length on modern x86?。您应该始终使用前缀填充指令以实现所需的对齐,而不是插入 NOP。可能英特尔认为值得付出努力,因为这实际上是 inside 内部循环,而不仅仅是内部循环之外的 NOP。
-
但请注意,某些 CPU 不能有效地解码一条指令上超过 3 个前缀,因此这可能就是为什么 this 缓解 JCC 勘误表的策略未启用的原因默认。您希望将填充分布在多个先前的指令上,以避免 Silvermont 系列(例如 Gracemont)的瓶颈(例如,Alder Lake E-cores 突然使该系列与主流相关)。我忘记了 AMD 解码限制。
-
IIRC,GNU 工具链在汇编程序中进行了缓解,所以寻找
as选项(你可以让GCC 与-Wa,-...一起使用)GCC 不知道指令大小,它只知道打印文本。这就是为什么它需要 GAS 支持像.p2align 4,,10这样的东西来对齐 16,如果这将需要少于 10 个字节的填充,以实现它想要使用的对齐启发式。 (通常后跟.p2align 3以无条件对齐 8。) -
发现博客文章提到尺寸影响为 3%,性能影响为可忽略:devblogs.microsoft.com/cppblog/jcc-erratum-mitigation-in-msvc
-
那个博客说在受影响的 CPU 上(我认为只有 Intel Skylake 系列),使用编译器选项使得性能与没有微码更新之前大致相同编译器选项。它没有说明它对其他 CPU 的影响,例如 Silvermont/Goldmont。 (我查看了 Agner Fog 的微架构指南,AMD Zen 对单个指令上的任意数量的前缀都没有问题,就像 Core2 以来的主流 Intel 一样。AMD Bulldozer 系列对解码超过 3 个前缀的指令有“非常大”的惩罚,比如 4-7 个前缀的 14-15 个周期。)
标签: assembly x86 intel cpu-architecture micro-optimization