如何解决AVX-512多核而不是单核的缓存命中率
以下是NASM程序的循环主体(循环主体表示我没有显示实例化内核和共享内存,读取输入数据,将最终结果写入文件的部分)。该程序是从C包装程序中调用的共享对象。显示了其中9条线的行号;它们与下面的注释中引用的行号相对应。
mov rax,255
kmovq k7,rax
label_401:
cmp r11,r10
jge label_899
vmovupd zmm14,[r12+r11] ;[185]
add r11,r9 ; stride ;[186]
vmulpd zmm13,zmm14,zmm31 ; [196]
vmulpd zmm9,zmm29 ; [207]
vmulpd zmm8,zmm13,zmm30
mov r8,1
Exponent_Label_0:
vmulpd zmm7,zmm29,zmm29
add r8,1
cmp r8,2 ;rdx
jl Exponent_Label_0
vmulpd zmm3,zmm7,zmm8
vsubpd zmm0,zmm9,zmm3
vmulpd zmm1,zmm0,zmm28
VCVTTPD2QQ zmm0{k7},zmm1 ; [240]
VCVTUQQ2PD zmm2{k7},zmm0 ; [241]
vsubpd zmm3,zmm1,zmm2
vmulpd zmm4,zmm3,zmm27 ; [243]
VCVTTPD2QQ zmm5{k7}{z},zmm4
VPCMPGTQ k2,zmm5,zmm26
VPCMPEQQ k3 {k7},zmm26
KADDQ k1,k2,k3
VCVTQQ2PD zmm2{k7},zmm0 ; [252]
vmulpd zmm1{k7},zmm2,zmm25
vmovupd zmm2,zmm1
VADDPD zmm2{k1},zmm25
vmovapd [r15+r14],zmm2 ; [266]
add r14,r9 ; stride
jmp label_401
该程序仅在第185行读取的数据之间使用AVX-512寄存器到寄存器指令,然后将最终结果写入第266行的共享内存缓冲区。我在1个核和4个核上运行了该指令,但4核版本比单核慢2-3倍。我使用Linux性能分析了它,以了解为什么多核AVX-512的速度比单核要慢2-3倍。
下面显示的perf报告是通过运行所有65个具有perf record / perf批注的PEBS计数器完成的-通过源代码行查看结果-通过perf stat获取全部计数。每个perf记录和perf stat计数器都是单独运行的,结果按源代码行进行汇总,来自perf stat的计数分别显示在下面。
每条指令后都有源代码行号。对于性能记录指令,它在源代码行中显示该计数器的百分比,并在每行末尾的括号中显示此类指令的总数(来自性能统计)。
我的主要问题是,为什么我们在AVX-512指令中看到的多核缓存命中率和未命中率都是寄存器到寄存器指令,而在单核上却没有相同的指令。对于完全在寄存器内的指令,不应有任何高速缓存命中或丢失。每个内核都有自己的一组寄存器,因此在指令全部为寄存器对寄存器的情况下,我不希望发生任何缓存活动。当仅使用单个内核运行时,我们几乎看不到所有寄存器指令中的缓存活动。
1. Line 186 - add r11,r9
mem_inst_retired.all_loads 75.00% (447119383)
mem_inst_retired.all_stores 86.36% (269650353)
mem_inst_retired.split_loads 71.43% (6588771)
mem_load_retired.l1_hit 57.14% (443561879)
Single core (line 177) - add r11,r9
mem_inst_retired.all_stores 24.00% (267231461)
该指令(加r11,r9)加两个寄存器。当使用单核时,我们看不到任何缓存命中/未命中或内存负载,但是使用多核时,我们可以看到。为什么这里有多核而不是单核的缓存命中和内存加载指令?
2. Line 196 - vmulpd zmm13,zmm31
mem_inst_retired.split_loads 28.57% (6588771)
mem_load_retired.fb_hit 100.00% (8327967)
mem_load_retired.l1_hit 14.29% (443561879)
mem_load_retired.l1_miss 66.67% (11033416)
Single core (line 187) - vmulpd zmm13,zmm31
mem_load_retired.fb_hit 187 100.00% (8889146)
该指令(vmulpd zmm13,zmm14,zmm31)是所有寄存器,但再次显示了L1命中,未命中以及使用多核而不是单核的负载分割。
3. Line 207 - vmulpd zmm9,zmm29
mem_load_retired.l1_hit 14.29% (443561879)
mem_load_retired.l1_miss 33.33% (11033416)
rs_events.empty_end 25.00% (37013411)
Single core (line 198):
mem_inst_retired.all_stores 24.00% (267231461)
mem_inst_retired.stlb_miss_stores 22.22%
此指令(vmulpd zmm9,zmm14,zmm29)与上述指令(vmulpd,所有寄存器)相同,但再次显示了L1命中,未命中以及使用多核而不是单核拆分负载。单核确实显示了第二级TLB丢失,并且存储了已退休的指令,但是没有缓存活动。
4. Line 240 - VCVTTPD2QQ zmm0{k7},zmm1
mem_inst_retired.all_loads 23.61% (447119383)
mem_inst_retired.split_loads 26.67% (6588771)
mem_load_l3_hit_retired.xsnp_hitm 28.07% (1089506)
mem_load_l3_hit_retired.xsnp_none 12.90% (1008914)
mem_load_l3_miss_retired.local_dram 40.00% (459610)
mem_load_retired.fb_hit 29.21% (8327967)
mem_load_retired.l1_miss 19.82% (11033416)
mem_load_retired.l2_hit 10.22% (12323435)
mem_load_retired.l2_miss 24.84% (2606069)
mem_load_retired.l3_hit 19.70% (700800)
mem_load_retired.l3_miss 21.05% (553670)
Single core line 231:
mem_load_retired.l1_hit 25.00% (429499496)
mem_load_retired.l3_hit 50.00% (306278)
此行(VCVTTPD2QQ zmm0 {k7},zmm1)是寄存器到寄存器。单核显示L1和L3活动,而多核显示更多的缓存活动。
5. Line 241 - VCVTUQQ2PD zmm2{k7},zmm0
mem_load_l3_hit_retired.xsnp_hitm 21.05% (1089506)
mem_load_l3_miss_retired.local_dram 10.00% (459610)
mem_load_retired.fb_hit 10.89% (8327967)
mem_load_retired.l2_miss 13.07% (2606069)
mem_load_retired.l3_miss 10.53%
Single core line 232:
Single core has no cache hits or misses reported
mem_load_retired.l1_hit 12.50% (429499496)
全寄存器指令(VCVTUQQ2PD zmm2 {k7},zmm0)显示了多核具有很多缓存活动,但单核只有少量L1命中(12.5%)。我不希望看到带有全寄存器指令的缓存命中/未命中或加载/存储指令。
6. Line 243 - vmulpd zmm4,zmm27
br_inst_retired.all_branches_pebs 12.13% (311104072)
Single core line 234:
mem_load_l3_hit_retired.xsnp_none 100.00% (283620)
为什么我们看到全寄存器mul指令的分支指令?
7. Line 252 - VCVTQQ2PD zmm2{k7},zmm0
br_inst_retired.all_branches_pebs 16.62% (311104072)
mem_inst_retired.all_stores 21.22% (269650353)
Single core line 243:
Single core also has branch instructions
br_inst_retired.all_branches_pebs 22.16% (290445009)
对于寄存器对寄存器指令(VCVTQQ2PD zmm2 {k7},zmm0),为什么我们看到分支指令?该指令不会分支,也不会在分支之前或之后。
8. Line 266 - vmovapd [r15+r14],zmm2
br_inst_retired.all_branches_pebs 43.56% (311104072)
mem_inst_retired.all_loads 48.67% (447119383)
mem_inst_retired.all_stores 43.09% (269650353)
mem_inst_retired.split_loads 41.30% (6588771)
mem_inst_retired.stlb_miss_loads 11.36% (487591)
mem_inst_retired.stlb_miss_stores 12.50% (440729)
mem_load_l3_hit_retired.xsnp_hitm 33.33% (1089506)
mem_load_l3_hit_retired.xsnp_none 56.45% (1008914)
mem_load_l3_miss_retired.local_dram 35.00% (459610)
mem_load_retired.fb_hit 39.60% (8327967)
mem_load_retired.l1_hit 48.75% (443561879)
mem_load_retired.l1_miss 51.65% (11033416)
mem_load_retired.l2_hit 71.51% (12323435)
mem_load_retired.l2_miss 45.10% (2606069)
mem_load_retired.l3_hit 59.09% (700800)
mem_load_retired.l3_miss 47.37% (553670)
Single core line 257:
mem_inst_retired.all_loads 84.86% (426023012)
mem_inst_retired.all_loads
mem_inst_retired.all_stores 59.28% (267231461)
mem_inst_retired.split_loads 89.92% (6477955)
mem_load_l3_miss_retired.local_dram 100.00% (372586)
mem_load_retired.fb_hit 92.80% (8889146)
mem_load_retired.l1_hit 54.17% (429499496)
mem_load_retired.l1_miss 91.30% (4170386)
mem_load_retired.l2_hit 100.00% (4564407)
mem_load_retired.l2_miss 100.00% (476024)
mem_load_retired.l3_hit 33.33% (306278)
此行(vmovapd [r15 + r14],zmm2)可能是最有可能影响单核与多核之间差异的线。在这里,我们将最终结果传输到所有内核共享的内存缓冲区。由于内存移动,我们希望看到多核和单核的缓存活动。单核使用通过malloc创建的单个缓冲区。对于多核,它是posix共享内存,因为它的运行速度比使用malloc创建的数组要快得多。
单核和多核都在2.30GHz的Intel Xeon Gold 6140 CPU上运行,该处理器具有两个用于AVX-512的FMA单元。
总而言之,我的问题是:(1)为什么我们在使用AVX-512多核而不是单核的寄存器对寄存器指令中看到缓存活动(少数情况除外); (2)有什么方法可以完全绕过vmovapd [r15 + r14],zmm2处的高速缓存并直接进入内存以避免高速缓存未命中吗? Posix共享内存是一项改进,但是并不能完全做到这一点。最后,还有其他原因导致多核AVX-512的速度比单核慢吗?
更新:此代码的访问模式由AVX决定-步幅为(64 x内核数)字节。对于4个内核,内核0从0开始,读取和处理64个字节,然后跳转256(64x4);核心1从64开始,读取和处理64个字节,然后跳转256,依此类推。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com(将#修改为@)