为什么CPU分支指令很慢?

问题描述 投票:0回答:4

自从我开始编程以来,我到处阅读,不惜一切代价避免浪费分支。

没关系,尽管没有一篇文章解释了我为什么应该这样做。当CPU解码分支指令并决定进行跳转时到底会发生什么?是什么“东西”使它比其他指令(例如加法)慢?

optimization architecture language-agnostic cpu
4个回答
50
投票

分支指令本质上并不比任何其他指令慢。

但是,您听说应该避免分支的原因是因为现代 CPU 遵循 管道架构 。 这意味着有多个顺序指令同时执行。 但是,只有能够在每个周期从内存中读取下一条指令,管道才能得到充分利用,这反过来意味着它需要知道要读取哪条指令。

条件

分支上,它通常不提前知道将采取哪条路径。 因此,当发生这种情况时,CPU 必须停止运行,直到决策得到解决,并丢弃分支指令后面的管道中的所有内容。 这会降低利用率,从而降低性能。 这就是像

分支预测分支延迟槽存在的原因。


7
投票
jmp

call
这样的控制指令时,事情就会变得复杂。

由于CPU在执行

jmp

指令时不知道下一条指令是什么,因此它使用

分支预测
技术来预测是否会采用分支指令(例如,循环片段中的分支指令可能会被执行)将指令流带回循环头)。 但是,当这种预测失败时,即所谓的“分支错误预测”,它将影响执行性能。由于分支之后的流水线必须被丢弃,并从正确的指令开始。

Oli 给出了非常好的解释为什么分支成本高昂:管道和分支预测。不过,我想补充一点,您不应该非常担心这个问题,因为现代编译器会优化代码,而其中一项优化就是减少分支。


3
投票
此处

阅读有关 Microsoft 编译器中 C++ 优化的更多信息 - 配置文件引导优化器使用运行时信息(即代码的哪些部分最常用)来优化您的代码。加速比在 20% 范围内。

其中一个操作是“条件分支优化”,例如 - 假设大多数时候 i 是 6 - 这更快: if (i==6) { //... } else { switch (i) { case 1: // case 2: // //... } }

比:

switch (i)
{
    case 1: //
    //...
    case 6: //
    case 7: //
}

这里有一篇关于其他优化的博客文章:

http://bogdangavril.wordpress.com/2011/11/02/optimizating-your-native-program/

    

这并不完全相关,但不惜一切代价避免分支的建议对于现代推测性乱序执行处理器来说简直是无稽之谈。推测执行正是在等待内存中的数据时为处理器提供处理指令的过程。对分支条件的推测就是推测执行的全部内容。用算术替换分支实际上会减慢你的程序,所以要小心!更多关于

这里

0
投票

© www.soinside.com 2019 - 2024. All rights reserved.