gpt4 book ai didi

performance - 现代 CPU 中的小分支

转载 作者:行者123 更新时间:2023-12-04 12:02:56 25 4
gpt4 key购买 nike

像 Kaby Lake 这样的现代 CPU 如何处理小分支? (在下面的代码中,它是跳转到标签 LBB1_67)。据我所知,分支不会有害,因为跳转低于 16 字节块大小,即解码窗口的大小。

或者是否有可能由于一些宏操作融合,分支将被完全省略?

        sbb     rdx, qword ptr [rbx - 8]
setb r8b
setl r9b
mov rdi, qword ptr [rbx]
mov rsi, qword ptr [rbx + 8]
vmovdqu xmm0, xmmword ptr [rbx + 16]
cmp cl, 18
je .LBB1_67
mov r9d, r8d
.LBB1_67: # in Loop: Header=BB1_63 Depth=1
vpcmpeqb xmm0, xmm0, xmmword ptr [rbx - 16]
vpmovmskb ecx, xmm0
cmp ecx, 65535
sete cl
cmp rdi, qword ptr [rbx - 32]
sbb rsi, qword ptr [rbx - 24]
setb dl
and dl, cl
or dl, r9b

最佳答案

在任何 x86 CPU 中都没有短分支距离的特殊情况。偶无条件jmp到下一条指令(架构上是 nop)需要正确的分支预测才能有效地处理;如果您连续放置足够多的 BTB 条目,则性能会下降。 Slow jmp-instruction

获取/解码只是一个小问题 ;是的,同一高速缓存行中的一个非常短的分支仍然会命中 L1i 和 uop 高速缓存。但是解码器不太可能对预测采取的前向跳转进行特殊处理,并利用包含分支和目标的一个块中的预解码指令边界查找。

当指令被解码为 uops 并被送入前端时,寄存器值不可用;这些仅在乱序执行后端可用。

主要问题是当.LBB1_67:之后的指令执行,架构状态根据是否采用分支而不同。
微架构状态(RAT = 寄存器分配表)也是如此。

任何一个:

  • r9取决于 sbb/setl结果(mov r9d, r8d 没有运行)
  • r9取决于 sbb/setb结果( mov r9d, r8d 确实运行了)

  • 条件分支在计算机体系结构术语中称为“控制依赖”。分支预测+推测执行避免将控制依赖转化为数据依赖。如果 je被预测没拿, setl结果( r9 的旧值)被 mov 覆盖并且在任何地方都不再可用。

    je 中检测到错误预测后,无法从中恢复。 (实际上应该已经采取了),尤其是在一般情况下。当前的 x86 CPU 不会尝试寻找重新加入所采用路径的失败路径或弄清楚它所做的任何事情。

    cl好久没准备好,好久没有发现一个误报, or dl, r9b后面的很多指令可能已使用错误的输入执行。在一般情况下,可靠+有效恢复的唯一方法是丢弃对来自“错误”路径的指令所做的所有工作。检测到 vpcmpeqb xmm0, [rbx - 16]例如仍然运行任何一种方式都很难,而不是寻找。 (现代英特尔,自 Sandybridge 以来,有一个分支顺序缓冲区 (BOB),它对分支上的 RAT 进行快照,允许在执行检测到分支未命中时立即有效回滚,同时仍然允许在早期指令上的乱序执行在回滚。在此之前,分支未命中必须回滚到退休状态。)

    某些非 x86 ISA(例如我认为的 PowerPC)的一些 CPU 已经尝试将恰好跳过 1 条指令的前向分支转换为预测(数据依赖),而不是推测它们。例如 Dynamic Hammock Predicationfor Non-predicated Instruction Set Architectures讨论这个想法,甚至决定是否在每个分支的基础上进行谓词。如果您的分支预测历史表明此分支预测不佳,则改为对其进行预测可能会很好。 (Hammock 分支是向前跳过一条或几条指令的分支。在具有固定宽度指令字的 ISA(如 RISC)上检测恰好 1 个指令情况是微不足道的,但在 x86 上则很难。)

    在这种情况下,x86 有一个 cmovcc指令,一种 ALU 选择操作,它根据标志条件产生两个输入之一。 cmove r9d, r8d而不是 cmp/je将使这不受分支错误预测的影响,但代价是引入对 cl 的数据依赖。和 r8d使用说明 r9d . Intel CPU 不会尝试为您执行此操作。

    (在 Broadwell 和后来的 Intel 上,cmov 只有 1 uop,低于 2。cmp/jcc 是 1 uop,而 mov 本身也是 1 uop,所以在未采用的情况下 cmov 对于前端。在被采用的情况下,即使预测正确,被采用的分支也会在管道中引入气泡,这取决于代码的吞吐量有多高:阶段之间的队列是否可以吸收它。)

    gcc optimization flag -O3 makes code slower than -O2对于 CMOV 比分支慢的情况,因为引入数据依赖是不好的。

    关于performance - 现代 CPU 中的小分支,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54963877/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com