英特尔Broadwell UOP融合技术用于AVX加载/存储指令

4

我正在尝试为内存绑定的向量化循环确定性能基线。我在一个32字节对齐的环境中使用Intel Broadwell芯片和AVX2指令。

基准循环每次使用8个YMM寄存器从一个位置加载数据并将其非时间地存储到另一个位置:

%define ptr
%define ymmword yword
%define SIZE 16777216*8 ;; array size >> LLC

align 32                ;; avx2 vector alignement

global _ls_01_opt

section .text

_ls_01_opt:             ;rdi is input, rsi output
  push rbp
  mov rbp,rsp

  xor rax,rax

  mov ebx, 111          ; IACA PREFIX
  db 0x64, 0x67, 0x90   ; 

  LOOP0:
    vmovapd ymm0, ymmword ptr [  (32) + rdi +8*rax]
    vmovapd ymm2, ymmword ptr [  (64) + rdi +8*rax]
    vmovapd ymm4, ymmword ptr [  (96) + rdi +8*rax]
    vmovapd ymm6, ymmword ptr [  (128) + rdi +8*rax]

    vmovapd ymm8, ymmword ptr  [  (160) + rdi +8*rax]
    vmovapd ymm10, ymmword ptr [  (192) + rdi +8*rax]
    vmovapd ymm12, ymmword ptr [  (224) + rdi +8*rax]
    vmovapd ymm14, ymmword ptr [  (256) + rdi +8*rax]

    vmovntpd ymmword ptr [  (32) + rsi +8*rax], ymm0
    vmovntpd ymmword ptr [  (64) + rsi +8*rax], ymm2
    vmovntpd ymmword ptr [  (96) + rsi +8*rax], ymm4
    vmovntpd ymmword ptr [  (128) + rsi +8*rax], ymm6

    vmovntpd ymmword ptr [  (160) + rsi +8*rax], ymm8
    vmovntpd ymmword ptr [  (192) + rsi +8*rax], ymm10
    vmovntpd ymmword ptr [  (224) + rsi +8*rax], ymm12
    vmovntpd ymmword ptr [  (256) + rsi +8*rax], ymm14

  add rax, (4*8)
  cmp rax, SIZE
  jne LOOP0


  mov ebx, 222          ; IACA SUFFIX
  db 0x64, 0x67, 0x90   ; 

  ret

我使用YASM进行汇编,并使用Intel Architecture Code Analyzer (IACA)进行测试,结果告诉我:
Throughput Analysis Report
--------------------------
Block Throughput: 8.00 Cycles       Throughput Bottleneck: PORT2_AGU, PORT3_AGU, Port4

Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
|  Port  |  0   -  DV  |  1   |  2   -  D   |  3   -  D   |  4   |  5   |  6   |  7   |
---------------------------------------------------------------------------------------
| Cycles | 0.5    0.0  | 0.5  | 8.0    4.0  | 8.0    4.0  | 8.0  | 0.5  | 0.5  | 0.0  |
---------------------------------------------------------------------------------------

N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis

| Num Of |                    Ports pressure in cycles                     |    |
|  Uops  |  0  - DV  |  1  |  2  -  D  |  3  -  D  |  4  |  5  |  6  |  7  |    |
---------------------------------------------------------------------------------
|   1    |           |     | 1.0   1.0 |           |     |     |     |     | CP | vmovapd ymm0, ymmword ptr [rdi+rax*8+0x20]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     | CP | vmovapd ymm2, ymmword ptr [rdi+rax*8+0x40]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     | CP | vmovapd ymm4, ymmword ptr [rdi+rax*8+0x60]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     | CP | vmovapd ymm6, ymmword ptr [rdi+rax*8+0x80]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     | CP | vmovapd ymm8, ymmword ptr [rdi+rax*8+0xa0]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     | CP | vmovapd ymm10, ymmword ptr [rdi+rax*8+0xc0]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     | CP | vmovapd ymm12, ymmword ptr [rdi+rax*8+0xe0]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     | CP | vmovapd ymm14, ymmword ptr [rdi+rax*8+0x100]
|   2    |           |     | 1.0       |           | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0x20], ymm0
|   2    |           |     |           | 1.0       | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0x40], ymm2
|   2    |           |     | 1.0       |           | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0x60], ymm4
|   2    |           |     |           | 1.0       | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0x80], ymm6
|   2    |           |     | 1.0       |           | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0xa0], ymm8
|   2    |           |     |           | 1.0       | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0xc0], ymm10
|   2    |           |     | 1.0       |           | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0xe0], ymm12
|   2    |           |     |           | 1.0       | 1.0 |     |     |     | CP | vmovntpd ymmword ptr [rsi+rax*8+0x100], ymm14
|   1    |           | 0.5 |           |           |     | 0.5 |     |     |    | add rax, 0x20
|   1    | 0.5       |     |           |           |     |     | 0.5 |     |    | cmp rax, 0x8000000
|   0F   |           |     |           |           |     |     |     |     |    | jnz 0xffffffffffffff78

我以为使用Broadwell处理器可以同时在2和3端口进行2倍负载。为什么不行呢?

谢谢。


更新

根据下面的建议,pd被替换为ps,并将地址合并到一个寄存器中,新代码如下:

%define ptr
%define ymmword yword
%define SIZE 16777216*8 ;; array size >> LLC

align 32                ;; avx2 vector alignement

global _ls_01_opt

section .text

_ls_01_opt:             ;rdi is input, rsi output
  push rbp
  mov rbp,rsp

  xor rax,rax
  xor rbx,rbx
  xor rcx,rcx

  or rbx, rdi
  or rcx, rsi


  mov ebx, 111          ; IACA PREFIX
  db 0x64, 0x67, 0x90   ; 

  LOOP0:
    vmovaps ymm0, ymmword ptr  [   (32) + rbx ]
    vmovaps ymm2, ymmword ptr  [   (64) + rbx ]
    vmovaps ymm4, ymmword ptr  [   (96) + rbx ]
    vmovaps ymm6, ymmword ptr  [  (128) + rbx ]

    vmovaps ymm8, ymmword ptr  [  (160) + rbx ]
    vmovaps ymm10, ymmword ptr [  (192) + rbx ]
    vmovaps ymm12, ymmword ptr [  (224) + rbx ]
    vmovaps ymm14, ymmword ptr [  (256) + rbx ]

    vmovntps ymmword ptr [   (32) + rcx], ymm0
    vmovntps ymmword ptr [   (64) + rcx], ymm2
    vmovntps ymmword ptr [   (96) + rcx], ymm4
    vmovntps ymmword ptr [  (128) + rcx], ymm6

    vmovntps ymmword ptr [  (160) + rcx], ymm8
    vmovntps ymmword ptr [  (192) + rcx], ymm10
    vmovntps ymmword ptr [  (224) + rcx], ymm12
    vmovntps ymmword ptr [  (256) + rcx], ymm14

  add rax, (4*8)
  add rbx, (4*8*8)
  add rcx, (4*8*8)
  cmp rax, SIZE
  jne LOOP0


  mov ebx, 222          ; IACA SUFFIX
  db 0x64, 0x67, 0x90   ; 

  ret

然后IACA告诉我:
Throughput Analysis Report
--------------------------
Block Throughput: 8.00 Cycles       Throughput Bottleneck: Port4

Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
|  Port  |  0   -  DV  |  1   |  2   -  D   |  3   -  D   |  4   |  5   |  6   |  7   |
---------------------------------------------------------------------------------------
| Cycles | 1.0    0.0  | 1.0  | 5.3    4.0  | 5.3    4.0  | 8.0  | 1.0  | 1.0  | 5.3  |
---------------------------------------------------------------------------------------

N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis

| Num Of |                    Ports pressure in cycles                     |    |
|  Uops  |  0  - DV  |  1  |  2  -  D  |  3  -  D  |  4  |  5  |  6  |  7  |    |
---------------------------------------------------------------------------------
|   1    |           |     | 1.0   1.0 |           |     |     |     |     |    | vmovaps ymm0, ymmword ptr [rbx+0x20]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     |    | vmovaps ymm2, ymmword ptr [rbx+0x40]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     |    | vmovaps ymm4, ymmword ptr [rbx+0x60]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     |    | vmovaps ymm6, ymmword ptr [rbx+0x80]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     |    | vmovaps ymm8, ymmword ptr [rbx+0xa0]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     |    | vmovaps ymm10, ymmword ptr [rbx+0xc0]
|   1    |           |     | 1.0   1.0 |           |     |     |     |     |    | vmovaps ymm12, ymmword ptr [rbx+0xe0]
|   1    |           |     |           | 1.0   1.0 |     |     |     |     |    | vmovaps ymm14, ymmword ptr [rbx+0x100]
|   2^   |           |     |           |           | 1.0 |     |     | 1.0 | CP | vmovntps ymmword ptr [rcx+0x20], ymm0
|   2^   |           |     |           |           | 1.0 |     |     | 1.0 | CP | vmovntps ymmword ptr [rcx+0x40], ymm2
|   2^   |           |     |           |           | 1.0 |     |     | 1.0 | CP | vmovntps ymmword ptr [rcx+0x60], ymm4
|   2^   |           |     |           |           | 1.0 |     |     | 1.0 | CP | vmovntps ymmword ptr [rcx+0x80], ymm6
|   2^   |           |     | 0.3       | 0.3       | 1.0 |     |     | 0.3 | CP | vmovntps ymmword ptr [rcx+0xa0], ymm8
|   2^   |           |     | 0.3       | 0.3       | 1.0 |     |     | 0.3 | CP | vmovntps ymmword ptr [rcx+0xc0], ymm10
|   2^   |           |     | 0.3       | 0.3       | 1.0 |     |     | 0.3 | CP | vmovntps ymmword ptr [rcx+0xe0], ymm12
|   2^   |           |     | 0.3       | 0.3       | 1.0 |     |     | 0.3 | CP | vmovntps ymmword ptr [rcx+0x100], ymm14
|   1    | 1.0       |     |           |           |     |     |     |     |    | add rax, 0x20
|   1    |           | 1.0 |           |           |     |     |     |     |    | add rbx, 0x100
|   1    |           |     |           |           |     | 1.0 |     |     |    | add rcx, 0x100
|   1    |           |     |           |           |     |     | 1.0 |     |    | cmp rax, 0x8000000
|   0F   |           |     |           |           |     |     |     |     |    | jnz 0xffffffffffffff7a

这告诉我,商店现在可以使用端口7来进行地址存储,并且操作已经存储。IACA告诉我,“块吞吐量”仍然为8个操作,因为需要额外的操作将地址存储到单个寄存器中。或许我的做法不对?

我仍然不理解为什么装载操作不能合并。


https://dev59.com/5-o6XIcBkEYKwwoYIAkf - Z boson
1个回答

5
端口7上的store-AGU只能处理“简单”的有效地址,因此您的存储器也需要在load端口上使用AGU。IACA显示您的负载实际上并不互相竞争;竞争的是存储器。
请注意,每个MOVNT存储器核心只有大约10个填充缓冲区,因此这些存储器将非常快地填满并成为瓶颈。
另见Micro fusion and addressing modes。如果您为存储器使用了一种寄存器寻址模式,则它们可以微融合并且需要较少的融合域uops。
此外,我想对于VEX编码指令,这并没有什么影响,但SSE pd版本需要一个额外的x86机器码字节。因为更短,所以clang倾向于对加载/存储使用movaps,即使在整数向量上也是如此。每个现有的CPU都运行movaps / movapd。因此,我建议只使用vmovaps / vmovntps。虽然它不会产生任何区别,但至少可以少设置一个VEX前缀的位。

感谢您的回复。我按照您下面的建议进行了更新,并成功将其用于存储操作的端口7,并获得了一些融合效果。但是我不明白为什么加载操作无法融合...也许我对此有误解。 - Gavin Portwood
纯负载指令不需要进行微融合。未融合的存储器是2个融合域uop。负载可以微融合到ALU uops中,例如addps xmm0,[rsi],但mov负载始终为1uop。它们利用了同一负载执行端口上的AGU和负载数据单元。如果您这样想,IACA永远不会在同一行显示两个指令。它列出uops,而不是周期数。 - Peter Cordes
@user2616417:此外,如果您愿意,可以继续使用索引寻址模式进行加载。 您的更新代码有三个循环计数器,但只使用其中两个。 您应该将其中一个指针与end-address进行cmp,并进行jb操作。 您可以使用rbx=src-dest,并从[rbx+rcx+offset]中进行加载,在循环中只需要一个加法操作。(由于mov-loads不需要微型熔合,因此没有问题使用2个寄存器寻址模式。)请参阅http://stackoverflow.com/a/35770938/224132,以获取此示例。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接