当前位置: 首页 > 知识库问答 >
问题:

在骑士登陆时清除一个或几个ZMM注册表最有效的方法是什么?

张淳
2023-03-14

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

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

vpxorq  zmm0, zmm0, zmm0
vpxorq  zmm1, zmm1, zmm1
vpxorq  zmm2, zmm2, zmm2
vpxorq  zmm3, zmm3, zmm3

在AVX2上,如果我想清除YMM寄存器,VPXOR是最快的,比VXORPS快,因为VPXOR可以在多个单元上运行。

在AVX512上,ZMM寄存器没有VPXOR,只有VPXORQVPXORD。这是清除登记簿的有效方法吗?当我用vpxorq清除ZMM寄存器之前的值时,CPU是否足够聪明,不会对它们产生错误的依赖关系?

我还没有一个物理AVX512 CPU来测试--也许有人在骑士登陆上测试过?是否有发布的延迟

共有1个答案

罗翰
2023-03-14

最有效的方法是利用AVX隐式归零到VLMAX(最大向量寄存器宽度,由XCR0的当前值决定):

vpxor  xmm6, xmm6, xmm6
vpxor  xmm7, xmm7, xmm7
vpxor  xmm8, xmm0, xmm0   # still a 2-byte VEX prefix as long as the source regs are in the low 8
vpxor  xmm9, xmm0, xmm0

这些指令只有4个字节(2个字节的VEX前缀),而不是6个字节(4个字节的EVEX前缀)。请注意,即使目标是XMM8-XMM15,也使用了低8中的源寄存器来允许2字节的VEX。(当第二个源reg为x/ymm8-15时,需要一个3字节的VEX前缀)。是的,只要两个源操作数是相同的寄存器(我测试了它在Skylake上不使用执行单元),这仍然被认为是归零习惯用法。

除了代码大小影响之外,性能与Skylake-AVX512和KNL上的vpxord/q zmmvxorps zmm相同。(代码越小越好。)但是请注意,KNL有一个非常弱的前端,最大解码吞吐量只能勉强饱和向量执行单元,根据Agner Fog的microarch指南,通常是瓶颈。(它没有uop缓存或循环缓冲区,每个时钟的最大吞吐量为2条指令。而且,每个周期的平均读取吞吐量限制在16B。)

vpxor   xmm14, xmm0, xmm0
vpxor   xmm15, xmm0, xmm0
vpxord  zmm16, zmm16, zmm16     # or XMM if you already use AVX512VL for anything
vpxord  zmm17, zmm17, zmm17

EVEX前缀是固定宽度的,所以使用ZMM0不会有任何好处。

如果目标支持AVX512VL(Skylake-AVX512但不支持KNL),那么您仍然可以使用VPXORD xmm31,...,以便在将来将512B指令解码为多个UOP的CPU上获得更好的性能。

如果您的目标具有AVX512DQ(Skylake-AVX512但不是KNL),那么在为FP数学指令创建输入时使用vxorps,或者在任何其他情况下使用vpxord可能是个好主意。对Skylake没有影响,但一些未来的CPU可能会关心。如果总是使用vpxord更容易,就不必担心这个问题。

vpternlogd/q的这种特例在KNL或Skylake-AVX512上不是独立的特例,所以请尝试选择一个冷寄存器。不过,在SKL-AVX512上它是相当快的:根据我的测试,每时钟吞吐量为2。(如果您需要多个regs,请使用vpternlogd并复制结果,特别是如果您的代码将在Skylake上运行,而不仅仅是在KNL上运行)。

我选择了32位元素大小(vpxord而不是vpxorq),因为32位元素大小被广泛使用,如果一个元素大小要变慢,通常不是32位元素大小慢。例如,pcmpeqq xmm0,xmm0比Silvermont上的pcmpeqd xmm0,xmm0慢得多。pcmpeqw是生成all-one向量(前AVX512)的另一种方式,但gcc选择pcmpeqd。我很肯定,对于XOR归零,尤其是在没有掩码寄存器的情况下,这不会有什么不同,但如果您正在寻找选择VPXORDVPXORQ之一的理由,这是一个很好的理由,除非有人在任何AVX512硬件上发现真正的性能差异。

有趣的是,gcc选择vpxord,但是vmovdqa64而不是vmovdqa32

XOR归零在英特尔SNB系列CPU上根本不使用执行端口,包括Skylake-AVX512。(Todo:将其中一些内容纳入答案,并对其进行其他更新。)

但是在KNL上,我很确定XOR零化需要一个执行端口。两个向量执行单元通常可以跟上前端,因此在发出/重命名阶段处理XOR零化在大多数情况下不会产生性能差异。根据Agner Fog的测试,VMOVDQA64/VMOVAPS需要一个端口(更重要的是具有非零延迟),因此我们知道它不能处理问题/重命名阶段的端口。(它可以像Sandybridge一样,消除XOR零化,但不会移动。但我对此表示怀疑,因为没有什么好处。)

正如Cody指出的,Agner Fog的表表明,KNL在FP0/1上运行vxorps/dvpxord/q,吞吐量和延迟相同,假设它们确实需要端口。我假设这只适用于xmm/ymmvxorps/d,除非Intel的文档出错,并且EVEXvxorps zmm可以在KNL上运行。

Skylake上的旁路延迟延迟取决于它选择的端口,而不是使用的指令。也就是说,vaddps读取vandps的结果会有额外的延迟周期,如果vandps被调度到p0或p1而不是P5。有关表格,请参见英特尔的优化手册。更糟糕的是,这种额外的延迟永远适用,即使结果在读取之前在寄存器中存在数百个周期。它影响从另一个输入到输出的dep链,所以在这种情况下它仍然很重要。(托多:把我的实验结果写出来,贴在某个地方。)

 类似资料:
  • 用户注册 修改 index.ts import * as Koa from 'koa'; import * as OtherParser from 'koa-better-body'; import * as bodyParser from 'koa-bodyparser'; // import * as Router from 'koa-better-router'; import * as C

  • 我需要从Python 2.7中的对象列表中删除前n个元素。有没有一种不使用循环的简单方法?

  • 问题内容: 我有一个可能的子字符串的列表,例如。实际上,该列表包含数百个条目。 我正在处理一个字符串,我正在寻找的是找到这些子字符串中任何一个的第一次出现的索引。 澄清一下,结果是3,结果是4。 我还需要知道找到了哪个子字符串(例如,其在子字符串列表中的索引或文本本身),或者至少是匹配的子字符串的长度。 有很明显的暴力方式可以实现这一目标,我想知道是否有任何优雅的Python / regex解决方

  • 问题内容: 我们的Docker映像会发送封闭源代码,我们需要使用自己的私有Docker注册表将它们存储在安全的地方。我们搜索 具有简单身份验证层的部署私有docker注册中心的最简单方法 。 我发现 : 这种手动方式http://www.activestate.com/blog/2014/01/deploying-your-own-private-docker-registry 和基于stackb

  • 问题内容: 在JavaScript中串联N个对象数组的最有效方法是什么? 数组是可变的,结果可以存储在输入数组之一中。 问题答案: 如果要连接两个以上的数组,那么这样做是为了方便和可能的性能。 对于仅连接两个数组,可以使用接受多个包含要添加到数组中的元素的参数的事实来代替将一个数组中的元素添加到另一个数组的末尾而不产生新数组。使用它也可以代替它,但是这样做似乎没有性能优势。 在ECMAScript

  • 问题内容: 考虑数组 我可以做 但这需要找到所有对象才可以找到第一个。 有没有更有效的方法? 我一直在试图找出我是否可以传递参数,从而获取的第一个分类,而不是最后一次。 编辑关于[dup]。 有几个原因使这个问题不同。 该问题和答案涉及价值观的平等。这是关于。 这些答案都遭受我的答案面临的同一问题。注意,我提供了一个完全有效的答案,但强调了它的效率低下。我正在寻找解决效率低下的问题。 编辑有关第二