问题标签 [avx512]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
2078 浏览

assembly - 在 Knights Landing 上清除单个或几个 ZMM 寄存器的最有效方法是什么?

说,我想清除 4 个zmm寄存器。

下面的代码会提供最快的速度吗?

在 AVX2 上,如果我想清除ymm寄存器,vpxor它是最快的,比 更快vxorps,因为vpxor可以在多个单元上运行。

在 AVX512 上,我们没有vpxorforzmm寄存器,只有vpxorqvpxord. 这是清除寄存器的有效方法吗?zmm当我用 清除寄存器时,CPU 是否足够聪明,不会对寄存器的先前值产生错误的依赖关系vpxorq

我还没有物理 AVX512 CPU 来测试它——也许有人在 Knights Landing 上测试过?是否有任何延迟发布

0 投票
1 回答
657 浏览

c++ - AVX2 中冲突检测的后备实现

AVX512CD 包含内在函数_mm512_conflict_epi32(__m512i a),它返回一个向量,如果位中的每个元素a具有相同的值,则在该向量中设置它。有没有办法在 AVX2 中做类似的事情?

我对确切的位不感兴趣,我只需要知道哪些元素是其左侧(或右侧)元素的副本。我只需要知道分散是否会发生冲突。

基本上我需要一个 AVX2 等价物

我能想到的唯一方法是使用_mm256_permutevar8x32_epi32()将每个值右移 1(跨通道),然后进行七次比较,屏蔽掉未使用的位,然后_mm256_or_si256()将它们放在一起,这非常慢。

0 投票
0 回答
292 浏览

c - avx512 寄存器串联?

我正在尝试有效地将内存中不同位置的 16 个 32 位值收集到 mm512i 向量中,以进行进一步的 32 位 SIMD 操作:

假设我有 16 个 32 位数据的缓冲区,其 16 个指针位于数组 c 中:

我想用这 16 个数组的内容(开始的第一个单词)初始化 _m512i 向量,并有一种有效的方法来移动我想使用 16*32 位 SIMD 操作处理的缓冲区数据。到目前为止,我已经写了以下内容:

我的主要问题当然是找到正确的内置函数来执行上面的连接(我称之为 __MM512_CONCAT)。但更一般地说,我想知道这是否是正确的方法。这要求我的所有缓冲区都位于 4GB 地址空间中(如果使用_mm512_i32gather_epi32()scale 参数并接受缓冲区对齐要求,则为 4GB 的倍数)。

为了进一步移动我的数据,我计划执行以下操作:

如果这不是从分散的地址空间初始化 16x32 (=512) 位向量的正确方法,他们应该怎么做?如果是,那么连接 256b 向量的正确方法是什么,以及在增量时间或增量时间将我的 64 位偏移量转换为 32 位时如何进行优雅的饱和度检查_mm512_cvtsepi64_epi32()

0 投票
1 回答
1562 浏览

c - 缺少掩码的 AVX-512 内在函数?

英特尔的内在函数指南列出了AVX-512 K* 掩码指令的一些内在函数,但似乎缺少一些:

  • KSHIFT{左/右}
  • KADD
  • 测试

英特尔开发人员手册声称内在函数不是必需的,因为它们是由编译器自动生成的。但是如何做到这一点?如果这意味着 __mmask* 类型可以被视为常规整数,那将很有意义,但测试类似的东西mask << 4似乎会导致编译器将掩码移动到常规寄存器,将其移位,然后移回掩码。这是使用Godbolt最新的 GCC 和 ICC 与-O2 -mavx512bw.

同样有趣的是,内在函数只处理__mmask16而不是其他类型。我没有进行太多测试,但看起来 ICC 不介意采用不正确的类型,但如果您使用内在函数,GCC 似乎确实会尝试确保掩码中只有 16 位。

我是否没有查看上述说明的正确内在函数以及其他 __mmask* 类型变体,还是有另一种方法可以在不诉诸内联汇编的情况下实现相同的目标?

0 投票
1 回答
206 浏览

intel - _mm512_storenr_pd 和 _mm512_storenrngo_pd

_mm512_storenrngo_pd_mm512_storenr_pd 有什么区别?

_mm512_storenr_pd(void * mt, __m512d v):

将压缩的双精度(64 位)浮点元素从 v 存储到内存地址 mt,并向处理器提供不读取提示。

我不清楚未读提示是什么意思。这是否意味着它是非缓存一致的写入。这是否意味着重用更昂贵或不连贯?

_mm512_storenrngo_pd(void * mt, __m512d v):

将压缩的双精度(64 位)浮点元素从 v 存储到内存地址 mt,并使用无读提示并使用弱排序内存一致性模型(使用此函数执行的存储不是全局排序的,后续存储从在他们之前可以观察到相同的线程)。

与 基本相同storenr_pd,但由于它使用弱一致性模型,这意味着进程可以在任何其他处理器之前查看自己的写入。但是另一个处理器的访问是不连贯的还是更昂贵?

0 投票
2 回答
745 浏览

intel - AVX512-CD的使用

我目前正在与 KNL 合作,并尝试了解 AVX512 的新机遇。除了扩展寄存器方面,AVX512 还带有新的指令集。冲突检测似乎很有希望。内在的

创建一个向量寄存器,包含给定源寄存器的无冲突子集:在此处输入图像描述

可以看到,一个值的第一次出现会在结果向量中的相应位置产生一个 0。如果该值多次出现,则结果寄存器保存一个零扩展值。到目前为止,一切都很好!但我想知道如何利用这个结果进行进一步的聚合或计算。我读到可以将它与前导零计数一起使用,但我认为这不足以确定子集的值。

有谁知道如何利用这个结果?

真挚地

0 投票
1 回答
307 浏览

x86 - 使用来自 avx-512 的分散存储

我有点好奇的行为

此内在函数应使用 idx 寄存器中的 32 位索引分散数据寄存器中的 32 位整数。只有在屏蔽寄存器中设置了相应的位时,才会存储一个值。按照官方文档,这些值从 base_addr 开始存储,并具有与 idx 寄存器相应的偏移量。Scale 用于缩放偏移量。

我的数据寄存器(data_reg)如下所示:

索引寄存器 (idx_reg) 如下所示:

掩码寄存器 (mask_reg) 如下所示:

我这样称呼内在:

结果数据(result_array)如下所示:

但它应该看起来像这样:

我错过了什么还是这种行为有点奇怪?

真挚地

0 投票
0 回答
70 浏览

gcc - AVX 确定写入值的数量

我有一个 512 位宽的向量寄存器(16 个值)和一个掩码,可以使用_mm512_mask_i32scatter_epi32(). 为了确定有多少值写入内存,我使用 . 计算掩码的前导零__builtin_clz()。如果掩码不是(!)为空,则一切正常。但是当面具为空时,会发生一些奇怪的事情:

掩码 = 0 clz(掩码) 31

我有两个问题:

  1. 有谁知道,为什么 clz 是 31 而不是 32?
  2. 有没有更好的方法来确定写入值的数量?

真挚地

0 投票
0 回答
899 浏览

x86 - 矢量加载/存储和收集/分散的每个元素原子性?

考虑一个像atomic<int32_t> shared_array[]. 如果你想 SIMD 矢量化for(...) sum += shared_array[i].load(memory_order_relaxed)怎么办?或者在数组中搜索第一个非零元素,或者将它的范围归零?这可能很少见,但考虑任何不允许在元素内撕裂但在元素之间重新排序的用例。 (也许是寻找 CAS 的候选人)。

认为x86 对齐的向量加载/存储在实践中用于 SIMDmo_relaxed操作是安全的,因为任何撕裂只会在当前硬件上最坏的情况下发生在 8B 边界(因为这就是使自然对齐的 8B 访问原子1的原因)。不幸的是,英特尔的手册只说:

“访问大于四字的数据的 x87 指令或 SSE 指令可以使用多个内存访问来实现。”

无法保证这些组件访问自然对齐、不重叠或其他任何内容。(有趣的事实:根据 Agner Fog 的说法, x87 10 字节的fld m80加载在 Haswell 上使用 2 个加载微指令和 2 个 ALU微指令完成,大概是 qword + word。)

如果您想以当前 x86 手册所说的适用于所有未来 x86 CPU 的面向未来的方式进行矢量化,您可以使用 / 加载/存储在 8B 块movqmovhps

或者,也许您可​​以将 256bvpmaskmovd与 all-true mask 一起使用,因为手册的 Operation 部分根据多个单独的 32 位加载来定义它,例如Load_32(mem + 4). 这是否意味着每个元素都充当单独的 32 位访问权限,从而保证该元素内的原子性?

(在真实硬件上,Haswell 上是 1 个负载和 2 个 port5 微指令,或者在 Ryzen 上只有 1 或 2 个负载 + ALU 微指令(128 / 256)。我认为这是针对不需要从元素中抑制异常的情况进入一个未映射的页面,因为这可能会更慢(但如果它需要微码辅助,则需要 IDK)。无论如何,这告诉我们它至少与vmovdqaHaswell 上的正常负载一样原子,但这并没有告诉我们关于 x86 Deathstation 9000 其中 16B / 32B 向量访问被分解为单字节访问,因此每个元素内都可能存在撕裂。

我认为实际上可以安全地假设您不会在任何真正的 x86 CPU 上看到对齐向量加载/存储的 16、32 或 64 位元素内的撕裂,因为这对于已经实现的高效实现没有意义必须保持自然对齐的 64 位标量存储原子,但有趣的是知道手册中的保证实际上能走多远。)


聚集 (AVX2,AVX512) / 分散 (AVX512)

像这样的指令vpgatherdd更明显地由多个单独的 32b 或 64b 访问组成。AVX2 表单被记录为做多个FETCH_32BITS(DATA_ADDR);,所以大概这被通常的原子性保证所涵盖,并且如果每个元素不跨越边界,它将被原子地收集。

AVX512 集合记录在英特尔的 PDF insn 参考手册
DEST[i+31:i] <- MEM[BASE_ADDR + SignExtend(VINDEX[i+31:i]) * SCALE + DISP]), 1) ,分别针对每个元素。(排序:元素可以按任何顺序收集,但故障必须按从右到左的顺序传递。内存排序和其他指令遵循 Intel-64 内存排序模型。)

AVX512 散点图记录方式相同(上一个链接的第 1802 页)。没有提到原子性,但它们确实涵盖了一些有趣的极端情况:

  • 如果两个或更多目标索引完全重叠,则可以跳过“较早”的写入。

  • 元素可以按任意顺序分散,但故障必须按从右到左的顺序传递

  • 如果该指令覆盖自身然后发生故障,则在交付故障之前只能完成元素的子集(如上所述)。如果故障处理程序完成并尝试重新执行该指令,则将执行新指令,并且分散不会完成。

  • 只有对重叠向量索引的写入才能保证相对于彼此进行排序(从源寄存器的 LSB 到 MSB)。请注意,这还包括部分重叠的向量索引。不重叠的写入可能以任何顺序发生。其他指令的内存排序遵循 Intel-64 内存排序模型。请注意,这不考虑映射到相同物理地址位置的非重叠索引。

(即因为相同的物理页面被映射到两个不同虚拟地址的虚拟内存中。因此允许在地址转换之前(或并行)发生重叠检测,而无需在之后重新检查。)

我包括了最后两个,因为它们是有趣的极端案例,我什至没有想过要怀疑它们。自我修改案例很有趣,尽管我认为rep stosd会有同样的问题(它也是可中断的,rcx用于跟踪进度)。

我认为原子性是 Intel-64 内存排序模型的一部分,所以他们提到它而不说其他任何东西的事实似乎意味着每个元素的访问是原子的。(收集两个相邻的 4B 元素几乎可以肯定不能算作一次 8B 访问。)


x86 手册保证哪些向量加载/存储指令在每个元素的基础上是原子的?

在真实硬件上进行的实验测试几乎肯定会告诉我,我的 Skylake CPU 上的一切都是原子的,而这不是这个问题的意义所在。 我在问我对手册的解释对于vmaskmov/vpmaskmov加载和收集/分散是否正确。

(如果有任何理由怀疑真正的硬件对于简单的movdqa负载将继续是元素级的原子,那也是一个有用的答案。)


  1. 脚注:x86 原子性基础知识:

根据 Intel 和 AMD 手册,在 x86 中,自然对齐的 8B 或更窄的加载和存储保证是原子的。事实上,对于缓存访问,任何不跨越 8B 边界的访问也是原子的。(在 Intel P6 和更高版本上提供比 AMD 更强的保证:在高速缓存行(例如 64B)内未对齐对于高速缓存访​​问是原子的)。

不保证 16B 或更宽的向量加载/存储是原子的。它们在某些 CPU 上(至少在观察者是其他 CPU 时用于缓存访问),但即使是对 L1D 缓存的 16B 宽的原子访问也不会使其成为原子的。例如,AMD K10 Opterons 的套接字之间的 HyperTransport 一致性协议在对齐的 16B 向量的两半之间引入了撕裂,即使对同一套接字(物理 CPU)中的线程进行测试显示没有撕裂。

(如果你需要一个完整的 16B 原子加载或存储,你可以lock cmpxchg16b像 gcc 那样破解一个std::atomic<T>,但这对性能来说很糟糕。另请参阅x86_64 上的原子双浮点或 SSE/AVX 向量加载/存储。)

0 投票
0 回答
815 浏览

performance - 新 AVX512 指令的成本 - 分散存储

我正在使用新的 AVX512 指令集,并尝试了解它们的工作原理以及如何使用它们。

我尝试的是交错由掩码选择的特定数据。我的小基准测试将 x*32 字节的对齐数据从内存加载到两个向量寄存器中,并使用动态掩码对它们进行压缩(图 1)。生成的向量寄存器分散到内存中,因此两个向量寄存器是交错的(图 2)。

压缩两个向量寄存器

图 1:使用相同的动态创建掩码压缩两个数据向量寄存器。

分散存储交错

图 2:分散存储以交错压缩数据。

我的代码如下所示:

我用

-O3 -march=knl -lmemkind -mavx512f -mavx512pf

我将此方法称为 100'000'000 个元素。为了真正了解分散存储的行为,我用不同的 maskCompress 值重复了这个测量。我预计执行所需的时间和 maskCompress 中设置的位数之间存在某种依赖性。但我观察到,测试需要大致相同的时间来执行。以下是性能测试的结果: 测量结果 图 3:测量结果。x 轴表示写入元素的数量,具体取决于 maskCompressed。y 轴显示性能。

可以看出,当更多的数据实际写入内存时,性能会变得更高。

我做了一些研究,得出了这个结论:avx512 的指令延迟。在给定的链接之后,所用指令的延迟是恒定的。但老实说,我对这种行为有点困惑。

关于 Christoph 和 Peter 的回答,我稍微改变了做法。因此,我不知道如何使用 unpackhi / unpacklo 来交错稀疏向量寄存器,我只是将 AVX512 压缩内在函数与 shuffle (vpermi) 结合起来:

这样,两个向量寄存器中的稀疏数据可以交错。不幸的是,我必须手动计算商店的掩码。这似乎相当昂贵。可以使用 LUT 来避免计算,但我认为这不是应该的方式。

存储性能 图 4:4 种不同商店的性能测试结果。

我知道这不是通常的方式,但我有 3 个与该主题相关的问题,我希望有人能帮助我。

  1. 为什么只有一个设置位的屏蔽存储需要与设置所有位的屏蔽存储相同的时间?

  2. 有没有人有一些经验或者是否有很好的文档来了解 AVX512 分散存储的行为?

  3. 有没有更简单或更高效的方法来交错两个向量寄存器?

谢谢你的帮助!

真挚地