首页 > 代码库 > gem5验证cache的不同映像方式对cache命中率的影响
gem5验证cache的不同映像方式对cache命中率的影响
陆续写些关于新书《自己动手写CPU》的博客,本篇主要是讲解 gem5验证cache的不同映像方式对cache命中率的影响。
cache的基本在http://blog.csdn.net/leishangwen/article/details/30049469中已有介绍,此处不再重复,只是简单介绍一下。
主要由三大部分组成:
- Cache存储体:存放由主存调入的指令与数据块。
- 地址转换部件:建立目录表以实现主存地址到缓存地址的转换。
- 替换部件:在缓存已满时按一定策略进行数据块替换,并修改地址转换部件。
地址映象:是指某一数据在内存中的地址与在缓冲中的地址,两者之间的对应关系。有三种地址映象的方式。
1、全相联方式
地址映象规则:主存的任意一块可以映象到Cache中的任意一块
(1) 主存与缓存分成相同大小的数据块。
(2) 主存的某一数据块可以装入缓存的任意一块空间中。
2、直接相联方式
地址映象规则: 主存储器中一块只能映象到Cache的一个特定的块中。
(1) 主存与缓存分成相同大小的数据块。
(2) 主存容量应是缓存容量的整数倍,将主存空间按缓存的容量分成区,主存中每一区的块数与缓存的总块数相等。
(3) 主存中某区的一块存入缓存时只能存入缓存中块号相同的位置。
3、组相联映象方式
组相联的映象规则:
(1) 主存和Cache按同样大小划分成块。
(2) 主存和Cache按同样大小划分成组。
(3) 主存容量是缓存容量的整数倍,将主存空间按缓冲区的大小分成区,主存中每一区的组数与缓存的组数相同。
(4) 当主存的数据调入缓存时,主存与缓存的组号应相等,也就是各区中的某一块只能存入缓存的同组号的空间内,但组内各块地址之间则可以任意存放, 即从主存的组到Cache的组之间采用直接映象方式;在两个对应的组内部采用全相联映象方式。
下面通过试验验证cache的不同映像方式对cache命中率的影响。采用的CPU模型是timeing,默认的dcache是64KB,缓存line大小是64B。观察下面的程序:
int main() { int i=0; long count=0; long temp[4096][8]; for(i=0;i<1000;i++) { temp[0][0]=count++; // 循环访问0,1024,2048 temp[1024][0]=count++; temp[2048][0]=count++; } }有一个二维数组temp,在C语言中,二维数组在内存中是按照行的次序在按照列的次序存放,也就是说,二维数组中同一行的数据在内存中是挨着的,但同一列的数据在内存中是分散的。所以,这个temp数组刚好对应4096个cache行,而数据cache实际只有64KB,共1024行,也就是说,这个数组中有多个元素会映射到cache的同一行,比如:temp[0][0]、temp[1024][0]、temp[2048][0]都会映射到cache的同一行。
上面的程序中,如果cache采用的是直接映射方式,那么会有大约1000*3次cache冲突,每次冲突都会替换cache,导致大约1000*3次cache reload,也会有大约1000*3次cache miss。
如果采用的是4路组相联的映射方式,那么temp[0][0]、temp[1024][0]、temp[2048][0]会被映射到cache不同的组中,从而避免了cache冲突,也就不会发生那么多次cache miss、cache reload,大约只有3次。
还是以我的开发环境为例,gem5安装在/root/gem5/gem5-stable-50ff05095970/路径下,修改tests/test-progs/hello/src目录下的hello.c,代码就是上面的代码。
使用如下命令编译(需要在/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/路径下执行下面的命令),其中有一个参数l1d_assoc=1,该参数制定了相联的组数为1,也就是直接相联方式。
./build/X86/gem5.opt ./configs/example/se.py --cpu-type=timing --caches --l1d_assoc=1 -c ./tests/test-progs/hello/src/hello
得到的统计结果在m5out/stats.txt中,找到其中的如下数据(数据cache写操作的缺失数):
system.cpu.dcache.WriteReq_misses::cpu.data 3092
再使用如下命令重新运行程序,其中参数l1d_assoc=4,该参数制定了相联的组数为4,也就是4路组相联方式。
./build/X86/gem5.opt ./configs/example/se.py --cpu-type=timing --caches --l1d_assoc=4 -c ./tests/test-progs/hello/src/hello得到的统计结果在m5out/stats.txt中,找到其中的如下数据(数据cache写操作的缺失数):
system.cpu.dcache.WriteReq_misses::cpu.data 93
从实验可知,对于测试程序而言,在4路组相联的cache下,可以大大减少cache miss的次数。
在实验中,产生了一个问题,百思不得其解,还盼哪位大神指点指点。问题是这样的,我们看下面的程序:
int main() { int i=0; long count=0; long temp[4096][8]; for(i=0;i<1000;i++) { temp[0][0]=count++; // 循环访问0,1024,2048,3072 temp[1024][0]=count++; temp[2048][0]=count++; temp[3072][0]=count++; // 比上面的测试程序多了这么一个赋值操作 } }
temp[0][0]、temp[1024][0]、temp[2048][0]、temp[3072][0]都会映射到cache的同一行,但是如果采用4路相联的cache,那么这四个值应该会被映射到不同的组中,这样按理说不会发生冲突,cache miss的次数大约是4次,但是实验结果显示是4000多次,不知道是什么原因。盼大神给解答。
gem5验证cache的不同映像方式对cache命中率的影响