Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
X86 AVX512中索引数组存储的最快方式?_X86_Avx_Avx512 - Fatal编程技术网

X86 AVX512中索引数组存储的最快方式?

X86 AVX512中索引数组存储的最快方式?,x86,avx,avx512,X86,Avx,Avx512,我对以下表格进行了操作: for (I=0;I<31;I++) { dst[index1[I]]=src1[I]; dst[index2[I]]=src2[I]; } 用于(I=0;I在当前的CPU上,AVX-512分散指令不是超快的,在Skylake-X上每个时钟周期少于一个64位元素,在Ice Lake1上刚好超过一个qword/时钟。手动分散应该比在64位分散指令中模拟128位分散更好,但如果你是c,你可以在两种方式下进行基准测试愤怒的 特别是如果索引可以在index1和ind

我对以下表格进行了操作:

for (I=0;I<31;I++)
{
 dst[index1[I]]=src1[I];
 dst[index2[I]]=src2[I];
}

用于(I=0;I在当前的CPU上,AVX-512分散指令不是超快的,在Skylake-X上每个时钟周期少于一个64位元素,在Ice Lake1上刚好超过一个qword/时钟。手动分散应该比在64位分散指令中模拟128位分散更好,但如果你是c,你可以在两种方式下进行基准测试愤怒的

特别是如果索引可以在index1和index2之间重叠(碰撞),则4个单独的128位存储几乎肯定比检查索引向量对之间的冲突要好。注意,如果
idx1[1]==idx2[0],从src1散射4x元素,然后从src2散射4x元素,将得到不同的最终结果
。按照原始源代码顺序,该dst元素将获得
src1[1]
,但如果您不小心,它将获得
src2[0]

对于128位元素,可能只需执行512位加载,并使用
vmovdqu xmm
(通过
\u mm512\u castsi512\u si128
\u mm\u storeu\u si128
)和3x
\u mm512\u extracti64x2\u epi64
(vextract64x2)存储进行手动分散

或者256位加载和
vmovdqu xmm
+
vextract128
存储。但是如果您在周围的代码中使用512位向量,您也可以在这里使用它们;您已经支付了CPU频率和执行端口关闭成本

如果您可以让编译器加载64位索引数据,并使用
mov-eax,edx
/
shr-rdx,32
,将32位的两部分分开,以保存内存加载/存储端口,这可能会很好。这可能与GNU C
typedef uint64_64_u属性((may_-alias,aligned(4));
有关


脚注1:例如,Skylake-X上的
vpscatterdq zmm
吞吐量为每11个循环一次,最佳情况。或冰湖上的吞吐量为每7个循环一次

这是每11个周期4倍128位存储。手动128位分散可能每2个周期至少1倍128位存储,甚至可能每时钟1次。或者在冰湖上更快,有2个存储端口和2个加载端口,以及更宽的前端

分散指令也是前端的大量UOP:SKX或ICL上分别为26或19


但只是为了好玩,模拟128位散射: 我们可以使用64位元素分散来模拟128位元素分散,例如
\u mm512\u i32scatter\u epi64
()。或者
\u mm512\u i64scatter\u epi64
(VPSCATTERQQ),如果您的索引需要为64位,则为加载索引节省内存带宽

生成一个索引向量,用于将连续的qword元素对存储到
index1[I]*2
index1[I]*2+1


分散中的比例因子只能是1、2、4或8,与x86索引寻址模式相同。如果您可以将“索引”存储为字节偏移量而不是元素偏移量,这可能有助于提高效率。否则,您必须先将每个索引输入向量加倍(将其添加到自身)

然后将其与递增的副本交错,可能与
vpermt2d

void scatter(char *dst, __m512i data_lo, __m512i data_hi, __m256i idx)
{
    idx = _mm256_add_epi32(idx,idx);
    __m256i idx1 = _mm256_sub_epi32(idx, _mm256_set1_epi32(-1));

    const __m256i interleave_lo = _mm256_set_epi32(11,3, 10,2, 9,1,  8,0);
    const __m256i interleave_hi = _mm256_set_epi32(15,7, 14,6, 13,5, 12,4);
    __m256i idx_lo = _mm256_permutex2var_epi32(idx, interleave_lo, idx1);  // vpermt2d
    __m256i idx_hi = _mm256_permutex2var_epi32(idx, interleave_hi, idx1);

    _mm512_i32scatter_epi64(dst, idx_lo, data_lo, 8);
    _mm512_i32scatter_epi64(dst, idx_hi, data_hi, 8);
}

显示它如何在循环中编译。(默认情况下,叮当声完全展开它。)

等等,所有数组都有128b元素,甚至索引?仅限x86-64有64位指针,那又有什么意义呢?或者你是说只有dst和2个源?如果index1/2是
无符号的uu int128
,你想在索引数组时截断它们的指针宽度吗?这是唯一有意义的事情。在我的回答中,我假设索引可能是32位以节省空间。我应该c更正此错误。索引数组元素为32位。