如果您仍然需要检查条件,则分支预测如何工作?


30

我正在从https://stackoverflow.com/q/11227809/555690阅读有关分支预测的流行答案,这使我感到困惑:

  • 如果您猜对了,它将继续进行。
  • 如果您猜错了,机长会停下来,后退并大喊大叫,以拨动开关。然后,它可以沿着其他路径重新启动。

如果您每次都猜对了,火车将永远不会停止。

如果您经常猜错,火车将花费大量时间停止,备份和重新启动。

但这不是我所能得到的:要知道您的猜测是对还是错,无论如何都必须进行条件检查。那么,如果您仍在进行相同的条件检查,那么分支预测甚至如何工作?

我要说的是,分支预测是否与完全没有分支预测完全相同,因为无论如何您都在执行相同的条件检查?(显然我错了,但我不明白)


1
这篇Wiki文章在解释它方面做得很好。
enderland'3

8
现代CPU具有流水线功能,可以同时执行多项操作。因此,它可以在仍猜出是否正确的同时开始执行其猜测。如果猜测正确,则管道将继续运行。一个错误的猜测是,管道被丢弃,执行从“正确答案”点重新开始。
markspace

2
相关阅读:管道。我也建议您重新阅读该SO问题的可接受答案,因为它确实在这里回答了您的问题。

Answers:


19

当然,条件是每一次检查一次。但是,在进行检查时,它已深入到CPU管道中。同时,其他指令也已进入管道,并且处于执行的各个阶段。

通常,条件紧随其后是条件分支指令,如果条件评估为TRUE则分支,如果条件评估为FALSE则通过。这意味着根据条件是TRUE还是FALSE,可以在条件指令和分支指令之后将两种不同的指令流加载到管道中。不幸的是,在加载条件指令和分支指令之后,CPU尚不知道条件将对结果求值,但是它仍然必须继续将内容加载到管道中。因此,它会根据条件评估结果的选择来选择两组指令之一。

稍后,随着条件指令沿管线传递,现在是时候对其进行评估了。那时,CPU会发现其猜测是对还是错。

如果猜测正确,则分支转到正确的位置,并将正确的指令加载到管道中。如果事实证明猜测是错误的,那么条件分支指令之后加载到管道中的所有指令都是错误的,因此必须将其丢弃,并且必须从正确的位置重新开始获取指令。

修正案

为了回应StarWeaver的评论,给出一个CPU执行一条指令所必须做的事情的想法:

考虑一下MOV AX,[SI+10]我们人类天真地认为“将AX加上SI加10的单词” 这样简单的事情。大致来说,CPU必须:

  1. 将PC的内容(“程序计数器寄存器”)发送到地址总线;
  2. 从数据总线读取指令操作码;
  3. 增量PC
  4. 解码操作码以弄清楚该如何处理;
  5. 将PC的内容发送到地址总线;
  6. 从数据总线读取指令操作数(在这种情况下为10);
  7. 增量PC
  8. 将操作数和SI馈入加法器;
  9. 将加法器的结果发送到地址总线;
  10. 从数据总线读取AX。

这是多达10个步骤。这些步骤中的某些步骤甚至在非流水线CPU中也会被优化,例如,CPU几乎总是与下一步并行地递增PC,这很容易做到,因为PC是非常非常特殊的寄存器,从未用于其他任何作业,因此,CPU的不同部分之间不可能争用该特定寄存器。但是,对于这样一条简单的指令,我们只剩下8个步骤,并且请注意,我已经代表CPU承担了某种程度的复杂性,例如,我假设对于该CPU,不需要整个额外的步骤。加法器实际执行加法,然后才能从中读取结果,

现在,考虑存在更复杂的寻址模式,例如MOV AX, [DX+SI*4+10],甚至更复杂的指令,例如MUL AX, operand,它们实际上在CPU内部执行循环以计算其结果。

因此,我的意思是,“原子级”隐喻远不适合CPU指令级。如果您不想深入到实际的逻辑门级别,则它可能适合于流水线步骤级别。


2
呵呵,我想知道(包括我在内)人们是否对理解这部分问题是(无论如何对我来说)很难想象一个仅对一条指令有部分了解的cpu。还是要有一堆半成品指令“通过披萨带式烤箱”……至少对我来说,当我习惯于在竖立架和金属车床之间进行加工时,感觉就像是原子向规模的转变。
StarWeaver

1
@StarWeaver我喜欢您的评论,所以我修改了我的回答以解决。
Mike Nakis 2015年

1
哇,爆破 我倾向于忘记将单词移动到更有用的位置会花费多少。我仍然将cpu想象成一组皮带驱动的披萨烤箱:3。
StarWeaver

值得牢记的是,与OP链接的Stack Overflow问题 -拥有130万个视图,可能使超过100万程序员了解了以前甚至不知道“分支预测”的事实-在Java中展示了一个示例。对于像我这样习惯于像Java这样的语言为我们提供抽象水平的人们来说,它们甚至MOV AX,[SI+10]是陌生的,而不是“简单的”。当今大多数程序员从未编写过汇编。我们不会“天真地认为”它有任何意义。
Mark Amery

@MarkAmery好吧,好吧,我认为这很明显是指“我们人类”,意思是“我们敢于编写汇编的人类”。提出的观点是,甚至汇编语言程序员也不是一直或什至根本没有想到管道。
Mike Nakis

28

可以将其视为没有GPS的公路旅行。您来到一个十字路口,认为您需要转弯,但并不确定。因此,您转弯,但请您的乘客检查地图。也许到您完成关于位置的争论时,您已经走了三英里。如果您是对的,那么您比转弯之前停下来并争吵的距离要远三英里。如果输入错误,则必须转身。

CPU管道以相同的方式工作。到他们可以检查状况时,他们已经是一条路。不同之处在于,他们不必向后行驶三英里,他们只是失去了领先优势。这意味着尝试没有任何危害。


2
这个解释很简洁。
Sharptooth 2015年

2

根据我的理解,当需要检查的条件需要昂贵或仍在进行中的结果时,分支预测最有用,否则您将不停地拨动拇指,等待值来评估条件。

对于乱序执行之类的事情,您可以使用分支预测来开始填充管道中本来无法使用的空白点。由于某种原因,在流水线中没有任何空闲周期的情况下,是的,分支预测没有收益。

但是这里的关键是,CPU正在为一个预测的分支开始工作,因为它尚不能评估条件本身。


1

简写:

一些CPU可以在完成旧指令之前开始处理新指令。这些是使用分支预测的CPU。

伪代码示例:

int globalVariable;
int Read(int* readThis, int* readThat)
{
    if ((globalVariable*globalVariable % 17) < 5)
       return *readThis;
    else
       return *readThat;
}

上面的代码检查条件,并根据结果需要返回存储在内存位置addThis的值或存储在的值readThat。如果分支预测预测条件为true,则CPU将addThis在执行评估if语句所需的计算时已经读取存储在内存位置的值。这是一个简化的示例。


1

是的,可以通过任何一种方式检查条件。但是分支预测的优点是您可以做工作而不是等待条件检查的结果。

假设您必须写一篇论文,并且它可能是关于主题A或主题B的。您从以前的论文中知道,您的老师比B更好地喜欢主题A,并且选择频率更高。不必等待他的决定,您可以开始撰写有关第一个主题的文章。现在有两种可能的结果:

  1. 您开始撰写的主题错误,因此必须放弃到目前为止所写的内容。您必须开始写另一个主题,这与您等待时一样。
  2. 您猜对了,并且您已经完成工作。

现代CPU大部分时间都处于空闲状态,因为它们正在等待IO响应或其他计算的结果。这段时间可以用来做一些将来的工作。

即使您不得不忽略在这段空闲时间里正在做的事情-如果您能够猜测程序将选择哪个路径,那么最有可能更有效。并且现代CPU具有此功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.