在英特尔 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, xmm
或 movaps 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。另见 x86标记 wiki 以获得更多链接。 reg,reg 形式与 Haswell/Broadwell 具有相同的性能。
关于x86-64 - 为什么英特尔宣传的某些 Haswell AVX 延迟比 Sandy Bridge 慢 3 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35859449/