英特尔与AMD的AVX性能比较

3

我注意到 Zen2 上的一些 AVX 指令与它们的英特尔对应物相比,其 μops 成本极高。根据 μops 表:

VPGATHERDD Skylake Zen3
延迟(时钟数) [0;22] [0;28]
倒数 TP(测得) 5.00 8.00
μops(测得) 5 39

这些数字看起来像是可能影响聚集性能的因素。这个问题类似于一些旧的标量 vs 聚集问题,但那些问题更多地关注了英特尔,没有讨论到挖掘机 / Zen μops 聚集成本。也许是因为当时 AMD CPU 并不流行,但今天它更相关了。我找到的唯一解释这样一个巨大的差异的方法是一些随机评论声称 AMD CPU 中的聚集被微码化了。我在 Agner Fog 和 AMD 编程指南中都没有找到任何额外的解释。

我试图在 Zen3、Skylake 和 Broadwell 处理器上进行一些基准测试,以查看标量负载与聚集的比较情况。

Broadwell Skylake Zen3
1x 1x 1x
1.5-2.1x 3.1-6x 1x

吞吐量差异应该使得英特尔方面的差异约为1.6倍(8/5)。有多少可以归因于μops的差异?

当与真实代码混合时,大μops成本会损害乱序执行吗?或者这是极不可能的,因为Zen处理器具有大μops缓存?是否有更好的基准测试?

*最初的基准测试是错误的;链接和表中的数字现已修正。


1
我再次使用 -O2 检查了您修复后的工作版本,并且在 Zen3 4 GHz CPU 上两个版本都始终得到大约 3.5M 纳秒的结果(其中聚集平均较慢 5%),看来您是正确的。这意味着 Zen3 中的聚集与 Haswell 中一样无用。 - Vladislav Kogan
1
是的,除非作为更大算法的一部分,如果您的索引已经作为计算结果存储在向量中,并且/或者您需要将结果保存在SIMD向量中以进行进一步计算。那么您可以避免解包到标量并重新洗牌回向量的过程。 - Peter Cordes
1
不幸的是,Zen 4 仍然没有快速的 gather 或 scatter。它具有快速的掩码加载,但掩码存储仍然非常缓慢。(因此,在其 AVX-512 支持中存在重大差距)。掩码加载和其他寄存器写入与掩码存储不同(也更容易),因为后者必须在存储缓冲区中表示,并且存储转发是一种技术。当然,他们可能会在 Zen 5 或以后解决其中的一些问题。 - Peter Cordes
1
更正一下,Zen 4 具有快速的 AVX-512 掩码存储,例如 vmovdqu32 (m256, k, ymm),但由于某种原因,AVX1/2 的微码 vmaskmovps/pdvpmaskmovd/q 仍然需要大量的 uops。不仅仅是将其与内部临时掩码进行比较并使用硬件支持。在看到 vmaskmovps 的数字后,我认为可能没有有效的掩码存储的硬件支持。 - Peter Cordes
1
任何包含1或2个uops的指令都会被解码为“Directpath”(由解码器直接生成的uops),而不是“Vectorpath”(解码器间接引用微码ROM)。https://en.wikichip.org/wiki/amd/microarchitectures/zen_2#Instruction_Fetch_and_Decode_Unit 我不知道为什么Zen 4的整数vphaddd需要4个uops,而vhaddps只需要3个uops。在英特尔上,“hadd *”指令始终为3个uops,除非有一个内存源。(可能需要2个洗牌来提供垂直加法。) - Peter Cordes
显示剩余3条评论
2个回答

2

成为多uops的最大影响在于它如何与周围代码(例如在循环中)重叠,而该代码“不是”相同的指令。

如果聚集是循环中几乎唯一的事情,您将主要瓶颈于聚集指令本身的吞吐量,无论管道的哪个部分限制了聚集到该吞吐量。

但是,如果循环执行许多其他操作,例如计算聚集索引和/或使用聚集结果,或完全独立特别是标量整数工作,则可能接近前端瓶颈(Zen 3上每时钟周期6个uops问题/重命名),或后端ALU端口的瓶颈。 (AMD有单独的整数和FP后端管道;Intel共享端口,尽管有一些额外的执行端口仅具有标量整数ALU。)在这种情况下,聚集的uops成本会导致瓶颈。

除了分支缺失和缓存缺失之外,性能的三个维度是前端uops、它竞争的后端端口以及作为关键路径的延迟。请注意,这些都不同于仅连续运行相同指令时得到的数字,即测量单个指令“吞吐量”的数字。这对于识别那些uops的任何其他特殊瓶颈是有用的。

某些uops可能会占用一个端口多个周期,例如一些英特尔的gather加载比元素的总数少,因此它们在某些时刻可能会阻止其他加载的调度,从而创建比每个端口的uops数量预期更多的后端端口压力。FP除法/平方根也是如此。但由于AMD的gather uops非常多,我希望它们都是完全流水线化的。

AMD的AVX1/2掩码存储器也是大量的uops;如果它们没有高效的专用硬件来模拟它,我不知道他们是如何在微码中模拟的,但它对性能并不好。也许通过将其分成多个条件标量存储器来实现。

奇怪的是,Zen 4 的 AVX-512 掩码存储(如 vmovdqu32 (m256, k, ymm)非常高效,单个操作码,时钟吞吐量为1(尽管可以在任何存储端口上运行,根据https://uops.info/; Intel有2个时钟掩码存储吞吐量与常规存储相同,自 Ice Lake 以来)。如果 vpmaskmovd 的微代码只是将比较结果用作掩码,并使用与 vmovdqu32 相同的硬件支持,那么它将更加高效。我认为这就是 Intel 所做的,考虑到 vmaskmovps 的操作码计数。

另请参见


这与缓存μops无关,而是每次指令运行时将所有这些μops通过管道的问题。
在AMD上,一个具有超过2个μops或在Intel上超过4个μops的uop被认为是“微码化”的,而uop缓存仅存储到微码序列器的指针,而不是所有的μops本身。这种机制使得支持像rep movsb这样根据寄存器值运行可变数量的μops的指令成为可能。至少在Intel上,微编码指令需要一整行uop缓存(请参见https://agner.org/optimize/ - 特别是他的微架构指南)。

1
@VladislavKogan:一些整数循环和指针计算开销(dec/ jnz,也许是add rsi, 32或其他),以及一些其他的SIMD uops,如vxorps(0.25c吞吐量)或vaddps / vmulps(每个0.5c吞吐量,但用于不同的端口,因此均匀混合也是0.25c)。可能还有一个额外的存储或其他东西。使用可以在不同端口上运行的不同uops的混合,您可以每个时钟运行6个uops。请参见https://en.wikichip.org/wiki/amd/microarchitectures/zen_3和Zen 2的管道图-https://en.wikichip.org/wiki/amd/microarchitectures/zen_2#Block_Diagram。 - Peter Cordes
谢谢。现在有关于Zen3实现比标量mov m/r32更快的解释吗?从理论上讲,它在uops(39 vs(1 * 8))和rTP(9 vs(0.5 * 8 = 4))方面都输了。我是否忽略了其他因素? - Vladislav Kogan
@VladislavKogan:如果你在谈论使用clang -O2编译的基准代码(https://godbolt.org/z/q46zvndh7),请注意,`main`中的所有`std::vector`都被优化掉了,甚至没有分配内存,也没有加载或存储。它调用`rand` 2x 8000次并丢弃结果,然后计时空循环,其中一个增加8,另一个增加1,因此速度快了约7.6倍。asm volatile("":::“memory”);仅对已经被取地址并可能全局可见或通过输入操作数到达的东西起作用,但你没有给它任何东西。 - Peter Cordes
不,我的意思是就算没有优化,普遍情况下也是如此。我在Zen3处理器上使用-O0运行了这段代码,仍然得到了明显的速度提升。我还运行了您修复后的版本,并且在5600H上使用-O0时,得到了24M与73M之间的差距,在-O2时则为3.1M与6.4M之间的差距。所以,正确的基准测试仍然显示Zen3上的gather比标量更好,这是预期的,因为这正是它们实现的全部意义。我只是不完全明白它们为什么更快。 - Vladislav Kogan
@VladislavKogan:使用-O0进行基准测试是没有意义的。由于所有本地变量的加载和存储(特别是std::vector的额外间接性),有太多的开销。通常,在-O0下,带有内在函数的SIMD比标量代码更受影响,但可能是C++模板开销导致这种情况发生。使用您的-O2基准测试来检查实际执行的标量汇编代码,以确保它没有太多额外的开销。 - Peter Cordes
显示剩余4条评论

0

这里并非Uops缓存的问题。在AMD Zen3上,vpgatherdd ymm具有高μops成本和高rTP。因此,在Zen3(以及可能在其他Zen上)上的收集指令显示出几乎与标量代码相同的性能。因此在AMD处理器上没有必要使用gather指令(除非它们是更大的SIMD算法的一部分)。

这类似于早期在Intel Sandy Bridge / Haswell上实现gather的情况,其中gather直到Broadwell和Skylake推出才等于标量代码。然而,在未来的Zen CPU中,这种情况可能会有所改善,就像以前发生的变化一样。

vpgatherdd ymm Zen+ Zen2 Zen3 Zen4
μops 65 60 39 42
rTP(CPI) 20 16 8 8

一些其他指令中也存在高(≥10x)的μops差异。总之,最新的Zen4(增加了AVX512支持)仍然没有快速的gather、scatter或掩码AVX/AVX2存储。Maskload和AVX-512 maskstore是快速的。更多细节在这里

这些慢速指令确实是微代码化的。在官方AMD指南中,它们的μops成本被标注为“ucode”,没有给出任何确切的数字。因此,它们基本上是CPU模拟而不是具有专用硬件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接