陆续写些关于新书《自己动手写CPU》的博客,本篇主要是讲解 gem5验证数组的缓存优化
软件优化是提高cache命中率的十分有效的手段,cache的基本原理是利用程序局部性,而软件优化可以通过提高程序局部性,从而提高cache命中率。举一个例子如下:
程序A:
#include <stdio.h> int main() { int i=0,j=0; long count=0; long temp[51200][8]; for(i=0;i<51200;i++) for(j=0;j<8;j++) { temp[i][j]=i*j; // 大约51200 次DCache缺失 } }在C语言中,二维数组在内存中是按照行的次序在按照列的次序存放,也就是说,二维数组中同一行的数据在内存中是挨着的,但同一列的数据在内存中是分散的。
假设数据cache的line size是64,long类型是8个字节,那么在程序A中,temp[i][0]-temp[i][7]刚好是64字节,占用数据cache的一个line,所以在写temp[i][0]将发生一次cache缺失,在写temp[i][1]-temp[i][7]的时候,不会发生数据缺失,所以,一共发生51200次缺失。
程序B:
#include <stdio.h> int main() { int i=0,j=0; long count=0; long temp[51200][8]; for(i=0;i<8;i++) for(j=0;j<51200;j++) { temp[j][i]=i*j; // 大约8*51200 次DCache缺失 } }仍然假设数据cache的line size是64,long类型是8个字节,那么在程序B中,是先按照列的次序访问,在按照行的次序访问,所以每次访问都会发生数据cache缺失,一共发生8*51200=409600次缺失。
下面我们通过gem5仿真验证上述分析是否正确。
还是以我的开发环境为例,gem5安装在/root/gem5/gem5-stable-50ff05095970/路径下,修改tests/test-progs/hello/src目录下的hello.c,如下:
#include <stdio.h> int main() { int i=0,j=0; long count=0; long temp[51200][8]; }使用如下命令编译(需要在/root/gem5/gem5-stable-50ff05095970/tests/test-progs/hello/src目录下执行下面的命令):
gcc --static hello.c -o hello然后使用前几次编译得到的X86对应的gem5.opt运行hello,并且选择CPU模型是Timing,也就是顺序流水线模型,命令如下(需要在/root/gem5/gem5-stable-50ff05095970/路径下执行下面的命令):
./build/X86/gem5.opt ./configs/example/se.py --cpu-type=timing --caches -c ./tests/test-progs/hello/src/hello得到的统计结果在m5out/stats.txt中,找到其中的如下数据(分别是执行时间和数据cache写操作的缺失数):
sim_seconds 0.000030 # Number of seconds simulated ...... system.cpu.dcache.WriteReq_misses::cpu.data 90
sim_seconds 0.013802 ...... system.cpu.dcache.WriteReq_misses::cpu.data 51290可见数据cache的缺失数增加了51200,符合我们前期的分析。
修改hello.c的代码为程序B,然后编译,并使用gem5.opt运行,再次打开stat.txt得到运行时间、数据cache的缺失数如下:
sim_seconds 0.031548 ...... system.cpu.dcache.WriteReq_misses::cpu.data 409688
原文地址:http://blog.csdn.net/leishangwen/article/details/43236295