基于gem5模拟trace的cache模拟器的实现
在做计算机体系结构的时候,模拟器是一个重要且又有效的工具。其中gem5集成了gem和m5的优点,使用起来比较简单和方便。其中包括了se模式和fs模式,se模式是在gem5运行我们已经编译好的程序,可以获取cache,cpu状态等数据,fs模式下可以模拟操作系统,我们可以将我们自己修改的linux内核加载到哥们上运行。下面介绍了使用gem5的se模式,运行编译好的ARM可执行文件。获取访存的trace,然后我们可以通过这些trace模拟cache,并以此获取cache命中率等数据信息。
首先使用gem5运行已经编译好的可执行文件,以hello为例
build/ARM/gem5.opt configs/example/se.py -c hello
为了获取运行的trace,需要添加一些运行的参数
build/ARM/gem5.opt --outdir=memaccess --debug-flags=MemoryAccess --debug-file=memoryaccess.out configs/example/se.py -c hello
命令参数解析:
--outdir=memaccess 指明生成的 memory-access trace 文件所存放的文件夹。
--debug-flags=MemoryAccess 指 明 要 获 得 什 么 trace, 我 们 此 处 指 定 要 获 得MemoryAccess 的 trace(注意大小写,否则 gem5 会提示不识别这个 flag)
--debug-file=memoryaccess.out 指 明 trace 文 件 的 名 称 。 此 处 为memoryaccess.out
此处为MemoryAccess的trace,我们还可以获得 MMC 和 DRAM的trace
Memoryaccess.out :(此文件相对较大,打开比较慢)
分成两部分:
第一部分:0---------------------------------0,tick 不增。
0 Tick:
此处显示的内容是把 hello 二进制程序“加载”到 gem5 的内存当中。
第二部分: 0--500--1000---------------------------end
0-500-1000,以 interval=500cycles 递增。此时就是实际程序逐条指令执行的过程。其中包括的信息和容易可以读懂。
在获取了该可执行文件的trace之后,也就知道了程序运行过程中具体的执行顺序,同时也知道了每一步具体执行的内存内容,包括IFetche读取指令,Write写数据,Read读数据等。
其中也包括了具体操作的物理地址。
下面就是cache模拟器的编写,我们使用4路组相连,blocksize默认大小为32Bytes,共4个组,下面是具体代码
#include<iostream> #include<cstdlib> #include<string.h> #include<string> #include<math.h> #include<fstream> using namespace std; typedef struct Cache { int index; int time; int dirty; }cache_t; int sets; int a; int blockSize; string l; cache_t **i_cache,**d_cache; string fileName; int i_num,wd_num,d_num,rd_num,i_hit,wd_hit,rd_hit; int stringToInt(string a) { int res = 0,now = 1; for(int i=a.size()-1;i>=0;i--) { if(a[i]>='a') res += (10+a[i]-'a')*now; else res += (a[i]-'0')*now; now *= 16; } return res; } void simu_i_cache(int sets1,int a1,int blockSize1,string l1,string fileName1) { sets = sets1; a = a1; blockSize = blockSize1; l = l1; fileName = fileName1; i_cache = new cache_t*[sets]; d_cache = new cache_t*[sets]; for(int i=0;i<sets;i++) { i_cache[i] = new cache_t[a]; memset(i_cache[i],-1,a*sizeof(cache_t)); d_cache[i] = new cache_t[a]; memset(d_cache[i],-1,a*sizeof(cache_t)); } } int findSet(int addr) { int res = addr>>(int)(log(blockSize)/log(2)); res %= sets; return res; } int findIndex(int addr) { int res = addr>>(int)(log(blockSize)/log(2)); res = res>>(int)(log(sets)/log(2)); return res; } bool visitICache(int addr) { int mySet = findSet(addr); int myIndex = findIndex(addr); for(int i=0;i<a;i++) { if(i_cache[mySet][i].index == myIndex) { return true; } } int maxTime=-1,insertIndex=-1,minTime = 1000000000;; for(int i=0;i<a;i++) { if(minTime>i_cache[mySet][i].time) { minTime = i_cache[mySet][i].time; insertIndex = i; } if(maxTime<i_cache[mySet][i].time) maxTime = i_cache[mySet][i].time; } i_cache[mySet][insertIndex].index = myIndex; i_cache[mySet][insertIndex].time = maxTime+1; return false; } bool visitDCache(int addr) { int mySet = findSet(addr); int myIndex = findIndex(addr); for(int i=0;i<a;i++) { if(d_cache[mySet][i].index == myIndex) { return true; } } int maxTime=-1,insertIndex=-1,minTime = 1000000000;; for(int i=0;i<a;i++) { if(minTime>d_cache[mySet][i].time) { minTime = d_cache[mySet][i].time; insertIndex = i; } if(maxTime<d_cache[mySet][i].time) maxTime = d_cache[mySet][i].time; } d_cache[mySet][insertIndex].index = myIndex; d_cache[mySet][insertIndex].time = maxTime+1; return false; } void readFile() { ifstream fin(fileName.c_str()); int type; string number; while(fin >> type >> number) { int addr = stringToInt(number); switch(type) { case 0: i_num++; if(visitICache(addr)) i_hit++; break; case 1: d_num++; rd_num++; if(visitDCache(addr)) rd_hit++; break; case 2: d_num++; wd_num++; if(visitDCache(addr)) wd_hit++; break; default: cout << "error"<< endl; } } cout << "instruction hit ratio "<<(double)i_hit/i_num << endl; cout << "write data hit ratio "<<(double)wd_hit/wd_num << endl; cout << "read data hit ratio "<<(double)rd_hit/rd_num << endl; } int main() { simu_i_cache(4,8,32,"LRU","output.txt"); readFile(); }
trace色输入文件是output.txt.即通过gem5模拟出来的trace。不过考虑到trace比较大,对trace做了预处理
output.txt实例
0 0xa94 1 0xa94 0 0xa98 0 0xa98 0 0xa9c 0 0xa9c 0 0xaa0 0 0xaa0 1 0x5edd4 0 0xaa4 0 0xaa4 0 0xaa8 0 0xaa8 0 0xaac 0 0xaac 2 0x5edd4 0 0xab0 0 0xab4
其中0代表代码读,1表示数据读,2表示数据写,后面是物理地址的16进制表示