为什么有条件移动不容易受到分支预测失败的影响?


77

在阅读了这篇文章(关于StackOverflow的答案)(在优化部分)之后,我想知道为什么条件移动不容易受到分支预测失败的影响。我在一篇关于cond move的文章中找到了该文章(AMD撰写的PDF)。同样,他们声称cond的性能优势。动作。但是为什么呢?我没看到 在评估该ASM指令时,尚不清楚先前的CMP指令的结果。


7
顺便说一句,您可能想知道,以我在Intel Core2和Core-i7 CPU上的经验来看,cmov并不总是能赢得性能。在我的测试中,只要预测率高于大约99%,分支本身就会更好。这听起来可能很高,但是在英特尔的分支机构预测器上却很常见。特别是在分支内部循环中会发生这种情况:说一个分支迭代1000次,而在第999次,它做了一些不同的事情。使用条件跳转比使用cmov总是更有效。
jstine

1
PDF链接当前需要授权。
leewz

对于C ++编译器它们是相同的:参见附加图像
尼古拉Trandafil

1
@NikolaiTrandafil:这完全取决于您选择的编译器,启用的编译标志和目标ISA。
Martijn Courteaux

相关:CMOVcc是否被视为分支指令?-不,这是ALU选择操作。答案包括一些有关性能折衷细节的链接。
彼得·科德斯

Answers:


64

错误预测的分支机构很昂贵

如果情况进展顺利,现代处理器通常每个周期执行一到三个指令(如果它不会停顿等待这些指令的数据相关性从先前的指令或从内存到达)。

上面的语句在紧密循环中表现出令人惊讶的良好表现,但这不应该使您对一个附加的依赖项视而不见,后者可以阻止指令在其周期到来时执行:要执行一条指令,处理器必须已经开始获取和解码在15-20个周期之前。

处理器遇到分支时应该怎么做?提取和解码两个目标均无法扩展(如果跟随更多分支,则必须并行获取指数级的路径)。因此,处理器仅以推测方式获取和解码两个分支之一。

这就是为什么错误预测的分支很昂贵的原因:分支需要花费15-20个周期,由于有效的指令流水线,这些周期通常是不可见的。

有条件的举动从来都不是很昂贵的

有条件的移动不需要预测,因此它永远不会受到惩罚。它具有数据依赖性,与普通指令相同。实际上,条件移动比普通指令具有更多的数据相关性,因为数据相关性包括“条件为真”和“条件为假”两种情况。指令之后,有条件地移动r1r2,内容r2似乎依赖于前面两个值r2r1。预测良好的条件分支允许处理器推断出更准确的依赖性。但是,如果数据依赖关系完全需要时间,则通常需要一两个周期才能到达。

请注意,从内存到寄存器的有条件移动有时是危险的选择:如果条件是从内存读取的值未分配给寄存器,则您在内存上等待的时间为空。但是,指令集中提供的条件移动指令通常是按寄存器注册的,从而避免了程序员的这种错误。


1
除第一句话外,我同意您写的所有内容(或看起来至少对我来说可以接受)。您能否详细说明一个CPU将在每个周期执行三个asm指令?
Martijn Courteaux

4
@MartijnCourteaux典型的现代台式机处理器的管线的所有阶段都能够处理约3条指令,在最佳情况下,每周期吞吐量可达到3条指令。例如,解码阶段可以每个周期解码16个字节的指令:通常是3个指令。还有足够的执行单元,可以在一个周期内处理三个独立的指令。有关详细信息,请访问agner.org/optimize/microarchitecture.pdf(顺便说一下,这是一个很好的参考)。
Pascal Cuoq

@MartijnCourteaux例如第79页:“流水线其余部分的吞吐量通常每个时钟周期为4条指令”(但是您几乎永远不会获得理论上每个周期的4条指令。即使只有3条仅在算法允许并且需要手动操作时)针对特定处理器模型编写的,手动对齐的代码)
Pascal Cuoq 2013年

因此,它可以解码4条指令,但可以同时处理2或3条指令,具体取决于我们对算法有多幸运?
Martijn Courteaux 2013年

如果它们只能容纳16个字节,它只能解码4条指令,因此这取决于您对开始所需的指令长度有多幸运。而且,如果它具有所有必要的单位来执行全部任务,那么它最多只能执行4个命令(如果这是您的目标,这可能需要混合使用浮点和整数计算来实现),并且如果输入的结果不是的输出,另一个。如果您真的有兴趣,可以看一下这种提高细粒度并行度的技术,但我应该警告您,它很少会加快实践速度:en.wikipedia.org/wiki/Software_pipelining
Pascal Cuoq 2013年

48

这全是关于指令流水线的。请记住,现代CPU在管道中运行其指令,当CPU可以预测执行流程时,这将显着提高性能。

克莫夫

    add     eax, ebx
    cmp     eax, 0x10
    cmovne  ebx, ecx
    add     eax, ecx

在评估该ASM指令时,尚不清楚先前的CMP指令的结果。

也许,但仍CPU知道下面的指令cmov会后立即执行,无论从结果,cmpcmov指令。因此,可以安全地提前提取/解码下一条指令,分支的情况并非如此。

下一条指令甚至可以在执行之前执行cmov(在我的示例中,这是安全的)

    add     eax, ebx
    cmp     eax, 0x10
    je      .skip
    mov     ebx, ecx
.skip:
    add     eax, ecx

在这种情况下,当CPU的解码器看到je .skip它时,必须选择是继续从下一条指令1)还是从跳转目标继续2)预取/解码指令。CPU会猜测此向前条件分支不会发生,因此下一条指令mov ebx, ecx将进入管道。

几个循环之后,je .skip执行并执行分支。哎呀!现在,我们的管道包含一些永远不应执行的随机垃圾。CPU必须刷新其所有缓存的指令并从重新开始.skip:

那是分支预测错误的性能损失,cmov因为它不会改变执行流程,所以永远不会发生。


4
我可以弄清楚这可能是带有操作码,目标,源的Intel语法,但是如果您明确提及汇编标准,那就太好了。
Zan Lynx

18

的确,结果可能还不得而知,但是如果其他情况允许(特别是依赖关系链),则cpu可以重新排序并执行指令cmov。由于不涉及分支,因此无论如何都需要评估那些指令。

考虑以下示例:

cmoveq edx, eax
add ecx, ebx
mov eax, [ecx]

后面的两条指令cmov不取决于的结果cmov,因此即使它们cmov本身处于挂起状态也可以执行它们(这被称为乱序执行)。即使它们无法执行,也仍然可以获取和解码。

分支版本可以是:

    jne skip
    mov edx, eax
skip:
    add ecx, ebx
    mov eax, [ecx]

这里的问题是控制流正在改变,并且cpu不够聪明,mov如果分支被错误地预测为已采用,它就不能“插入”跳过的指令-相反,它会丢弃分支后所做的一切,然后重新启动从头开始。这就是罚款的来源。


2
我可以弄清楚这可能是带有操作码,目标,源的Intel语法,但是如果您明确提及汇编标准,那就太好了。
Zan Lynx

3

您应该阅读这些。使用Fog + Intel,只需搜索CMOV。

Linus Torvald在2007年左右对CMOV的批评
Agner Fog对微体系结构的比较Intel®64
和IA-32体系结构优化参考手册

简短的回答,正确的预测是“免费的”,而条件分支的错误预测可能会在Haswell上花费14-20个周期。但是,CMOV永远不会免费。不过,我仍然认为CMOV比Torvalds抱怨时要好得多。在所有曾经回答过的处理器上,没有任何一种方法能够始终正确。


3
不,cmov仍然是数据依赖项,因此可以创建分支预测将隐藏的循环承载的依赖项链。英特尔Broadwell / Skylake将其解码为单个uop,而不是2(Haswell和更早版本),因此现在价格便宜一些。Sandybridge和更高版本的uop缓存意味着多uop指令的解码吞吐量损失通常也不是一个因素。尽管如此,它并没有改变数据和控件依赖项之间的根本区别。同样,x86cmov仍然没有带有立即操作数的形式,因此x = x<3 ? x : 3实现起来仍然很笨拙。
彼得·科德斯

1
另外,我认为您在以下方面有一个编辑错误:“除非分支预测错误,否则CMOV永远不会非常昂贵”。该句子完全是胡说八道,因为没有预测cmov。这就是为什么它不会遭受错误的预测。
彼得·科德斯

非常感谢您提供有用的链接。
Maxim Masiutin

可能感兴趣的另一个链接:gcc.gnu.org/bugzilla/show_bug.cgi?id=56309
Max Barraclough

0

我从[Peter Puschner et al。]幻灯片中获得了此插图,该幻灯片解释了如何将其转换为单路径代码并加快执行速度。

在此处输入图片说明


1
比较谓词下一条指令会很好,但是实际架构通常也需要3条指令来执行谓词序列。(除了ARM 32位,如果有交换/交换指令,它可以cmp/ swplt。)无论如何,现代CPU通常不会从分支中产生气泡,而会因错误预测而产生气泡:stackoverflow.com/questions/11227809/…。但是,在高吞吐量代码中,正确预测的采用分支可能会减少解码/前端带宽。
彼得·科德斯
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.