gpt4 book ai didi

assembly - 在仅读取ZMM寄存器并写入k掩码的512位指令之后,Skylake是否需要vzeroupper来使turbo时钟恢复?

转载 作者:行者123 更新时间:2023-12-03 21:40:16 30 4
gpt4 key购买 nike

编写ZMM寄存器可以使Skylake-X(或类似的)CPU无限期地处于最大涡流降低的状态。 (SIMD instructions lowering CPU frequencyDynamically determining where a rogue AVX-512 instruction is executing)大概冰湖是相似的。

(解决方法:根据我在Is it useful to use VZEROUPPER if your program+libraries contain no SSE instructions?中引用的@BeeOnRope的评论,对于zmm16..31 来说不是问题。
因此,这个问题可能只适用于带有zmm16的vpxord xmm16,xmm16,xmm16vpcmpeqb。)

如果您有硬件,如何进行测试:

@BeeOnRope发布了test code in an RWT thread:将vbroadcastsd zmm15, [zero_dp]替换为vpcmpeqb k0, zmm0, [rdi]作为“脏污”指令,然后查看其后的循环运行缓慢还是快速。

我认为执行任何512位uop都会暂时触发减少的turbo(同时关闭向量ALU uops的端口1,而512位uop实际上在后端),但问题是:CPU能否在其上恢复如果您仅在读取ZMM寄存器后从未使用过vzeroupper,您是否拥有?

(和/或以后的SSE或AVX指令是否会有过渡惩罚或错误的依赖关系?)

具体来说,使用此类insns的strlen在返回之前是否需要vzeroupper(实际上可以在任何实际CPU上使用,和/或由Intel记录以证明其具有面向 future 的最佳实践。)假定以后的指令可能包括非VEX SSE和/或VEX编码的AVX1/2,而不仅仅是GP整数。这种情况与256以上的脏情况有关,从而使Turbo减少了。

; check 64 bytes for zero, strlen building block.
vpxor xmm0,xmm0,xmm0 ; zmm0 = 0 using AVX1 implicit zero-extension
vpcmpeqb k0, zmm0, [rdi] ; 512-bit load + ALU, not micro-fused
;kortestq k0,k0 / jnz or whatever

kmovq rax, k0
tzcnt rax, rax

;vzeroupper before lots of code that goes a long time before another 512-bit uop?

(受到 AVX512BW: handle 64-bit mask in 32-bit code with bsf / tzcnt?中strlen的启发,如果将其向量reg调零已正确优化以使用较短的VEX而不是EVEX指令,它将看起来像这样。)

关键指令是 vpcmpeqb k0, zmm0, [rdi],它在SKX或CNL上解码为2个单独的uops( not micro-fused: retire-slots = 2.0):512位负载(装入512位物理寄存器?)和ALU与掩码寄存器进行比较。

但是,没有架构性的ZMM寄存器曾经被显式写入,只能被读取。因此,假设至少有一个 xsave/ xrstor可以清除任何“脏污上限”条件,如果此条件之后还存在的话。 (在Linux上不会发生这种情况,除非在该内核上有实际的上下文切换到另一个用户空间进程,或者线程迁移了;仅进入内核进行中断不会导致它。因此,这实际上仍然可以在主流操作系统(如果您拥有硬件;我没有)。

我可以想象到的SKX/CNL和/或Ice Lake的可能性:
  • 无长期影响:max-turbo的恢复速度与vzeroupper一样快
  • 最大Turbo限制为512位速度,直到上下文切换为止。 (xrstor或同等功能会清除所有肮脏的上层状态标志,因为体系结构规则是干净的)。
  • 即使在上下文切换之间,Max turbo的最大速度也限制为512位,就像运行vaddps zmm0,zmm0,zmm0一样。 (肮脏的高位标志设置在已保存的状态中,并以架构状态恢复。)这是合理的,因为xsaveopt确实跳过了保存的128个或256个向量reg的上部(如果知道它们是干净的)。


  • 我假设 kmovq不会降低max turbo或触发其他512位uop效果。掩码寄存器的高32位通常仅与用于64字节向量的AVX512BW一起使用,但是大概它们不会单独对掩码寄存器的高32位(仅是向量寄存器的高32字节)进行电源门控。有一些用例,例如使用 kshiftkunpack处理64位掩码的块(用于加载/存储或传输到整数regs),即使您一次仅使用YMM或XMM的AVX512VL生成或使用32位掩码也是如此regs。

    PS:至强融核不受这些影响。在运行其他代码时,它不是要在不超过重型AVX512的情况下向上运行,因为它是为运行AVX512而设计的。实际上 vzeroupper非常慢,不建议在KNL/KNM上使用。

    我的示例使用AVX512BW的事实实际上与问题无关,但是所有带有AVX512的主流(非Xeon Phi)CPU都具有AVX512BW。它只是一个很好的实际用例,使用AVX512BW排除KNL的事实是无关紧要的。

    最佳答案

    ,如果您将vpcmpeqb寄存器用作比较项之一,则至少在SKX上,将zmm放入掩码寄存器不会触发慢速模式。

    对于仅读取 key 512位寄存器( key 寄存器为zmm0-zmm15)的任何其他指令(据我测试)也是如此。例如,vpxord zmm16, zmm0, zmm1也不会弄脏鞋面,因为虽然它涉及作为 key 寄存器的zmm1zmm0,但仅在写入不是 key 寄存器的zmm16时才从它们中读取。

    我在Xeon W-2104上使用avx-turbo对其进行了测试,该处理器的标称速度为3.2 GHz,L1 Turbo许可(AVX2 turbo)为2.8 GHz,L2许可(AVX-512 turbo)为2.4 GHz。在每次使用--dirty-upper进行测试之前,我都使用vpxord zmm15, zmm14, zmm15选项弄脏了鞋帮。如以下结果所示,这将导致所有使用所有SIMD寄存器(包括标量SSE FP)的测试均以较低的2.8 GHz速度运行(请参见A/M-MHz列中的cpu频率):

    CPUID highest leaf  : [16h]
    Running as root : [YES]
    MSR reads supported : [YES]
    CPU pinning enabled : [YES]
    CPU supports AVX2 : [YES]
    CPU supports AVX-512: [YES]
    cpuid = eax = 2, ebx = 266, ecx = 0, edx = 0
    cpu: family = 6, model = 85, stepping = 4
    tsc_freq = 3191.8 MHz (from calibration loop)
    CPU brand string: Intel(R) Xeon(R) W-2104 CPU @ 3.20GHz
    4 available CPUs: [0, 1, 2, 3]
    4 physical cores: [0, 1, 2, 3]
    Will test up to 1 CPUs
    Cores | ID | Description | OVRLP1 | OVRLP2 | OVRLP3 | Mops | A/M-ratio | A/M-MHz | M/tsc-ratio
    1 | pause_only | pause instruction | 1.000 | 1.000 | 1.000 | 2256 | 0.99 | 3173 | 1.00
    1 | ucomis_clean | scalar ucomis (w/ vzeroupper) | 1.000 | 1.000 | 1.000 | 790 | 1.00 | 3192 | 1.00
    1 | ucomis_dirty | scalar ucomis (no vzeroupper) | 1.000 | 1.000 | 1.000 | 466 | 0.88 | 2793 | 1.00
    1 | scalar_iadd | Scalar integer adds | 1.000 | 1.000 | 1.000 | 3192 | 0.99 | 3165 | 1.00
    1 | avx128_iadd | 128-bit integer serial adds | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx256_iadd | 256-bit integer serial adds | 1.000 | 1.000 | 1.000 | 2793 | 0.87 | 2793 | 1.00
    1 | avx512_iadd | 512-bit integer adds | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_iadd_t | 128-bit integer parallel adds | 1.000 | 1.000 | 1.000 | 8380 | 0.88 | 2793 | 1.00
    1 | avx256_iadd_t | 256-bit integer parallel adds | 1.000 | 1.000 | 1.000 | 8380 | 0.88 | 2793 | 1.00
    1 | avx128_mov_sparse | 128-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx256_mov_sparse | 256-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx512_mov_sparse | 512-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 2794 | 0.87 | 2793 | 1.00
    1 | avx128_merge_sparse | 128-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx256_merge_sparse | 256-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx512_merge_sparse | 512-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_vshift | 128-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx256_vshift | 256-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx512_vshift | 512-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_vshift_t | 128-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 5587 | 0.88 | 2793 | 1.00
    1 | avx256_vshift_t | 256-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 5588 | 0.88 | 2793 | 1.00
    1 | avx512_vshift_t | 512-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_imul | 128-bit integer muls | 1.000 | 1.000 | 1.000 | 559 | 0.88 | 2793 | 1.00
    1 | avx256_imul | 256-bit integer muls | 1.000 | 1.000 | 1.000 | 559 | 0.88 | 2793 | 1.00
    1 | avx512_imul | 512-bit integer muls | 1.000 | 1.000 | 1.000 | 559 | 0.88 | 2793 | 1.00
    1 | avx128_fma_sparse | 128-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx256_fma_sparse | 256-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx512_fma_sparse | 512-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx128_fma | 128-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 698 | 0.88 | 2793 | 1.00
    1 | avx256_fma | 256-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 698 | 0.87 | 2793 | 1.00
    1 | avx512_fma | 512-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 698 | 0.88 | 2793 | 1.00
    1 | avx128_fma_t | 128-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 4789 | 0.75 | 2394 | 1.00
    1 | avx256_fma_t | 256-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 4790 | 0.75 | 2394 | 1.00
    1 | avx512_fma_t | 512-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 2394 | 0.75 | 2394 | 1.00
    1 | avx512_vpermw | 512-bit serial WORD permute | 1.000 | 1.000 | 1.000 | 466 | 0.88 | 2793 | 1.00
    1 | avx512_vpermw_t | 512-bit parallel WORD permute | 1.000 | 1.000 | 1.000 | 1397 | 0.87 | 2793 | 1.00
    1 | avx512_vpermd | 512-bit serial DWORD permute | 1.000 | 1.000 | 1.000 | 931 | 0.87 | 2793 | 1.00
    1 | avx512_vpermd_t | 512-bit parallel DWORD permute | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00

    全速运行的唯一测试是根本没有使用SSE/AVX寄存器的 Scalar integer adds,以及在每次测试之前都具有显式 scalar ucomis (w/ vzeroupper)vzeroupper,因此不会在脏鞋帮上执行。

    然后,我将弄脏指令更改为您感兴趣的 vpcmpeqb k0, zmm0, [rsp]指令。新结果:
    Cores | ID                  | Description                     | OVRLP1 | OVRLP2 | OVRLP3 | Mops | A/M-ratio | A/M-MHz | M/tsc-ratio
    1 | pause_only | pause instruction | 1.000 | 1.000 | 1.000 | 2256 | 1.00 | 3192 | 1.00
    1 | ucomis_clean | scalar ucomis (w/ vzeroupper) | 1.000 | 1.000 | 1.000 | 790 | 1.00 | 3192 | 1.00
    1 | ucomis_dirty | scalar ucomis (no vzeroupper) | 1.000 | 1.000 | 1.000 | 790 | 1.00 | 3192 | 1.00
    1 | scalar_iadd | Scalar integer adds | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx128_iadd | 128-bit integer serial adds | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3190 | 1.00
    1 | avx256_iadd | 256-bit integer serial adds | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx512_iadd | 512-bit integer adds | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_iadd_t | 128-bit integer parallel adds | 1.000 | 1.000 | 1.000 | 9575 | 1.00 | 3192 | 1.00
    1 | avx256_iadd_t | 256-bit integer parallel adds | 1.000 | 1.000 | 1.000 | 9577 | 1.00 | 3192 | 1.00
    1 | avx128_mov_sparse | 128-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx256_mov_sparse | 256-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx512_mov_sparse | 512-bit reg-reg mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx128_merge_sparse | 128-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx256_merge_sparse | 256-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx512_merge_sparse | 512-bit reg-reg merge mov | 1.000 | 1.000 | 1.000 | 2793 | 0.88 | 2793 | 1.00
    1 | avx128_vshift | 128-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx256_vshift | 256-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx512_vshift | 512-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_vshift_t | 128-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 6386 | 1.00 | 3192 | 1.00
    1 | avx256_vshift_t | 256-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 6386 | 1.00 | 3192 | 1.00
    1 | avx512_vshift_t | 512-bit variable shift (vpsrld) | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00
    1 | avx128_imul | 128-bit integer muls | 1.000 | 1.000 | 1.000 | 638 | 1.00 | 3192 | 1.00
    1 | avx256_imul | 256-bit integer muls | 1.000 | 1.000 | 1.000 | 639 | 1.00 | 3192 | 1.00
    1 | avx512_imul | 512-bit integer muls | 1.000 | 1.000 | 1.000 | 559 | 0.88 | 2793 | 1.00
    1 | avx128_fma_sparse | 128-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx256_fma_sparse | 256-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 3193 | 1.00 | 3192 | 1.00
    1 | avx512_fma_sparse | 512-bit 64-bit sparse FMAs | 1.000 | 1.000 | 1.000 | 2793 | 0.87 | 2793 | 1.00
    1 | avx128_fma | 128-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 798 | 1.00 | 3192 | 1.00
    1 | avx256_fma | 256-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 798 | 1.00 | 3192 | 1.00
    1 | avx512_fma | 512-bit serial DP FMAs | 1.000 | 1.000 | 1.000 | 698 | 0.88 | 2793 | 1.00
    1 | avx128_fma_t | 128-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 6384 | 1.00 | 3192 | 1.00
    1 | avx256_fma_t | 256-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 5587 | 0.87 | 2793 | 1.00
    1 | avx512_fma_t | 512-bit parallel DP FMAs | 1.000 | 1.000 | 1.000 | 2394 | 0.75 | 2394 | 1.00
    1 | avx512_vpermw | 512-bit serial WORD permute | 1.000 | 1.000 | 1.000 | 466 | 0.87 | 2793 | 1.00
    1 | avx512_vpermw_t | 512-bit parallel WORD permute | 1.000 | 1.000 | 1.000 | 1397 | 0.88 | 2793 | 1.00
    1 | avx512_vpermd | 512-bit serial DWORD permute | 1.000 | 1.000 | 1.000 | 931 | 0.88 | 2793 | 1.00
    1 | avx512_vpermd_t | 512-bit parallel DWORD permute | 1.000 | 1.000 | 1.000 | 2794 | 0.88 | 2793 | 1.00

    现在,大多数测试都以全速运行。仍在2.8 GHz上运行的(对于并行512位FMA,一种情况下为2.4 GHz)是那些实际使用512位矢量,或使用256位矢量和较重的FP指令(如FMA)的设备。

    关于assembly - 在仅读取ZMM寄存器并写入k掩码的512位指令之后,Skylake是否需要vzeroupper来使turbo时钟恢复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58568514/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com