作者:扩散平衡 | 来源:互联网 | 2023-02-13 17:01
我正在生成一个合成C基准测试,旨在通过以下Python脚本导致大量的指令获取失败:
#!/usr/bin/env python
import tempfile
import random
import sys
if __name__ == '__main__':
functiOns= list()
for i in range(10000):
func_name = "f_{}".format(next(tempfile._get_candidate_names()))
sys.stdout.write("void {}() {{\n".format(func_name))
sys.stdout.write(" double pi = 3.14, r = 50, h = 100, e = 2.7, res;\n")
sys.stdout.write(" res = pi*r*r*h;\n")
sys.stdout.write(" res = res/(e*e);\n")
sys.stdout.write("}\n")
functions.append(func_name)
sys.stdout.write("int main() {\n")
sys.stdout.write("unsigned int i;\n")
sys.stdout.write("for(i =0 ; i <100000 ;i ++ ){\n")
for i in range(10000):
r = random.randint(0, len(functions)-1)
sys.stdout.write("{}();\n".format(functions[r]))
sys.stdout.write("}\n")
sys.stdout.write("}\n")
代码所做的只是生成一个C程序,该程序由许多随机命名的虚函数组成,这些函数依次以随机顺序调用main()
.我正在用CentOS 7下的gcc 4.8.5编译生成的代码-O0
.该代码在配备2x Intel Xeon E5-2630v3(Haswell架构)的双插槽机器上运行.
我感兴趣的是在分析从C代码编译的二进制文件时(而不是Python脚本,仅用于自动生成代码),理解perf报告的与指令相关的计数器.特别是,我正在观察以下计数器perf stat
:
说明
L1-icache-load- miss(缺少L1的指令提取,Haswell上的r0280)
r2424,L2_RQSTS.CODE_RD_MISS(指令提取错过L2)
rf824,L2_RQSTS.ALL_PF(所有L2硬件预取器请求,包括代码和数据)
我首先在BIOS中禁用了所有硬件预取器的代码,即
MLC Streamer禁用
MLC Spatial Prefetcher已禁用
DCU数据预取器已禁用
DCU指令预取器已禁用
结果如下(进程被固定到第二个CPU的第一个核心和相应的NUMA域,但我想这没有太大的区别):
perf stat -e instructions,L1-icache-load-misses,r2424,rf824 numactl --physcpubind=8 --membind=1 /tmp/code
Performance counter stats for 'numactl --physcpubind=8 --membind=1 /tmp/code':
25,108,610,204 instructions
2,613,075,664 L1-icache-load-misses
5,065,167,059 r2424
17 rf824
33.696954142 seconds time elapsed
考虑到上面的数字,我无法解释L2中如此大量的指令获取失误.我已经禁用了所有预取程序,L2_RQSTS.ALL_PF确认了这一点.但为什么我看到L2中的指令获取次数比L1i多两倍?在我的(简单)心理处理器模型中,如果在L2中查找指令,则必须先在L1i中查找.显然我错了,我错过了什么?
然后,我尝试在启用所有硬件预取程序的情况下运行相同的代码,即
启用MLC Streamer
启用MLC空间预取程序
DCU数据预取器已启用
DCU指令预取器已启用
结果如下:
perf stat -e instructions,L1-icache-load-misses,r2424,rf824 numactl --physcpubind=8 --membind=1 /tmp/code
Performance counter stats for 'numactl --physcpubind=8 --membind=1 /tmp/code':
25,109,877,626 instructions
2,599,883,072 L1-icache-load-misses
5,054,883,231 r2424
908,494 rf824
现在,L2_RQSTS.ALL_PF似乎表明发生了更多事情,虽然我预计预取器会更加激进,但我认为由于跳跃密集型工作负载和数据预取器,指令预取器严重受到考验与这种工作量没什么关系.但同样,L2_RQSTS.CODE_RD_MISS仍然太高,启用了预取器.
所以,总结一下,我的问题是:
禁用硬件预取程序后,L2_RQSTS.CODE_RD_MISS似乎远高于L1-icache-load-miss.即使启用了硬件预取程序,我仍然无法解释它.与L1-icache-load- miss相比,L2_RQSTS.CODE_RD_MISS计数如此之高的原因是什么?