Optimization 为什么CPU分支指令速度慢?

Optimization 为什么CPU分支指令速度慢?,optimization,architecture,language-agnostic,compiler-construction,cpu,Optimization,Architecture,Language Agnostic,Compiler Construction,Cpu,自从我开始编程以来,我在每个地方都读过书,不惜一切代价避免浪费分支 那很好,虽然没有一篇文章解释我为什么要这样做。当对分支指令进行解码并决定跳转时,会发生什么情况?是什么“东西”使它比其他指令(如加法)慢呢?分支指令本身并不比任何其他指令慢 然而,您之所以听说应该避免分支,是因为现代CPU遵循一种新的方法。这意味着同时执行多个顺序指令。但是,只有当管道能够在每个周期从内存中读取下一条指令时,它才能被充分利用,这反过来意味着它需要知道要读取哪条指令 在条件分支上,它通常不提前知道将采用哪条路径。因

自从我开始编程以来,我在每个地方都读过书,不惜一切代价避免浪费分支


那很好,虽然没有一篇文章解释我为什么要这样做。当对分支指令进行解码并决定跳转时,会发生什么情况?是什么“东西”使它比其他指令(如加法)慢呢?

分支指令本身并不比任何其他指令慢

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

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


这就是类似和存在的原因。

因为CPU采用管道来执行指令,这意味着当前一条指令在某个阶段(例如,从寄存器读取值)执行时,下一条指令将在同一时间执行,但在另一个阶段(例如,解码阶段)执行。对于非控制指令,这是可以的,但当执行
jmp
call
等控制指令时,会使事情变得复杂

由于CPU在执行
jmp
指令时不知道下一条指令是什么,因此它使用各种技术来预测是否执行分支指令(例如,循环片段中的分支指令可能会将指令流带回循环头)


然而,当这样的预测失败时,它将影响执行性能。因为分支后的管道必须被丢弃,并从正确的指令重新开始。

奥利很好地解释了为什么分支代价高昂:管道和分支预测。然而,我想补充一点,您不应该非常关心这个问题,因为现代编译器将优化代码,而一个优化就是减少分支

<>你可以在微软编译器中阅读更多关于C++优化的信息。配置文件优化程序使用运行时信息(即代码的哪些部分最常用)来优化代码。加速率在20%范围内

其中一个操作是“条件分支优化”,例如-假设大部分时间i为6-这会更快:

if (i==6)
{
    //...
}

else
{
    switch (i)
    {
        case 1: //
        case 2: //
        //...
    }
}
比:


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

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

+1:对于这个问题也很重要:现代CPU通常必须将这种性能损失降至最低。但是有一些技术可以加速这个过程,称为“分支预测”(branch prediction)。这并不总是奏效,但总的来说效果更好。编辑:我太慢了。我只是想说明一下:暂停管道意味着必须卸载所有预加载的指令。此外,必须恢复任何可能的副作用(通常是由于预测失误而更改的数据)。所有这些操作都需要花费时间和精力。
switch (i)
{
    case 1: //
    //...
    case 6: //
    case 7: //
}