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

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

方嘉言
2023-03-14

读完这篇文章(StackOverflow上的答案)(在优化部分)后,我想知道为什么条件移动对分支预测失败并不脆弱。我在这里找到了一篇关于cond移动的文章(AMD的PDF)。同样在那里,他们声称cond的性能优势。移动。但这是为什么?我看不出来。在评估ASM指令的那一刻,前面的CMP指令的结果还不知道。

共有3个答案

濮泳
2023-03-14

事实上,结果可能还不知道,但如果其他情况允许(特别是依赖链),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指令——相反,它会丢弃分支后所做的一切,并从头重新启动。这就是惩罚的来源。

厉文栋
2023-03-14

这都是关于指令管道的。记住,现代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时。跳过它必须选择是从下一条指令继续预取/解码指令,还是从跳转目标继续预取/解码指令。CPU将猜测该前向条件分支不会发生,因此下一条指令mov ebx,ecx将进入管道。

几个周期后,je。执行skip,并执行分支。糟了!我们的管道现在包含一些不应该被执行的随机垃圾。CPU必须刷新所有缓存的指令,并从重新开始。跳过:

这是预测失误分支的性能损失,这在cmov中永远不会发生,因为它不会改变执行流。

晁国发
2023-03-14

如果一切顺利(如果它没有暂停等待这些指令的数据依赖性从以前的指令或内存中到达),现代处理器通常每个周期执行一到三条指令。

上面的语句对于紧密循环非常有效,但这不应该让您看不到一个额外的依赖项,它可以阻止指令在其周期到来时执行:对于要执行的指令,处理器必须已经开始获取和解码它15-20个周期之前。

处理器遇到分支时应该怎么做?获取和解码两个目标不会扩展(如果后续分支更多,则必须并行获取指数数量的路径)。因此,处理器只是推测性地获取和解码这两个分支中的一个。

这就是错误预测的分支代价高昂的原因:由于高效的指令管道,它们花费了通常不可见的15-20个周期。

条件移动不需要预测,所以它永远不会有这个惩罚。它有数据依赖关系,与普通指令相同。事实上,条件移动比普通指令具有更多的数据依赖关系,因为数据依赖关系包括“条件true”和“条件false”两种情况。在有条件地将r1移动到r2的指令之后,r2的内容似乎既依赖于r2的前一个值,也依赖于r1。一个预测良好的条件分支允许处理器推断更准确的依赖关系。但数据依赖通常需要一两个周期才能到达,如果它们根本需要时间到达的话。

请注意,从内存到寄存器的有条件移动有时会是一个危险的赌注:如果条件是从内存读取的值没有分配给寄存器,那么您在内存上等待的时间就没有了。但指令集中提供的条件移动指令通常是寄存器对寄存器的,以防止程序员出现这种错误。

 类似资料:
  • 在阅读了这篇文章(关于StackOverflow的回答)(在优化部分)之后,我想知道为什么条件移动不容易受到分支预测失败的影响。我在这里找到了一篇关于cond移动的文章(由AMD提供的PDF格式)。同样在这里,他们宣称cond的性能优势。动作。但这是为什么呢?我看不出来。在评估ASM指令时刻,还不知道前面CMP指令的结果。

  • 我已经为Kubernetes部署中的容器定义了就绪性和活性探测。当这些失败时,我希望看到它们的输出包含在POD的事件中。然而,我没有看到这样的事件。我确实看到了同一吊舱的其他事件。 我在GKE上运行,Kubernetes V1.6.4。

  • 我有以下映射,它给出了最新elasticsearch的错误: 我得到以下错误。。。怎么了?“根映射定义有不受支持的参数:[mydoctype:{properties={location={type=geo_point}}}]

  • Html树: Xpath://table[@class='ur MatrixLayout urhtmltableReset']//tr//table//tr//td//div//div/span[contains(text(),'revisations')]

  • 从Spring 3.1开始,由于@Enable*注释,我们可以更容易地使用JavaConfig。 所以我做了一个WebConfig来设置WebMvc配置,并尝试对其进行测试。但是,如果我使用WebConfig扩展WebMVCConfigureAdapter或WebMvcConfigurationSupport,单元测试将失败,因为缺少ServletContext。代码和消息如下所示。 网络配置。J

  • 问题内容: 我的元素彼此相邻。 我想在它们之间进行设置,但没有效果。为什么? 我的代码: 问题答案: 原因 从MDN文档中: [margin属性]适用于除表标题,表和内联表以外的其他表显示类型的元素以外的所有元素 换句话说,该物业是 不 适用的元素。 解 考虑改为使用该属性。 请注意,应将其应用于具有布局和的父元素。 例如: HTML CSS 水平和垂直方向的边距不同 正如迭戈·基洛斯(Diego