简短概述: 影响并不像你想的那么糟糕,因为CPU不再需要等待缓慢的操作,即使它们没有被取消。几乎所有的操作都被密集地分段处理,因此许多操作可以同时进行。错误预测的操作并不会阻止新的操作开始。
当前的x86设计不会同时对分支的两侧进行猜测。它们只会沿着预测的路径进行猜测。
我不知道是否有任何特定的微架构在任何情况下都可以同时猜测分支的两个方向,但这并不意味着没有。我主要只了解x86微架构(请参阅标签wiki以获取链接到Agner Fog的微架构指南)。我相信这已经在学术论文中被提出,并且可能在某个实际设计中得到了实现。
我不确定在当前的Intel和AMD设计中,当检测到分支预测错误时,缓存未命中的加载或存储已经执行挂起,或者除法占用了除法单元会发生什么。当然,乱序执行不必等待结果,因为没有未来的uop依赖于它。
在P4以外的微架构中,当检测到分支预测错误时,ROB /调度器中的虚假uops将被丢弃。从Agner Fog的微架构文档中可以看出,他谈到了P4与其他微架构之间的区别:
“误判惩罚异常高,有两个原因...[长流水线和]...在未正确预测分支之前,虚假μops不会被丢弃。一个误判通常涉及45个μops。如果这些μops是除法或其他耗时操作,则误判可能非常昂贵。其他微处理器可以在检测到误判后立即丢弃μops,以便它们不会不必要地使用执行资源。”
目前占用执行单元的uops则另当别论:
几乎所有执行单元(除了除法器)都是完全流水线化的,因此另一个乘法、洗牌或其他操作可以在不取消正在进行的FP FMA的情况下启动。 (Haswell:5个时钟周期的延迟,每个具有每个时钟周期吞吐量的两个执行单元,总持续吞吐量为每0.5c一个。这意味着最大吞吐量需要同时保持10个FMAs,并通常带有10个矢量累加器)。 但是除法很有趣。 整数除法是许多uop,因此分支错误预测至少会停止发出它们。 FP除法仅是单个uop指令,但不完全流水线化,尤其是在较旧的CPU中。 取消绑定除法单元的FP div会很有用,但我不知道是否可能。 如果添加取消功能会使正常情况变慢或成本更高,则可能会被省略。 这是一个罕见的特殊情况,可能不值得花费晶体管。
x87中的fsin
指令是一个非常昂贵的例子。直到我重新阅读这个问题,我才注意到这一点。它是微编码的,因此即使它具有47-106个周期的延迟(Intel Haswell),它也有71-100个uop。分支预测失败会导致前端无法发布其余的uop,并取消排队的所有uop,就像整数除法一样。请注意,真正的libm
实现通常不使用fsin
等指令,因为它们比软件实现(即使没有SSE)更慢、不够准确。
对于缓存未命中,它可能会被取消,从而在L3缓存(或者主内存)上节省带宽。即使没有取消,指令也不再需要退役,因此ROB不会因等待其完成而填满。这通常是为什么缓存未命中会对OOO执行造成如此大的影响,但在这里,最坏的情况只是占用了一个负载或存储缓冲区。现代CPU可以同时有多个未完成的缓存未命中操作。通常,代码无法实现这一点,因为未来的操作依赖于在缓存中未命中的加载的结果(例如,在链接列表或树中跟踪指针),因此无法将多个内存操作进行流水线处理。即使分支预测错误没有取消大量正在进行的内存操作,也可以避免大部分最坏的影响。
我听说在代码块的末尾放置一个
ud2
(非法指令),以防止指令预取触发TLB未命中,当该块位于页面末尾时。 我不确定何时需要使用此技术。也许如果有条件分支始终实际被采用?这没有意义,你应该只使用无条件分支。可能有一些我忘记了的事情。