CSAPP的缓存实验分为partA和partB
partA就是模拟一个缓存
难的不是处理缓存的思路,而是处理参数的思路,如何将参数、内容抽象成数据结构。
#include "cachelab.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define IDX(m,n,E) m * E + n
#define MAXSIZE 30
char input[MAXSIZE]; /* 保存每行的字符串 */
struct mCache{
int valid;//有效位
int tag;//标记位
int count;//最近访问次数
};
typedef struct mCache Cache;
int hit_count = 0, miss_count = 0, eviction_count = 0;
/* 将 16 进制转为 10 进制数 */
int hextodec(char c);
/* 反转二进制的 b 位,可以不需要 */
/* int converse(int n, int b); */
/* 缓存加载 */
void Load(int count, unsigned int setindex, unsigned int tag,
double s_pow, unsigned int E,
double b_pow, Cache *cache);
int main(int argc,char* argv[])
{
// const char *str = "Usage: ./csim [-hv] -s <num> -E <num> -b <num> -t "
// "<file>\nOptions:\n -h Print this help message.\n -v "
// "Optional verbose flag.\n -s <num> Number of set index "
// "bits.\n -E <num> Number of lines per set.\n -b <num> "
// "Number of block offset bits.\n -t <file> Trace file.\n\n"
// "Examples :\n linux> ./csim -s 4 -E 1 -b 4 -t "
// "traces/yi.trace\n linux> ./csim -v -s 8 -E 2 "
// "-b 4 -t traces/yi.trace\n ";
int opt = 0; /* 保存参数 */
unsigned int s = 0, E = 0, b = 0; /* 组的位数 每组行数 和 块数目的位数 */
double s_pow = 0, b_pow = 0; /* 组数 块数 */
char *t = ""; /* trace 文件 */
while((opt = getopt(argc, argv, "s:E:-b:-t:")) != -1) {
switch (opt) {
case 's' :
s = atoi(optarg);
s_pow = 1 << s;/* 组数 */
break;
case 'E' :
E = atoi(optarg);/* 每组行数 */
break;
case 'b':
b = atoi(optarg);
b_pow = 1 << b; /* 每行块数 */
break;
case 't':
t = optarg; /* trace 文件 */
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-hv] -s <num> -E <num> -b <num> -t <file>\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
Cache *cache = (Cache*)malloc(sizeof(Cache) * s_pow * E);
for(int i = 0; i < s_pow * E; ++i) {
cache[i].valid = 0;
cache[i].tag = 0;
cache[i].count = 0;
}
FILE *fp = fopen(t, "r"); /* 打开 trace 文件 */
int count = 0; /* 可以当作时间的计数,用于每次访问缓存时更新缓存行的计数 */
/* 分析 trace 文件的每一行 */
while(fgets(input,MAXSIZE,fp)) {
int op = 0; /* 需要访问缓存的次数 */
unsigned int offset = 0, tag = 0,
setindex = 0; /* 缓存行的块索引,tag 标记,组号 */
char c;
int cflag = 0; /* 是否有逗号的标记 */
unsigned int address = 0; /* 访问缓存的地址 */
count++; /* 计数 */
for(int i = 0; (c = input[i]) && (c != '\n');++i) {
if(c == ' ') continue;
else if(c == 'I') {
op = 0;
}else if(c == 'L') {
op = 1;
}else if(c == 'S') {
op = 1;
}else if(c == 'M') {
op = 2;
}else if(c == ',') {
cflag = 1;
}else {
if(cflag) {//逗号
;
}else {
address = (address << 4) + hextodec(c);
}
}
}
//计算offset
for(int i = 0; i < b; ++i) {
offset = (offset << 1) + (address & 0x1);
address >>= 1;
}
//计算组
for(int i = 0; i < s; ++i) {
setindex = (setindex << 1) + (address & 0x1);
address >>= 1;
}
tag = address;
if(op == 1) {
Load(count,setindex,tag,s_pow,E,b_pow,cache);
}else if(op == 2) {
Load(count,setindex,tag,s_pow,E,b_pow,cache);
++hit_count;
}
}
free(cache);
fclose(fp);
printSummary(hit_count, miss_count, eviction_count);
return 0;
}
void Load(int count, unsigned int setindex, unsigned int tag,
double s_pow, unsigned int E,
double b_pow, Cache *cache)
{
for(int i = 0; i < E; ++i) {
if(cache[IDX(setindex,i,E)].valid &&
tag == cache[IDX(setindex,i,E)].tag) {
cache[IDX(setindex,i,E)].count = count;
++hit_count;
return;
}
}
//缓存不命中
++miss_count;
for(int i = 0; i < E; ++i) {
if(!cache[IDX(setindex,i,E)].valid) {
cache[IDX(setindex,i,E)].valid = 1;
cache[IDX(setindex,i,E)].tag = tag;
cache[IDX(setindex,i,E)].count = count;
return;
}
}
int min_index = 0,max_count = 1000000000;
for(int i = 0; i < E; ++i) {
if(cache[IDX(setindex,i,E)].count < max_count) {
min_index = i;
max_count = cache[IDX(setindex,i,E)].count;
}
}
++eviction_count;
cache[IDX(setindex,min_index,E)].tag = tag;
cache[IDX(setindex,min_index,E)].count = count;
cache[IDX(setindex,min_index,E)].valid = 1;
return ;
}
int hextodec(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return 0;
}
参考资料:
Exely/CSAPP-Labs