x86-64 - 为什么英特尔宣传的某些 Haswell AVX 延迟比 Sandy Bridge 慢 3 倍?

标签 x86-64 intel simd cpu-architecture avx2

在英特尔 intrinsics webapp ,从桑迪布里奇到哈斯韦尔,一些操作似乎已经恶化。例如,像 _mm256_insertf128_si256 这样的许多插入操作显示的成本表如下所示:

   Performance
 Architecture   Latency   Throughput
 Haswell        3         -
 Ivy Bridge     1         - 
 Sandy Bridge   1         - 

我发现这种差异令人费解。这种差异是因为有新的指令取代这些指令或补偿它的东西(哪些)?有谁知道 Skylake 是否会进一步更改此模型?

最佳答案

电话:DR :根据 Agner Fog's testing,所有跨车道混洗/插入/提取在 Haswell/Skylake 上都有 3c 延迟,但在 SnB/IvB 上有 2c 延迟.

这可能是执行单元中的 1c + 某种不可避免的旁路延迟,因为 SnB through Broadwell have standardized latencies of 1, 3, or 5 cycles, never 2 or 4 cycles 中的实际执行单元. (SKL 制作了一些 uops uops 4c,包括 FMA/ADDPS/MULPS)。

(请注意,在使用 128b ALU 执行 AVX1 的 AMD CPU(例如 Bulldozer/Piledriver/Steamroller)上,insert128/extract128 比像 VPERM2F128 这样的 shuffle 快得多。)

内在指南有时会包含虚假数据。我认为它是用于 reg-reg 形式的指令,除了负载内在函数的情况下。即使它是正确的,内在指南也没有给出非常详细的性能图;有关 Agner Fog 的表格/指南的讨论,请参见下文。

(我对内在函数的不满之一是很难使用 PMOVZX/PMOVSX 作为负载,因为提供的唯一内在函数采用 __m128i 源,即使 pmovzxbd 只加载 4B 或 8B (ymm) . 它和/或广播负载( _mm_set1_* 与 AVX1/2)是压缩内存中常量的好方法。应该有采用 const char* 的内在函数(因为它可以为任何东西设置别名))。

在这种情况下,Agner Fog's measurements显示 SnB/IvB 对 reg-reg 的延迟为 2c vinsertf128/vextractf128 ,而他对 Haswell 的测量(3c 延迟,每 1c tput 一个)与英特尔的表格一致。所以这是英特尔内在指南中的数字错误的另一种情况。 它非常适合找到正确的内在函数,但不是可靠性能数据的良好来源。 它不会告诉您有关执行端口或总 uops 的任何信息,并且通常甚至会忽略吞吐量数字。 无论如何,延迟通常不是向量整数代码中的限制因素。 这可能就是英特尔让 Haswell 延迟增加的原因。

reg-mem 形式明显不同。 vinsertf128 y,y,m,i具有 lat/recip-tput:IvB:4/1、Haswell/BDW:4/2、SKL:5/0.5。它始终是一个 2-uop 指令(融合域),使用一个 ALU uop。 IDK为什么吞吐量如此不同。也许阿格纳的测试略有不同?

有趣的是,vextractf128 mem,reg, i不使用任何 ALU uops。这是一个 2-fused-domain-uop 指令,只使用 store-data 和 store-address 端口,而不是 shuffle 单元。 (Agner Fog 的表格将其列为在 SnB 上使用 1 p015 uop,在 IvB 上使用 0。但即使在 SnB 上,在任何特定列中也没有标记,因此 IDK 哪个是正确的。)
vextractf128真傻在立即操作数上浪费一个字节。我猜他们不知道他们将在下一个向量长度扩展中使用 EVEX,并且正在准备立即从 0..3 开始。但是对于 AVX1/2,你永远不应该使用立即数 = 0 的指令。相反,只是 movups mem, xmmmovaps xmm,xmm . (我认为编译器知道这一点,并且当您使用索引 = 0 的内在函数时会这样做,就像他们对 _mm_extract_epi32 等等( movd )所做的那样。)

延迟通常是 FP 代码中的一个因素,而 Skylake 是 FP ALU 的怪物。他们设法将 FMA 的延迟降低到 4 个周期,因此 mulps/addps/fma...ps 都是 4c 延迟,每 0.5c 吞吐量一个。 (Broadwell 是 mulps/addps = 3c 延迟,fma = 5c 延迟。Haswell 是 addps=3c 延迟,mul/fma=5c)。 Skylake 放弃了单独的 add 单元,因此 addps 实际上从 3c 恶化到 4c,但吞吐量是原来的两倍。 (Haswell/BDW 只在每 1c 吞吐量下添加一个,是 mul/fma 的一半。)所以 在大多数 FP 算法中使用许多向量累加器是必不可少的 如果存在循环携带依赖性,则一次保持 8 或 10 个 FMA 处于飞行状态以使吞吐量饱和。否则,如果循环体足够小,乱序执行将同时进行多次迭代。

整数 in-lane 操作通常只有 1c 延迟,因此您需要更少量的并行来最大化吞吐量(并且不受延迟限制)。

将数据输入/输出 ymm 的上半部分的其他选项都不是更好
vperm2f128或 AVX2 vpermps更贵。通过内存会导致存储转发失败-> 插入的大延迟(2 个窄存储-> 宽负载),所以这显然很糟糕。不要试图避免 vinsertf128在它有用的情况下。

与往常一样,尽量使用最便宜的指令序列。例如对于水平总和或其他缩减,始终首先缩减到 128b 向量,因为跨车道洗牌很慢。通常它只是 vextractf128/addps xmm ,然后是通常的 horizontal 128b .

正如 Mysticial 所暗示的那样,Haswell 和后来的 128b 向量的 channel 内向量洗牌吞吐量是 SnB/IvB 的一半。 SnB/IVB 可以 pshufb/pshufd每 0.5c 吞吐量一个,但对于 shufps,每 1c 只有一个(即使是 128b 版本);对于在 AVX1 中具有 ymm 版本的其他洗牌也是一样的(例如 vpermilps ,它显然只存在以便可以在一条指令中完成 FP 加载和洗牌)。 Haswell 完全摆脱了 port1 上的 128b shuffle 单元,而不是为 AVX2 加宽它。

回复:天湖

Agner Fog 的指南/insn 表于 12 月更新,包括 Skylake。另见 标记 wiki 以获得更多链接。 reg,reg 形式与 Haswell/Broadwell 具有相同的性能。

关于x86-64 - 为什么英特尔宣传的某些 Haswell AVX 延迟比 Sandy Bridge 慢 3 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35859449/

相关文章:

performance - 在内存中交换未对齐的 64 位值的字节的最快方法是什么?

performance - 在 x86-64 上,32 位应用程序比 64 位应用程序有性能优势吗?

image-processing - openCV 使用什么样的加速?怎么处理的这么快?

c++ SSE SIMD框架

x86 - 使用 AVX 最快实现指数函数

c++ - 如何在 linux asm 中正确地返回一个 double

c - 动态创建适当对齐的 C 结构内存内容

c++ - 英特尔 C++ 编译器 (19.0) 现在是否仅使用 Clang 前端(即已放弃 EDG)?

c - MPI 共享内存和四精度的段错误

c++ - 为什么 ARM NEON 不比普通 C++ 快?