avx512 具有任意步幅的跨步聚集
Posted
技术标签:
【中文标题】avx512 具有任意步幅的跨步聚集【英文标题】:avx512 strided gather with arbitrary stride 【发布时间】:2021-07-13 23:19:06 【问题描述】:我知道在 AVX512 中,您可以以 1、2、4、8 的步幅执行跨步聚集。但是,如果我的步幅可以在 10 到 1000 之间的任意位置怎么办?步幅在编译时是已知的。我知道指令不会成为瓶颈,内存可能会。 _mm512_set_ps 是最有效的方法吗?
【问题讨论】:
【参考方案1】:步幅为 1,2,4,8 的跨步聚集
不,对此没有特别的支持;也许你在考虑 ARM/ARM64 NEON vld4
4-way deinterleave?
在 x86 中,您可以使用 1、2、4 或 8 作为vpgatherdd
/ vpgatherdps
的索引向量的比例因子,但如果您只想要每个第二个元素,那就更好了手动洗牌(例如,_mm512_permutex2var_ps
从 2 个输入向量中获取备用浮点数),以一个宽负载获取许多有用的元素,而不是每个元素访问一次缓存。
但在您的情况下,最小步幅为 10,最多 2 个元素将来自同一个 16 x 32 位 512 位向量,并且步幅更宽,每个向量甚至没有一个。
所以你可以在循环中使用vpgatherdps
和_mm512_add_epi32(idx, _mm512_set1_epi32(16 * stride))
。 或者更好的是,只需使用固定的索引向量并递增基指针。您可以使用_mm512_mullo_epi32(_mm512_setr_epi32(0,1,2,3,...,15), _mm512_set1_epi32(stride))
生成该索引向量。由于浮点数为 4 字节宽,因此在集合中使用比例因子 4
。
即使您需要处理巨大的数组,递增指针而不是向量元素也可以避免对 64 位索引的任何需求,并最大限度地减少向量微指令的数量。 (在当前 CPU 上使用 512 位向量时很有价值。)
IIRC,英特尔的优化手册有一节关于跨步负载以及手动收集与使用收集指令之间的权衡。向量越宽,收集指令就会相对更好(2/时钟负载吞吐量,但对于大多数 shuffle 而言只有 1/时钟 shuffle 吞吐量),因此特别是对于 512 位向量,使用向量 shuffle 可能会胜出。
【讨论】:
与编写类似 _mm512_set_ps(input[a15],input[a14]...) 之类的东西相比,使用 _mm512_i32gather_ps 和您所描述的索引的效率如何? @bumpbump:这正是我要说的;如果您查看该_mm512_set_ps
的编译器 asm 输出,它将涉及大约 15 个 shuffle 指令;有些人可能设法使用像vmovhps
这样的内存源操作数,但它仍然必须将128 位块组合成256 位,然后用vinsertf32x8 组合它们。如果您不确定,请将其作为实际用例的一部分进行基准测试。
vpgatherdps
中的各个负载是否能够利用 ip 预取器?如果不是,也许标量 + vpsinrd
会更快获得更大的步幅?
@Noah:L2 预取器应该检测步幅模式;也许不是 L1d 预取器,我不知道。如果收集延迟不是循环承载的 dep 链的关键路径的一部分,OoO exec 可能会隐藏 L2-hit 延迟。或者,如果您遇到内存瓶颈(很可能即使在 L3 中很热,这取决于您对每个向量做了多少工作),那么您只想最小化 uops,以便 OoO exec 可以看到很好且很远的地方(跨越预取的页面边界也不行)。
@PeterCordes 你知道关于 OoO exec 如何与微码交互/微码中有多少 OoO exec 的资源吗?如果它的内存瓶颈无法想象vpgatherd
会因为 IP 预取器而更快,除非微码对 OoO exec 有一些优势。 AFAIK,除非您的瓶颈是 FE(不太可能有这样的紧密循环),否则 OoO exec 上的任何后端瓶颈都将只是来自vpgatherd
的微码 uops 作为正常负载的存在。还会担心 DSB/MITE 转换(循环中的一般微代码让我害怕)。以上是关于avx512 具有任意步幅的跨步聚集的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MATLAB 中以(恒定)任意步幅将图像平铺成(恒定)任意大小的补丁?