在执行uop计数不是处理器宽度倍数的循环时性能是否会降低?

时间:2016-09-03 22:28:22

标签: performance assembly x86 cpu-architecture micro-optimization

我想知道各种大小的循环如何在最近的x86处理器上执行,作为uop数的函数。

以下是Peter Cordes的一句话:another question提出了非多重4的问题:

  

我还发现循环缓冲区中的uop带宽不是a   如果循环不是4 uop的倍数,则每个循环常数4。 (即   这是abc,abc,......;不是abca,bcab,...)。 Agner Fog的微博文档   遗憾的是,对于循环缓冲区的这种限制并不清楚。

问题在于循环是否需要是N uops的倍数才能以最大uop吞吐量执行,其中N是处理器的宽度。 (即最近的英特尔处理器为4)。在谈论“宽度”和计算微动时,有很多复杂因素,但我大多想忽略这些因素。特别是,假设没有微观或宏观融合。

Peter给出了以下一个循环,其中包含7个uop的循环:

  

7-uop循环将发出4 | 3 | 4 | 3 | ...我没有测试更大的组   循环(不适合循环缓冲区)以查看是否可能   从下一次迭代开始的第一条指令   组作为它的分支,但我不认为。

更一般地说,声明是在其正文中具有xmlns:android="http://schemas.android.com/apk/res/android" uops的循环的每次迭代将至少进行x次迭代,而不仅仅是ceil(x / 4)次迭代。

对于部分或全部最新的x86兼容处理器,这是真的吗?

2 个答案:

答案 0 :(得分:5)

这是原始答案的后续,基于Andreas Abel提供的测试结果来分析另外五种体系结构的行为:

  • Nehalem
  • 桑迪桥
  • 常春藤桥
  • 百老汇
  • 咖啡湖

除了Skylake和Haswell之外,我们还将快速查看这些架构的结果。由于Nehalem以外的所有架构都遵循上述现有模式之一,因此它只需要“快速”外观即可。

首先,简短的nop情况适用于传统的解码器(用于LSD中不适合的循环)和LSD。这是针对所有7种架构的此方案的周期/迭代。

图2.1:所有架构都具有密集的nop性能:

All Architectures Dense Nop Performance

该图确实很忙(单击以查看大图),并且由于许多体系结构的结果相互重叠而难以阅读,但是我尝试确保专用的读者可以跟踪任何体系结构的线条

首先,让我们讨论一个较大的离群值:Nehalem。所有其他架构的斜率都大致遵循4 oups /周期的线,但是Nehalem每个周期几乎正好为3 uops,因此很快落后于所有其他架构。在初始LSD区域之外,该线也完全平滑,没有其他架构中看到的“阶梯”外观。

这完全与Nehalem的uop 退休限制为3 oups /周期一致。这是LSD之外的ouop的瓶颈:它们每个周期执行的时间大约为3 uops,在退休时成为瓶颈。前端不是瓶颈,因此确切的uop计数和解码安排无关紧要,因此没有阶梯。

除Nehalem以外,除Broadwell以外的其他体系结构都非常干净地分为几类:类似Haswell或Skylake。也就是说,对于大于约15 oups的循环,所有Sandy Bridge,Ivy Bridge和Haswell的行为都类似于Haswell(在另一个答案中讨论了Haswell行为)。即使它们是不同的微体系结构,它们的行为也基本相同,因为它们的传统解码功能是相同的。在大约15 oups以下,对于任何uop计数(不是4的倍数),我们都可以看到Haswell更快一些。也许由于更大的LSD或其他“小循环”优化,它在LSD中会产生额外的展开。对于Sandy Bridge和Ivy Bridge而言,这意味着小循环绝对应该以uop计数为目标,该计数是4的倍数。

咖啡湖的行为与Skylake 1 类似。这是有道理的,因为微架构是相同的。在大约16 oups以下,Coffee Lake看起来比Skylake更好,但是默认情况下,这只是Coffee Lake的禁用LSD的影响。 Skylake已通过启用的LSD进行了测试,之后英特尔由于安全问题通过微码更新将其禁用。在已知此问题后发布了Coffee Lake,因此LSD禁用了现成的功能。因此,对于此测试,Coffee Lake使用的是DSB(适用于大约18 uops以下的循环,仍可以容纳在DSB中)或旧版解码器(适用于其余的循环),这对于较小的uop计数会带来更好的结果LSD造成开销的循环(有趣的是,对于较大的循环,由于非常不同的原因,LSD和旧式解码器恰好施加了相同的开销)。

最后,我们看一下2字节的NOP,它们的密度不足以阻止使用DSB(因此这种情况更能反映典型的代码)。

图2.1:2字节nop性能:

2-byte nop performance

同样,结果与之前的图表相同。 Nehalem仍是每个周期3微秒的瓶颈。对于大约60欧元的范围,除Coffee Lake以外的所有体系结构都使用LSD,我们发现Sandy Bridge和Ivy Bridge在这里的性能稍差一些,舍入到下一个周期,因此只能实现最大吞吐量4 uops / cycle,如果循环中的uops数目是4的倍数。高于32 uops时,Haswell和新的uarch的“展开”功能无效,因此一切都大致相同。

Sandy Bridge实际上具有一些uop范围(例如,从36到44 oups),其性能要比更新的体系结构更好。出现这种情况似乎是因为LSD并非检测到所有循环,而是在这些范围内由DSB提供循环。由于DSB通常更快,因此在这些情况下,Sandy Bridge也是如此。

英特尔怎么说

正如Andreas Abel在评论中指出的,您实际上可以在《英特尔优化手册》的3.4.2.5节中找到专门处理此主题的部分。英特尔说:

  

LSD包含微操作,这些操作构成了小的“无限”循环。   来自LSD的微操作是在乱序引擎中分配的。的   LSD中的循环以到循环开始的分支分支结束。   循环结束时采取的分支始终是最后一个微操作   在周期中分配。循环开始处的指令   总是在下一个周期分配。如果代码性能是   受前端带宽限制,未使用的分配时隙会导致   分配过程中出现泡沫,并可能导致性能下降。   英特尔微体系结构代码名称Sandy Bridge中的分配带宽   每个周期四个微操作。性能最好的时候   LSD中的微操作导致最少的未使用分配   插槽。您可以使用循环展开来控制微操作的数量   在LSD中。

他们继续显示一个示例,由于LSD“四舍五入”,将循环展开两倍,对性能没有帮助,但是展开三幅作品。该示例非常令人困惑,因为它实际上混合了两种效果,因为展开更多还可以减少循环开销,从而减少每次迭代的微指令数。一个更有趣的示例是,由于LSD舍入效应,展开循环更少时间导致性能提高。

本节似乎准确地描述了Sandy Bridge和Ivy Bridge中的行为。上面的结果表明,这两种体系结构都按上述方式工作,并且对于分别具有4N + 3、4N + 2或4N + 1的循环,您将丢失1、2或3个uop执行插槽。

它并没有使用Haswell及其以后的新性能进行更新。如另一个答案所述,性能已从上述简单模型提高,行为更加复杂。


1 在16 ups处有一个怪异的异常值,其中Coffee Lake的性能比所有其他体系结构都要差,甚至包括Nehalem(约50%的回归),但也许是这种测量噪声?

答案 1 :(得分:3)

TL; DR:对于恰好由7 oups组成的紧密循环,将导致无效的退用带宽利用率。考虑手动展开循环,因此循环将包含12微秒


我最近面临退休带宽下降的问题,环路包括7微妙。在我自己进行了一些研究之后,快速谷歌搜索将我引向这个话题。这是我向Kaby Lake i7-8550U CPU申请的2美分:

正如@BeeOnRope所指出的,KbL i7-8550U之类的芯片上的LSD已关闭。

考虑以下NASM宏

;rdi = 1L << 31
%macro nops 1
    align 32:
    %%loop:
    times %1 nop
    dec rdi
    ja %%loop
%endmacro

“平均退休率” uops_retired.retire_slots/uops_retired.total_cycle如下所示:

enter image description here

这里要注意的是,当循环由7个oups组成时,其退休性能将下降。这导致每个周期退回3.5 uops。

idq的平均投放速度idq.all_dsb_cycles_any_uops / idq.dsb_cycles

enter image description here

对于7 oups的循环,导致每个周期将3.5 uops传送到idq。仅根据此计数器判断,不可能得出uops缓存传递4 | 3还是6 | 1组的结论。

对于由6个uops组成的循环,可以有效利用uops高速缓存带宽-6 uops / c。当IDQ溢出时,微码缓存会保持空闲状态,直到可以再次发送6微码为止。

要检查uops缓存如何保持空闲状态,我们比较idq.all_dsb_cycles_any_uops和周期

enter image description here

传递给idq的微循环数等于7微循环的总循环数。相比之下,对于6微秒的循环,计数器明显不同。

要检查的关键计数器是idq_uops_not_delivered.*

enter image description here

对于7 oups的循环可以看到,重命名器采用4 | 3组,这导致无效的退休带宽利用。