当前位置: 首页 > 知识库问答 >
问题:

英特尔这些年为什么要改变静态分支预测机制?

鲜于温书
2023-03-14

从这里我知道Intel这些年实现了几种静态分支预测机制:

>

  • 80486年龄:始终未取

    Pentium4年龄:向后取/向前不取

    由于Intel不再在其文档中明确陈述动态预测机制,所以GCC的builtin_expect()只能做的就是从hot Path中移除不太可能的分支。

    我不熟悉CPU的设计,也不知道Intel现在的静态预测器到底用了什么机制,但我还是觉得Intel最好的机制应该是清楚地记录他的CPU“动态预测器失败时我打算去哪里,前进还是后退”,因为通常程序员是当时最好的指导者。

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

  • 共有1个答案

    苏高峰
    2023-03-14

    静态预测在现代设计中不受欢迎的主要原因是,与动态预测相比,静态预测在流水线中出现得太晚了。基本问题是,在获取分支方向和目标位置之前必须知道它们,但静态预测只能在decode(在获取之后)之后进行。

    更详细的...

    简而言之,在执行过程中需要从内存中提取指令,解码这些指令,然后执行它们1。在高性能CPU上,这些阶段将被流水线化,这意味着它们通常都是并行发生的--但在任何给定时刻都是针对不同的指令。您可以在维基百科上读到一些关于这方面的内容,但请记住,现代CPU更复杂,通常有更多的阶段。

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

    所有这一切的结果是,即使静态预测是100%正确的,但由于前端流水线失败,因此在Take branch的情况下,它的效率非常低。如果在提取和解码结束之间有6个流水线级,则每个被提取的分支都会在流水线中产生6个周期的气泡,并假定预测本身和冲洗坏路径指令都是“零周期”。

    然而,现代x86 CPU能够在每个周期最多执行1个分支,即使是完美预测的静态执行,也比极限要好得多。为了实现这一点,预测器通常不能使用解码后可用的信息。它必须能够重定向每一个周期的提取,并且只使用在最后一次预测之后延迟一个周期的可用输入。从本质上说,这意味着predictor基本上是一个独立的进程,它只使用自己的输出作为下一个周期预测的输入。

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

    所有这些都削弱了静态预测的有用性。

    首先,这一预测来得太晚了,因此即使在运行完美的情况下,它也暗示着现代英特尔的分支会出现6-8个周期的泡沫(事实上,这些是从英特尔所谓的“前端重定向”中观察到的数据)。这极大地改变了进行预测的成本/收益等式。当你有一个动态预测器在进行预测之前,你或多或少地想要做一些预测,如果它甚至有51%的准确率,它可能会得到回报。

    然而,对于静态预测,如果您想要进行“已采取的”预测,则需要具有高精度。例如,考虑8个周期的前端重定向成本,而16个周期的“完全错误预测”成本。假设在某些程序中,采取冷的反向分支的频率是不采取的频率的两倍。这对于向后预测的静态分支预测应该是一个胜利,对吧(与总是“预测”2不采取的默认策略相比)?

    别这么快!如果假设8个周期的重新转向成本和16个周期的完全错误预测成本,它们最终具有10.67个周期的相同混合成本--因为即使在正确预测的情况下,也是8个周期的泡沫,但在跌落情况下,没有静态预测的情况下没有相应的成本。

    再加上没有静态预测的情况已经使静态预测的另一半正确(前向分支不采取的情况),静态预测的效用并没有想象的那么大。

    为什么现在变了?也许是因为流水线的前端部分与其他部分相比变长了,或者是因为动态预测器的性能和内存的增加意味着更少的冷支路可以用于静态预测。静态预测器性能的提高还意味着反向预测对于冷分支变得不那么强,因为动态预测器更频繁地记住循环(这是反向规则的原因)。

    这种变化也可能是由于与动态预测的交互作用:动态预测器的一种设计是,对于从未观察到要采取的分支,根本不使用任何分支预测资源。由于这样的分支很常见,这可以节省大量的历史表和BTB空间。但是,这样的方案与将反向分支预测为已采取的静态预测器不一致:如果从未采取反向分支,您不希望静态预测器拾取该分支,并将其预测为已采取,从而破坏为未采取的分支节省资源的策略。

    1...然后还要做更多的事情,比如退休,他们--但执行后发生的事情对我们这里的目的并不重要。

    2我在这里把“预测”放在吓人的引号中,因为在某种程度上,它甚至不是预测:not-take是在没有相反预测的情况下提取和解码的默认行为,所以如果您根本不放入任何静态预测,它就是您得到的结果,而您的动态预测器不会告诉您其他情况。

     类似资料:
    • 问题内容: 从我读到的内容来看,它用于修复CPU中的错误,而无需修改BIOS。根据我对汇编的基本知识,我知道汇编指令在内部由CPU分解为微代码,并相应地执行。但是intel以某种方式可以在系统启动和运行时进行一些更新。 有人有更多信息吗?是否有关于微码可以做什么以及如何使用的文档? 编辑:我读过维基百科的文章:没弄清楚我怎么能自己写一些,以及它有什么用。 问题答案: 在较早的时期,微代码在CPU中

    • 这个问题和它的答案,最近被标记为史诗般的答案,让我产生了疑问;我可以根据CPU分支预测失败来衡量Windows中运行的应用程序的性能吗?我知道存在一些静态分析工具,这可能有助于优化代码以在分支预测情况下获得良好的性能,手动技术可以通过简单地进行更改和重新测试来提供帮助,但我正在寻找一种自动机制,它可以在一段时间内报告分支预测失败的总数,我希望一些Visual C的Profiler工具可以帮助我。

    • Docker需要哪些英特尔虚拟化技术? 在英特尔cpu上运行的Linux系统上,英特尔需要哪些虚拟化技术来完成Docker容器的执行?例如,有VT-X、… 或者没有必要使用这样的技术,因为Docker与现有的虚拟化解决方案(如VirtualBox)有所不同。在这种情况下,为什么没有必要?

    • 从我的大学课程中,我听说,按照惯例,最好将更可能的条件放在中,而不是条件中,这可能有助于静态分支预测器。例如: 可以改写为: 我找到了一篇博客文章分支模式,使用GCC,它更详细地解释了这种现象: 为 if 语句生成转发分支。使它们不太可能被采用的理由是,处理器可以利用这样一个事实,即分支指令之后的指令可能已经放置在指令单元内的指令缓冲区中。 旁边写着(强调我的): 在编写if-else语句时,始终

    • 如果语句更多地依赖于分支预测,而v表查找更多地依赖分支目标预测,那么

    • 分支目标预测(BTP)与分支预测(BP)不同。我知道BTP会找到分支将跳转到的位置,而BP只是决定可能采取哪个分支。 BTP依赖BP吗,如果BTP不使用BP来预测哪个分支被采用,它怎么可能知道分支的目标呢? 我不明白为什么会有这么大的差异?一旦分支被预测为被占用,找到目标并不像读取指令中的地址一样简单吗?