如何解决在AVX512中索引数组存储的最快方法?
我的操作形式为:
for (I=0;I<31;I++)
{
dst[index1[I]]=src1[I];
dst[index2[I]]=src2[I];
}
所有数据数组都有128b个元素。 [编辑]
我不确定在AVX512中实现它的最佳方法是什么。我可以将源加载到zmm寄存器中,但此后我能做的最好的事情是使用提取和128b存储。有什么建议吗?
解决方法
在当前的CPU上,AVX-512分散指令不是非常快,在Skylake-X上每个时钟周期少于一个64位元素,在Ice Lake上仅超过1个qword /时钟
特别是如果索引可以在index1和index2之间重叠(碰撞),则几乎可以肯定4个独立的128位存储要比检查索引向量对之间的冲突好。请注意,从中分散4x个元素如果library(tidyverse)
rdf1 <- Df_2 %>%
left_join(Df_1,by = 'value') %>%
group_by(ID.x) %>%
mutate(keep = !any(is.na(ID.y))) %>%
ungroup
# > rdf1
# # A tibble: 6 x 4
# ID.x value ID.y keep
# <chr> <chr> <chr> <lgl>
# 1 y A x FALSE
# 2 y B x FALSE
# 3 y D NA FALSE
# 4 z A x TRUE
# 5 z B x TRUE
# 6 z C x TRUE
rdf1 %>% filter(keep)
,则src1和src2中的4x元素将给出不同的最终结果。按照原始的源顺序,该dst元素将得到idx1[1] == idx2[0]
,但是如果您不小心,它将得到src1[1]
。
使用128位元素,可能只进行512位加载,并通过src2[0]
(通过vmovdqu xmm
/ _mm512_castsi512_si128
)和3x {{ 1}}(VEXTRACTI64x2)商店。
或256位加载和_mm_storeu_si128
+ _mm512_extracti64x2_epi64
存储。但是,如果在周围的代码中使用512位向量,则最好在此处使用它们;您已经在支付CPU频率和执行端口关闭费用。
如果可以让编译器执行64位索引数据加载,并用vmovdqu xmm
/ vextracti128
分开32位一半,以节省内存加载/存储端口,那可能会很好。 。使用GNU C mov eax,edx
可能是可行的。
脚注1 :例如在最佳情况下,Skylake-X上的shr rdx,32
的吞吐量为每11个周期1个。或在冰湖上,每7个周期1个。 https://uops.info/
因此,每11个周期有4个128位存储。手动128位分散可能每2个周期至少存储1x 128位存储,甚至每个时钟1次。甚至在Ice Lake上,它有2个存储端口
对于前端来说,分散指令也有很多用法:分别在SKX或ICL上为26或19。
但只是为了好玩,模拟128位分散:
我们可以使用诸如typedef uint64_t aliasing_u64 __attribute((may_alias,aligned(4)));
(VPSCATTERDQ)这样的64位元素散点来模拟128位元素散点。如果您的索引需要为64位,则可以使用vpscatterdq zmm
(VPSCATTERQQ),否则可以节省用于加载索引的内存带宽。
生成索引向量,该向量将连续的qword元素对存储到_mm512_i32scatter_epi64
和_mm512_i64scatter_epi64
。
散点图中的比例因子只能是1,2,4或8,与x86索引寻址模式相同。如果您可以将“索引”存储为字节偏移量而不是元素偏移量,则可能会提高效率。否则,您必须首先将每个索引输入向量加倍(通过将其自身添加)。
然后将其与增量副本(可能与index1[I]*2
index1[I]*2 + 1
https://godbolt.org/z/TxzjWz显示了它如何循环编译。 (默认情况下,clang会完全展开它。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。