在英特尔 内在的webapp,从Sandy Bridge到Haswell,几项行动似乎已经恶化。例如,许多插入操作(如_mm256_insertf128_si256)显示如下的成本表:
Performance
Architecture Latency Throughput
Haswell 3 -
Ivy Bridge 1 -
Sandy Bridge 1 -
我发现这种差异令人费解。这有什么不同,因为有新的指令可以取代这些指令或补偿它的指令(哪些指令)?有谁知道Skylake是否进一步改变了这个模型?
TL:DR:所有车道交叉shuffle /插入/提取在Haswell / Skylake上有3c延迟,但在SnB / IvB上有2c延迟,根据 Agner Fog的测试。
这可能是执行单元中的1c +某种不可避免的旁路延迟,因为实际的执行单元在 通过Broadwell的SnB具有标准化的1,3或5个周期的延迟,而不是2或4个周期。 (SKL制作了一些uops uc 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的测量结果 表明SnB / IvB对reg-reg有2c延迟 vinsertf128
/vextractf128
虽然他对Haswell的测量(3c延迟,每1c输出一次)与英特尔的表一致。因此,英特尔内在指南中的数字是错误的另一种情况。 它非常适合寻找合适的内在数据,但不是可靠性能数据的良好来源。 它没有告诉你有关执行端口或总uop的任何信息,甚至经常忽略吞吐量数字。 无论如何,延迟通常不是向量整数代码中的限制因素。 这可能就是为什么英特尔让Haswell的延迟增加的原因。
reg-mem形式有很大不同。 vinsertf128 y,y,m,i
具有纬度/接收量:IvB:4/1,Haswell / BDW:4/2,SKL:5 / 0.5。它总是一个2-uop指令(融合域),使用一个ALU uop。 IDK为什么吞吐量如此不同。也许Agner的测试略有不同?
有趣的是, vextractf128 mem,reg, i
不使用任何ALU uops。它是一个2-fused-domain-uop指令,只使用存储数据和存储地址端口,而不是shuffle单元。 (Agner Fog的表将其列为在SnB上使用一个p015 uop,在IvB上使用0。但即使在SnB上,在任何特定列中都没有标记,因此IDK哪一个是正确的。)
这太愚蠢了 vextractf128
在立即操作数上浪费一个字节。我猜他们不知道他们将使用EVEX进行下一个向量长度扩展,并且正准备从0到3进行立即。但对于AVX1 / 2,你永远不应该使用immediate = 0来使用该指令。相反,只是 movups mem, xmm
要么 movaps xmm,xmm
。 (我认为编译器知道这一点,当你使用index = 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放弃了单独的添加单元,因此addps实际上从3c恶化到4c,但吞吐量增加了一倍。 (Haswell / BDW只做了每1c吞吐量一次的添加,是mul / fma的一半。)所以 在大多数FP算法中使用许多向量累加器是必不可少的 如果存在循环携带的依赖性,则一次保持8或10个FMA在飞行中以使吞吐量饱和。否则,如果循环体足够小,则无序执行将立即在飞行中进行多次迭代。
整数通道内操作通常只有1c延迟,因此您需要更少的并行度来最大化吞吐量(并且不受延迟限制)。
将数据输入/输出ymm的高半部分的其他选项都没有更好
vperm2f128
或AVX2 vpermps
比较贵。通过内存将导致存储转发失败 - >插入的大延迟(2个窄存储 - >宽负载),所以它显然很糟糕。不要试图避免 vinsertf128
在它有用的情况下。
一如既往,尽量使用最便宜的指令序列。例如对于水平总和或其他减少,总是首先减少到128b向量,因为跨车道改组是缓慢的。通常它只是 vextractf128
/ addps xmm
那么平常 水平128b。
正如Mysticial所提到的,Haswell以及后来对于128b向量具有SnB / IvB的一半的通道内矢量混洗吞吐量。 SnB / IvB可以 pshufb
/ pshufd
每0.5c吞吐量一个,但每1c只有一个 shufps
(即使是128b版本);对于在AVX1中具有ymm版本的其他shuffle也是如此(例如 vpermilps
,这显然只存在于FP load-and-shuffle可以在一条指令中完成。 Haswell完全摆脱了port1上的128b shuffle单元,而不是为AVX2扩展它。
回复:skylake
Agner Fog的指南/ insn表于12月更新,包括Skylake。另见 86 标记维基以获取更多链接。 reg,reg形式具有与Haswell / Broadwell相同的性能。