x86 – 为什么英特尔多年来改变了静态分支预测机制?

here开始,我知道英特尔近年来实施了几种静态分支预测机制:

> 80486年龄:永远不被采取
>Pentium4年龄:未采取后退/前锋
>像Ivy Bridge,Haswell这样的新型CPU变得越来越无形,见Matt G’s experiment here.

英特尔似乎不想再谈论它,因为我在英特尔文档中找到的最新资料大约是十年前写的.

我知道静态分支预测(远远不是)比动态更重要,但在很多情况下,CPU将完全丢失,程序员(使用编译器)通常是最好的指南.当然,这些情况通常不是性能瓶颈,因为一旦频繁执行分支,动态预测器就会捕获它.

由于英特尔不再在其文档中明确声明动态预测机制,因此GCC的builtin_expect()只能从热路径中删除不太可能的分支.

我不熟悉CPU设计,我不知道英特尔现在使用什么样的静态预测器机制,但我仍然觉得英特尔最好的机制应该是在动态预测器失败的时候清楚地记录他的CPU计划. ,向前或向后’,因为通常程序员是当时最好的指南.

更新:我发现你提到的主题逐渐超出我的知识范围.这里涉及一些动态预测机制和CPU内部细节,我在两三天内无法学习.所以请允许我暂时退出你的讨论并充电.这里仍然欢迎任何答案,也许会帮助更多人

最佳答案
静态预测在现代设计中不受青睐,甚至可能不存在的主要原因是,与动态预测相比,静态预测在管道中发生得太晚.基本问题是分支方向和目标位置必须在获取之前才知道,但静态预测只能在解码后(在获取之后)进行.

更详细……

CPU流水线

简而言之,在执行期间需要从内存中获取指令,解码这些指令然后执行它们1.在高性能CPU上,这些阶段将是流水线的,这意味着它们通常会并行发生 – 但是在任何给定时刻都会有不同的指令.你可以读一下这个on Wikipedia,但请记住,现代CPU更复杂,通常有更多的阶段.

在具有复杂解码可变长度指令集的现代x86上,可能有许多流水线“阶段”仅涉及获取和解码指令,可能是六个或更多.这些指令也是superscalar,能够一次执行多个指令.这意味着当以峰值效率执行时,将有许多指令在飞行中,在被提取,解码,执行等的各个阶段中.

重定向提取

在管道的整个初始部分(通常称为前端)上感受到采用分支的效果:当您跳转到新地址时,您需要从该新地址获取,从该新地址解码,等等.我们说采取的分支需要重定向获取.这对分支预测可以使用的信息施加了某些限制以便有效地执行.

考虑静态预测是如何工作的:它查看指令,如果它是分支,则比较其目标以查看它是“向前”还是“向后”.所有这一切必须在解码发生后很大程度上发生,因为那时实际的指令是已知的.然而,如果检测到分支并且被预测(例如,向后跳跃),则预测器需要重定向提取,这是更早的许多流水线阶段.在解码指令N之后重新定向提取时,已经有许多后续指令在错误(未采用)路径上被提取和解码.那些必须被扔掉.我们说在前端引入了泡沫.

所有这一切的结果是,即使静态预测100%正确,在采用的分支情况下效率非常低,因为前端流水线操作失败了.如果在提取和解码结束之间有6个流水线级,则每个采用的分支在流水线中引起循环6气泡,并且慷慨地假设预测本身和刷新坏路径指令采用“零周期”.

救援的动态预测

但是,现代x86 CPU能够在每个周期执行最多1个分支,即使是完美预测的静态执行,也必须优于极限.为实现此目的,预测器通常不能使用解码后可用的信息.它必须能够在每个周期重定向获取,并且仅使用在最后一次预测之后具有一个周期的延迟的可用输入.从本质上讲,这意味着预测器基本上是一个自包含的过程,它只使用自己的输出作为下一周期预测的输入.

这是大多数CPU的动态预测器.它预测从下一个周期获取的位置,然后根据该预测,它预测在此之后从周期中获取的位置,依此类推.它不使用有关已解码指令的任何信息,而仅使用分支的过去行为.它最终从执行单元获得关于分支的实际方向的反馈,并基于此更新其预测,但这一切基本上异步地发生,在相关指令通过预测器之后的许多循环.

添加它

所有这些都有助于削弱静态预测的有用性.

首先,预测来得太晚了,所以即使完美地工作,它也意味着现代英特尔采用分支机构的6-8个周期的泡沫(事实上,这些是英特尔所谓的“前端转发器”的观察数据).这极大地改变了进行预测的成本/收益等式.如果你在获取预测之前有一个动态预测器,你或多或少想要做一些预测,如果它具有甚至51%的准确度,它可能会得到回报.

但是,对于静态预测,如果您想要进行“采取”预测,则需要具有高精度.例如,考虑一个8周期前端重定时器成本,而不是16周期“完全错误预测”成本.让我们说在某些程序中,冷向后分支的采集频率是未采取的两倍.这应该是静态分支预测的胜利,它预测向后采取,正确(与默认策略总是“预测”2未采取)?

没那么快!如果你假设8个周期的重新转向成本和16个周期的完全错误预测成本,他们最终会得到10.67个周期的相同混合成本 – 因为即使在正确预测的情况下,这是一个8周期的泡沫,但在通过案例,无静态预测案例没有相应的成本.

除此之外,无静态预测案例已经使静态预测的另一半正确(前向分支未采取的情况),静态预测的效用并不像人们想象的那么大.

为什么现在改变?也许是因为管道的前端部分与其他部分相比延长了,或者因为动态预测器的性能和内存的增加意味着更少的冷分支完全符合静态预测的条件.提高静态预测变量的性能还意味着向后采取的预测对于冷分支变得不那么强,因为循环(这是向后采用规则的原因)被动态预测器更频繁地记住.

保存动态预测资源

这种变化也可能是因为与动态预测的相互作用:动态预测器的一种设计是根本不使用任何分支预测资源用于从未观察到的分支.由于这种分支很常见,这可以节省大量的历史表和BTB空间.但是,这样的方案与预测向后分支的静态预测器不一致:如果从未采用向后分支,则不希望静态预测器选择此分支,并将其预测为已采用,从而弄乱了您的策略为未采取的分支节省资源.

1 …然后再做更多的事情,比如退休,他们 – 但执行后发生的事情对我们的目的来说并不重要.

2我把“预测”放在这里的恐慌引用中,因为在某种程度上它甚至没有预测:在没有相反的预测的情况下,未采取是默认的提取和解码行为,所以如果你不这样做就是你得到的t根本没有任何静态预测,你的动态预测器也不会告诉你.

转载注明原文:x86 – 为什么英特尔多年来改变了静态分支预测机制? - 代码日志