首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >vxorps-对AMD Jaguar/Bulldozer/Zen使用xmm寄存器的速度比ymm快吗?

vxorps-对AMD Jaguar/Bulldozer/Zen使用xmm寄存器的速度比ymm快吗?
EN

Stack Overflow用户
提问于 2017-05-01 01:53:05
回答 1查看 1.2K关注 0票数 12

AMD CPU通过解码成两个128 B操作来处理256 b AVX指令。例如,AMD上的vaddps ymm0, ymm1,ymm1解码为2个宏操作,其吞吐量是vaddps xmm0, xmm1,xmm1的一半.

XOR-零是一种特例(不依赖于输入,也不依赖于在Jaguar上,至少避免消耗物理寄存器文件条目,并且可以在发出/重命名时消除该寄存器中的movdqa,就像Bulldozer一直做的那样,甚至对于非零规则也是如此)。但是,是否已经足够早地检测到,vxorps ymm0,ymm0,ymm0 vxorps xmm0,xmm0,xmm0**仍然只解码到1宏op,性能与vxorps xmm0,xmm0,xmm0**?相同。(与** vxorps ymm3, ymm2,ymm1**)**不同)

或者,在已经解码成两个uop之后,独立检测会在以后发生吗?另外,对AMD CPU的矢量xor-零点仍然使用执行端口吗?在Intel-CPU上,Nehalem需要一个端口,但沙桥家族在发布/重命名阶段处理它。

阿格纳·福格的指示表没有列出这一特殊情况,他的微弓指南也没有提到uops的数量。

这可能意味着vxorps xmm0,xmm0,xmm0是实现_mm256_setzero_ps()的更好方法。

对于AVX512,_mm512_setzero_ps()也只使用VEX编码的零化成语来保存字节,而不是在可能的情况下使用EVEX。(即zmm0-15。vxorps xmm31,xmm31,xmm31仍然需要一个EVEX)。gcc/clang目前使用的是任意宽度的xor-零成语,而不是总是使用AVX-128。

报道为clang bug 32862和gcc bug 80636。MSVC已经使用了xmm。尚未向ICC报告,ICC也使用zmm regs进行AVX512零化。(虽然英特尔可能不介意改变,因为目前没有任何英特尔CPU的好处,只有AMD。如果他们能释放出一个低功耗的CPU,把向量分成两半,他们可能会。他们目前的低功耗设计(Silvermont)根本不支持AVX,只有SSE4。

我知道使用AVX-128指令对256 b寄存器进行归零的唯一可能的缺点是它不会在Intel CPU上触发256 b执行单元的预热。可能会击败试图让他们热身的C或C++黑客。

(256 b矢量指令在第一256 b指令之后的第一~56k循环中较慢。参见Agner‘中的Skylake部分)。如果调用一个返回noinline_mm256_setzero_ps函数并不是使执行单元热身的可靠方法,这可能是可以的。(没有AVX2仍然可以工作,避免任何负载(可能缓存丢失)是__m128 onebits = _mm_castsi128_ps(_mm_set1_epi8(0xff));

return _mm256_insertf128_ps(_mm256_castps128_ps256(onebits), onebits),它应该编译成pcmpeqd xmm0,xmm0,xmm0 / vinsertf128 ymm0,xmm0,1。对于您曾经调用过的用于在关键循环之前为执行单元进行热身(或保持温暖)的事情来说,这仍然是非常微不足道的。如果你想要可以内联的东西,你可能需要内联-asm。)

我没有AMD硬件,所以我不能测试这个。

如果有人有AMD硬件,但不知道如何测试,请使用perf计数器来计数周期(最好是know或uop或其他AMD调用的)。

这是我用来测试短序列的NASM/YASM源:

代码语言:javascript
复制
section .text
global _start
_start:

    mov     ecx, 250000000

align 32  ; shouldn't matter, but just in case
.loop:

    dec     ecx  ; prevent macro-fusion by separating this from jnz, to avoid differences on CPUs that can't macro-fuse

%rep 6
    ;    vxorps  xmm1, xmm1, xmm1
    vxorps  ymm1, ymm1, ymm1
%endrep

    jnz .loop

    xor edi,edi
    mov eax,231    ; exit_group(0) on x86-64 Linux
    syscall

如果您不在Linux上,可以用ret替换循环后的内容(退出syscall),并从C main()函数调用该函数。

nasm -felf64 vxor-zero.asm && ld -o vxor-zero vxor-zero.o组装,生成静态二进制文件。(或使用我在问答中发布了关于使用/不使用libc组装静态/动态二进制文件的脚本。)。

示例输出的i7-6700k (Intel Skylake),3.9GHz。(闲置几分钟后,我的机器才升到3.9GHz。)涡轮增压最高可达4.2或4.4GHz,启动后正常工作)。由于我使用的是perf计数器,所以这台机器运行的时钟速度并不重要。不涉及加载/存储或代码缓存错误,因此,所有事物的核心时钟周期的数量都是恒定的,不管它们有多长。

代码语言:javascript
复制
$ alias disas='objdump -drwC -Mintel'
$ b=vxor-zero;  asm-link "$b.asm" && disas "$b" && ocperf.py stat -etask-clock,cycles,instructions,branches,uops_issued.any,uops_retired.retire_slots,uops_executed.thread -r4 "./$b"
+ yasm -felf64 -Worphan-labels -gdwarf2 vxor-zero.asm
+ ld -o vxor-zero vxor-zero.o

vxor-zero:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:       b9 80 b2 e6 0e          mov    ecx,0xee6b280
  400085:       66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00    data16 data16 data16 data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]
  400094:       66 66 66 2e 0f 1f 84 00 00 00 00 00     data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]

00000000004000a0 <_start.loop>:
  4000a0:       ff c9                   dec    ecx
  4000a2:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000a6:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000aa:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000ae:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000b2:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000b6:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000ba:       75 e4                   jne    4000a0 <_start.loop>
  4000bc:       31 ff                   xor    edi,edi
  4000be:       b8 e7 00 00 00          mov    eax,0xe7
  4000c3:       0f 05                   syscall

(ocperf.py is a wrapper with symbolic names for CPU-specific events.  It prints the perf command it actually ran):

perf stat -etask-clock,cycles,instructions,branches,cpu/event=0xe,umask=0x1,name=uops_issued_any/,cpu/event=0xc2,umask=0x2,name=uops_retired_retire_slots/,cpu/event=0xb1,umask=0x1,name=uops_executed_thread/ -r4 ./vxor-zero

 Performance counter stats for './vxor-zero' (4 runs):

        128.379226      task-clock:u (msec)       #    0.999 CPUs utilized            ( +-  0.07% )
       500,072,741      cycles:u                  #    3.895 GHz                      ( +-  0.01% )
     2,000,000,046      instructions:u            #    4.00  insn per cycle           ( +-  0.00% )
       250,000,040      branches:u                # 1947.356 M/sec                    ( +-  0.00% )
     2,000,012,004      uops_issued_any:u         # 15578.938 M/sec                   ( +-  0.00% )
     2,000,008,576      uops_retired_retire_slots:u # 15578.911 M/sec                   ( +-  0.00% )
       500,009,692      uops_executed_thread:u    # 3894.787 M/sec                    ( +-  0.00% )

       0.128516502 seconds time elapsed                                          ( +-  0.09% )

+- 0.02%是因为我运行了perf stat -r4,所以它运行了我的二进制文件4次。

uops_issued_anyuops_retired_retire_slots是融合域( Skylake和Bulldozer家族中每个时钟的前端吞吐量限制为4)。这些统计数字几乎相同,因为没有分支错误预测(这导致投机性发布的uop被丢弃,而不是退休)。

uops_executed_thread是未融合域uop(执行端口)。xor-在Intel CPU上不需要任何零化。,所以实际上执行的只是dec和分支uop。(如果我们将操作数更改为vxorps,使其不仅仅是对寄存器进行零化,例如vxorps ymm2, ymm1,ymm0将输出写入下一个寄存器不读取的寄存器,那么执行的uop将与融合域uop计数相匹配。我们可以看到,每个时钟的吞吐量限制是三个vxorp。)

在500 m时钟周期中发出的2000 m融合域uops为每个时钟4.0 uop:实现了理论上最大的前端吞吐量。6* 250是1500,因此这些计数与Skylake解码vxorps ymm,ymm,ymm匹配到1个融合域uop。

在循环中有不同数量的uop,情况就不那么好了。例如,一个5 uop循环只以每个时钟3.75 uop发出。我有意选择了8 uop(当vxorps解码为单个uop时)。

禅宗的发行宽度为每周6次,因此它可以在不同的展开量下做得更好。(有关短循环的更多信息,其uop计数不是问题宽度的倍数,请参见这个问答,Intel SnB-系列uarches)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-03 05:32:36

xor‘’ing一个ymm寄存器本身在AMD Ryzen上生成两个微操作,而xor‘’ing一个xmm寄存器本身只生成一个微操作。因此,复制ymm寄存器的最佳方法是用它自己对相应的xmm寄存器进行xor,并依赖于隐式零扩展。

今天唯一支持AVX512的处理器是骑士登陆。它使用单个微操作进行xor‘’ing寄存器。通常情况下,通过将向量分成两部分来处理向量大小的新扩展。这发生在从64位到128位以及从128位到256位的转换中。未来一些处理器(来自AMD、Intel或任何其他厂商)很可能会将512位矢量分割成两个256位矢量,甚至四个128位矢量。因此,zmm寄存器为零的最佳方法是对128位寄存器本身进行xor,并依赖于零扩展。你说得对,128位VEX编码的指令要短一两个字节。

大多数处理器将寄存器本身的xor识别为独立于寄存器的先前值。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43713273

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档