投机性执行是否会进入昂贵的操作?

时间:2016-03-08 00:46:57

标签: c++ x86 branch-prediction speculative-execution

如果我理解正确分支(x86),处理器有时会推测性地采用代码路径并执行指令并取消'错误路径的结果。如果错误的代码路径中的操作非常昂贵,例如导致高速缓存未命中的内存读取或某些昂贵的数学运算,该怎么办?处理器是否会提前尝试执行昂贵的操作?处理器通常如何处理这个问题?

<div>

<h2>Hello World</h2>

    <button onclick="window.location.href= '#/userForm' ">Next Page</button>

</div>

1 个答案:

答案 0 :(得分:7)

tl:dr :影响并不像您想象的那么糟糕,因为CPU不再需要等待缓慢的事情,即使它没有取消它们。几乎所有东西都是大量流水线,因此许多操作可以同时在飞行中。错误推测的操作不会阻止新的操作开始。

当前的x86设计一次推测分支的两侧。他们只推测预测的路径。

我不知道任何特定的微体系结构在任何情况下都会沿着分支的两种方式进行推测,但这并不意味着没有。我大多只阅读微体系结构(请参阅标签维基以获取Agner Fog微代码的链接)。我确信它已在学术论文中被提出,甚至可能在某个地方的真实设计中实现。

我不确定在当前的英特尔和AMD设计中,当缓存未命中加载或存储已经执行挂起或者除数占用除法单元时检测到分支错误预测时会发生什么。当然,无序执行不必等待结果,因为没有未来的uop依赖它。

在P4以外的搜索中,当检测到错误预测时,丢弃ROB /调度程序中的虚假uops。来自Agner Fog的微博文档,谈论P4与其他搜索:

  由于两个原因,错误预测惩罚异常高...... [长管道和]   ...错误预测的分支中的虚假μops不是   在他们退休前丢弃。错误预测通常涉及45   μops。如果这些μops是划分或其他耗时的操作   那么错误的预测可能会非常昂贵。其他微处理器   一旦检测到错误预测,就可以丢弃μops   不要不必要地使用执行资源。

目前占据执行单位的uops是另一个故事:

除了分频器之外,几乎所有执行单元都是完全流水线的,因此可以在不取消飞行中的FP FMA的情况下启动另一个乘法,随机播放或其他任何操作。 (Haswell:5个周期延迟,两个执行单元,每个时钟吞吐量一个,每0.5c一个总持续吞吐量。这意味着最大吞吐量需要一次保持10个FMA,通常有10个向量累加器)。但是分歧很有趣。整数除法是很多uops,因此分支错误预测至少会停止发布它们。 FP div只是一个uop指令,但不是完全流水线的,尤其是。在较旧的CPU中。取消绑定除法单元的FP div是有用的,但如果可能则取消IDK。如果添加取消的能力会减慢正常情况,或者耗费更多的电力,那么它可能会被遗漏。这是一个罕见的特殊情况,可能不值得花费晶体管。

x87 fsin或其他东西是一个非常昂贵的指令的好例子。我没有注意到,直到我重新阅读这个问题。它是微编码的,所以即使它具有47-106个周期的延迟(Intel Haswell),它也是71-100微秒。分支错误预测会阻止前端发出剩余的uops,并取消所有排队的,就像我说的整数除法一样。请注意,真正的libm实现通常不使用fsin等等,因为它们比软件(即使没有SSE),IIRC更慢,更准确。

对于缓存未命中,它可能会被取消,可能会节省L3缓存(可能还有主内存)的带宽。即使没有,指令也不再需要退出,所以ROB不会等待它完成。这通常是为什么缓存未命中会对OOO执行产生如此大的影响,但在最糟糕的情况下,这只会占用一个加载或存储缓冲区。现代CPU可以同时在飞行中有许多未完成的缓存未命中。通常代码不会使这成为可能,因为将来的操作依赖于缓存中遗漏的负载的结果(例如,链接列表或树中的指针追逐),因此多个存储器操作不能被流水线化。即使分支错误预测不能取消大量的飞行内存操作,它也可以避免大部分最糟糕的影响。

我听说过在代码块的末尾放置ud2(非法指令),以阻止指令预取在块位于页面末尾时触发TLB未命中。我不确定这种技术何时是必要的。也许如果有一个总是实际采取的条件分支?这没有意义,你只需要使用无条件分支。当你这样做时,一定有一些我不记得的东西。