为什么需要微操作层压?

Why unlamination of μops necessary?

提问人:Frontier_Setter 提问时间:1/2/2023 最后编辑:Peter CordesFrontier_Setter 更新时间:1/2/2023 访问量:129

问:

在丹尼斯·巴赫瓦洛夫(Denis Bakhvalov)的《英特尔CPU中的微聚变》(MicroFusion in Intel CPUs)一书中,他说:

enter image description here《英特尔® 64 和 IA-32 架构优化参考手册》的“2.3.2.4:微操作队列和环流检测器 (LSD)”一章中介绍了 SandyBridge 的解层:

微操作队列为某些指令类型提供解码后功能。特别是,当与索引寻址一起使用时,与计算操作和所有存储相结合的负载在解码器或解码 ICache 中表示为单个微运算。在微操作队列中,它们通过称为解层压的过程被分成两个微操作,一个执行负载,另一个执行操作

HackerNews 帖子中,BeeOnRope 指出:

当指令在解码时被融合,但在重命名之前被“解层压”时,它通常具有与完全没有融合相似的性能(但它确实节省了 uop 缓存中的空间),因为 RAT 更有可能成为性能限制。

在这种情况下,为什么在解码指令时使用解层而不是使用更多的μops?这似乎没有必要吗?

还是因为在解码阶段不确定给定的μop是否应该解层,需要根据运行时的CPU使用状态动态确定?

x86 cpu intel cpu架构

评论


答:

5赞 Peter Cordes 1/2/2023 #1

微熔 + 解层压在大多数前端中获得了微熔的吞吐量优势,只有在问题/重命名时才会丢失它。如果没有这种好处,更多的代码可能会在管道的早期部分遇到瓶颈,尤其是遗留解码,其中任何多 uop 指令都必须在一个“复杂”解码器中解码,而不是任何“简单”解码器。https://www.realworldtech.com/sandy-bridge/4/


Sandybridge 系列简化了后端无序部分(ROB 和 RS)1 的 uop 格式;对于相同数量的 ROB 条目,更少的晶体管可以节省 CPU 功耗密集型部分的功耗。ROB 必须跟踪两个 uop 是否已完成执行,并且正在处理物理寄存器编号,因为寄存器重命名已经发生在发出/重命名/分配时。

对我来说,在解码器和 uop 缓存中解码为单个 uop 是值得的,然后再解层,而不是一开始就不融合。vaddps ymm0, ymm1, [rdi+rdx*4]

在解码器中,只有一个复数解码器可以产生超过 1 个 uop,因此任何尚未碰巧在其解码组中排在第一位的多 uop 指令都会提前结束该组。使用索引寻址模式的一堆带有内存操作数的指令可能会削弱传统解码的吞吐量,因为每个这样的指令都会自行解码,需要复杂的解码器。

在 uop 缓存中,节省空间是有意义的;每“行”6 个 UOP 不是很大,多个指令的额外 UOP 很容易需要同一个 32 字节块的额外“行”,从而降低缓存密度,从而降低命中率。与 ROB 不同,它只需要作为块的一部分获取,而不是索引即可让完成端口将其标记为“完成”并准备停用。


英特尔确实在 Haswell 中进行了更改,以允许保留更多指令微融合:具有 2 个操作数的指令,具有读+写目标,可以保持索引寻址模式微融合,例如 .但不幸的是,不是。请参阅微融合和寻址模式addps xmm0, [rdi + rdx*4]vaddps xmm0, xmm0, [rdi+rdx*4]

因此,显然他们意识到或决定在 ROB 条目上多花一些钱以减少大量代码中的解层。很多时候,CPU 运行的是标量代码,指令类似于 or(存储在 Intel CPU 上是存储地址 + 存储数据 uops,每个都写入存储缓冲区条目的一部分),而不是 AVX。此外,Haswell uop 格式必须更改以适应具有 3 个输入的单 uop FMA;在此之前,英特尔 uops 最多可以有 2 个输入。(直到 Broadwell 才利用这一点来制作和 single-uop;也许他们希望通过微码禁用 FMA 是一种选择,以防发现错误,所以不想将其硬连接到一些基线 x86 指令的处理方式中,这在需要运行现有二进制文件的 CPU 中是无法禁用的。add rdx, [rsi+rcx]mov [rdi + rcx*4], eaxadccmov


还是因为在解码阶段不确定给定的μop是否应该解层,需要根据运行时的CPU使用状态动态确定?

也许这个想法是关于什么的;在预解码中,指令被引导到适当的解码器。一些操作码总是被引导到复杂的解码器,将它们限制在传统解码的 1/时钟吞吐量,即使该操作码的实例实际上解码为单个 uop。(至少这是我们最好的解释理论:最近英特尔微架构中的简单解码器能否处理所有 1μop 指令?)

如果预解码器必须转向基于索引寻址模式的复杂解码器,他们可能会做一些不幸的事情,例如将任何带有 SIB 的 uop 发送到复杂解码器,包括 .add eax, [rsp+16]

它可能还保留了部分解码器更类似于 Nehalem,无论寻址模式如何,如果可能的话,它总是微融合内存操作数。


脚注 1:我不记得我在哪里读到过关于英特尔在后端简化内部 uop 格式的事实。它不在 https://www.realworldtech.com/sandy-bridge/ 所以可能在 https://agner.org/optimize/(微拱指南)

评论

0赞 BeeOnRope 1/23/2023
我也许不应该说“通常 [4 uop 重命名限制更重要]”——实际上我真的不知道。我想这来自我自己在微视时的经验:通常您可以在 uop 缓存中组织命中,因此解码限制并不重要,通常您可以组织事情,以便 uop 缓存规则不限制带宽(但这要小心)将 4/周期限制保留为不可侵犯的限制。在其他场景中,如编译代码或更轻度优化的东西,其他限制可能更重要。
0赞 Peter Cordes 1/23/2023
@BeeOnRope:是的,对于在循环中花费大量时间的代码,UOP 缓存通过微融合避免了 CPU 上现有的遗留解码瓶颈。但是,不能在 ROB 中保持融合的微熔断 uop 会消耗额外的 uop 缓存空间,并可能导致某些循环的某些 32 字节块不适合 uop 缓存。(许多带有内存操作数的 2 字节或 3 字节指令可能会将每字节的平均 uops 向上推高,并在某些行的末尾留出未使用的空间。当然,除了占用更多的 uop 缓存空间外,还有更多的失误:遗留解码更重要