基于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进制表示

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。