实验指导书
http://csapp.cs.cmu.edu/3e/cachelab.pdf
这里的LRU和之前上课学的不一样,首先会对地址进行哈希运算再LRU。
如果E=1,那就不是LRU了。
不需要真的保存数据,只需要计算hit, miss, eviction次数即可。
#include
#include
#include
#include
#include
#include "cachelab.h"
#include
int S, E, B;
int hit = 0, miss = 0, eviction = 0;//保存结果
/*
* valid是表示当前cacheLine是否已被使用,addr存放地址,time存放时间,从1开始
*/
typedef struct {
int valid;
long addr;
int time;
} cacheLine;
cacheLine *cache;
/*
* 返回1表示hit,2表示miss,4表示eviction,所以6表示miss和eviction
* 读入一条指令,可能为L,M,S。
* L与S的效果相同,首先对B取余数找到对应区间(在这里就是cache的第几行),然后遍历该行,
*(获取地址是否存在信息、存在的索引或最小索引、当前最大time)
* 看看地址是否存在,若存在则根据对应index更新time。
* 若不存在,则更新time最小的cacheLine。
*/
int readCacheLine(cacheLine *cache, char type, long addr);
void printHelp() {
printf("Usage: ./csim-wrc [-hv] -s -E -b -t \n"
"• -h: Optional help flag that prints usage info\n"
"• -v: Optional verbose flag that displays trace info\n"
"• -s : Number of set index bits (S = 2^s is the number of sets)\n"
"• -E : Associativity (number of lines per set)\n"
"• -b : Number of block bits (B = 2^b is the block size)\n"
"• -t : Name of the valgrind trace to replay\n" );
}
/*
* 返回0代表成功
* 1是读入参数错误
* 2是分配内存失败
* 3是打开文件失败
*/
int main(int argc, char *argv[]) {
opterr = 0;
int verboseFlag = 0;
int oc;
int error = 0;
int in = 0;
char *filePath = NULL;
while ((error == 0) && ((oc = getopt(argc, argv, "s:E:b:t:hv")) != -1)) {
in = 1;
switch (oc) {
case 's':
S = (int) pow(2, atoi(optarg));
break;
case 'E':
E = atoi(optarg);
break;
case 'b':
B = (int) pow(2, atoi(optarg));
break;
case 't':
filePath = optarg;
break;
case 'v':
verboseFlag = 1;
break;
case 'h':
case '?':
default:
error = 1;
printHelp();
break;
}
}
//输入错误时输出用法
if (in == 0 && oc == -1)
printHelp();
if (error == 0) {
FILE *file = fopen(filePath, "r");
if (file == NULL) {
printf("找不到文件");
return 3;
}
cache = (cacheLine *) malloc(S * E * sizeof(cacheLine));
if (cache == NULL) {
printf("内存分配失败");
return 2;
}
memset(cache, 0, S * E * sizeof(cacheLine));
char type;
int size;
long addr;
while (!feof(file)) {
int tr = fscanf(file, " %c %lx,%x", &type, &addr, &size);
if (tr != 3)
continue;
if (type != 'I') {
int rclResult = readCacheLine(cache, type, addr);
char *temp1 = NULL;
switch (rclResult) {
case 1:
hit++;
temp1 = "hit";
if (type == 'M')
hit++;
break;
case 2:
miss++;
temp1 = "miss";
break;
case 3:
miss++;
hit++;
temp1 = "miss";
break;
case 6:
miss++;
eviction++;
temp1 = "miss";
break;
case 7:
default:
miss++;
eviction++;
hit++;
temp1 = "miss";
break;
}
if (verboseFlag) {
printf("%c %lx,%x %s", type, addr, size, temp1);
if (rclResult == 6) {
printf(" eviction");
} else if (rclResult == 3) {
printf(" hit");
} else if (rclResult == 7) {
printf(" eviction hit");
} else if (rclResult == 1 && type == 'M') {
printf(" hit");
}
printf("\n");
}
}
}
free(cache);
cache = NULL;
printSummary(hit, miss, eviction);
}
// printSummary(0, 0, 0);
return error;
}
int readCacheLine(cacheLine *cache, char type, long addr) {
int result = 0;
int sIndex = (int) ((addr / B) % S);
int eIndex = 0, minTime = INT_MAX, maxTime = -1, exist = 0, insert = 0;
for (int i = 0; i < E; ++i) {
cacheLine *ptr = (cache + sIndex * E + i);
if (insert == 0 && result == 0) {
if (ptr->valid != 1) {
ptr->valid = 1;
ptr->addr = addr;
insert = 1;
exist = 0;
result = 2;
eIndex = i;
if (type == 'M')
result = 3;
//这里还不能break,要找到最大时间
} else {
//如果addr已存在,则索引为当前索引,否则为time最小的索引
if ((ptr->addr / B) == (addr / B)) {
exist = 1;
eIndex = i;
result = 1;
}
if (minTime > ptr->time) {
minTime = ptr->time;
if (exist == 0)
eIndex = i;
}
}
}
if (ptr->time > maxTime)
maxTime = ptr->time;
}
cacheLine *ptr = (cache + sIndex * E + eIndex);
//更新而不是插入
if (insert == 0) {
if (exist == 0) {
ptr->addr = addr;
result = 6;
if (type == 'M')
result = 7;
}
}
ptr->time = maxTime + 1;
return result;
}
已通过traces目录给出的用例测试