Lew*_*sey 4 pipeline intel cpu-architecture interrupt-handling branch-prediction
特定向量(未屏蔽)发生硬件中断,CPU 检查 IF 标志并将 RFLAGS、CS 和 RIP 压入堆栈,同时后端仍有指令完成,其中一条指令的分支预测结果是错误的。通常管道会被刷新,前端开始从正确的地址获取,但在这种情况下,中断正在进行中。
我已经读过这篇文章,显然解决方案是立即刷新管道中的所有内容,这样就不会发生这种情况,然后生成指令将 RFLAGS、CS、RIP 推送到 TSS 中内核堆栈的位置;然而,问题出现了,它如何知道与最新架构状态关联的 (CS:)RIP,以便能够将其推送到堆栈上(假设前端 RIP 现在将领先)。这类似于 port0 上的采取分支执行单元如何知道当采取预测结果错误时应该获取的 (CS:)RIP 的问题——是编码到指令中的地址以及预言?当你想到陷阱/异常时,也会出现同样的问题,CPU需要将当前指令(故障)或下一条指令(陷阱)的地址推送到内核堆栈,但是它是如何计算出这条指令的地址的当它处于管道的中途时——这让我相信地址必须被编码到指令中并使用长度信息计算出来,这可能全部在预解码阶段完成。
CPU 可能会丢弃 ROB 的内容,在服务中断之前回滚到最新的退休状态。
飞行中的分支未命中不会改变这一点。根据 CPU(较旧/较简单)的不同,当中断到达时,它可能已经处于回滚到退休状态并由于分支未命中而刷新的过程中。
正如 @Hadi 所说,CPU 可以选择在此时退出分支(中断将 CS:RIP 指向正确的分支目标),而不是让其在从中断返回后重新执行。
但这仅在分支指令已准备好退出时才有效:没有比分支更旧的指令仍未执行。由于尽早发现分支未命中很重要,因此我假设分支恢复在执行期间发现错误预测时开始,而不是等到它退休时才开始。(这与其他类型的故障不同:例如 Meltdown 和L1TF基于故障负载,而不是基于故障负载)触发#PF故障处理,因此 CPU 确定在真实的执行路径上确实存在故障。您不希望启动昂贵的管道刷新,直到您确定它没有受到错误预测或早期故障的影响。)
但由于分支未命中不会出现异常,因此在我们首先确定分支指令是正确路径的一部分之前,可以尽早开始重定向前端。
例如cmp byte [cache_miss_load], 123/je预测错误但很长一段时间不会被发现。然后,在错误预测的阴影下,“错误”路径上的cmp eax, 1/运行,并发现了它的错误预测。je通过快速恢复,可以在发现早期错误预测之前就开始刷新过去的微指令,并从“正确”路径获取/解码/执行。
为了保持较低的 IRQ 延迟,CPU 不会为运行中的指令提供额外的退出时间。此外,任何在存储缓冲区中仍具有数据的退役存储(尚未提交到 L1d)必须先提交,然后中断处理程序才能提交任何存储。但中断是串行化的(我认为),并且处理程序中的任何 MMIO 或端口 IO 都可能涉及内存屏障或强顺序存储,因此如果涉及存储,让更多指令退出可能会损害 IRQ 延迟。(一旦存储退役,即使其数据仍在存储缓冲区中,也肯定需要发生)。
乱序的后端总是知道如何回滚到已知良好的退休状态;ROB 的全部内容始终被认为是推测性的,因为任何加载或存储都可能出错,许多其他指令也可能出错1。 对过去分支的猜测并不是特别特别。
分支的特殊之处在于具有额外的跟踪以实现快速恢复(Nehalem 及更新版本中的分支顺序缓冲区),因为它们在正常操作期间预计会以不可忽略的频率进行错误预测。请参阅当 skylake CPU 错误预测分支时到底会发生什么?了解一些细节。尤其是大卫·坎特的一句话:
Nehalem 增强了分支错误预测的恢复能力,这一点已被延续到 Sandy Bridge 中。一旦发现分支错误预测,一旦知道正确的路径,核心就能够重新开始解码,同时乱序机器从错误推测的路径中清除微指令。以前,直到管道完全刷新后,解码才会恢复。
(这个答案故意非常以 Intel 为中心,因为您将其标记为intel,而不是x86。我认为 AMD 做了类似的事情,并且可能其他 ISA 的大多数无序 uarches 大致相似。除了内存顺序错误推测之外在具有较弱内存模型的 CPU 上,不允许 CPU 明显地重新排序负载。)
脚注 1:如果 FP 异常未屏蔽,则可以div或任何 FPU 指令。非规范 FP 结果可能需要微代码辅助来处理,即使 FP 异常像默认情况下那样被屏蔽。
在 Intel CPU 上,内存顺序错误推测也可能导致管道核武器(在较早的加载完成之前推测性地加载,但在 x86 内存模型表示加载可以获取其值之前,缓存丢失了该行的副本) )。
| 归档时间: |
|
| 查看次数: |
1067 次 |
| 最近记录: |