CSAPP-cachelab

大一时候还懵懵懂懂,现在能看懂了。有时候不是不懂,只是因为前置知识不够,得再学习一段时间。

CSAPP的缓存实验分为partA和partB

PartA

partA就是模拟一个缓存
难的不是处理缓存的思路,而是处理参数的思路,如何将缓存的参数(s,E,b)抽象,并用数据结构表达出来。这里实现的数据结构只涉及到组和行,而不涉及到块的处理。实际上也因为这里并不需要处理块。不过如果要处理块,也挺简单,再在数据结构里加个动态数据,根据偏移就可以找到了。

我参照github的来写的,先看懂思路然后自己摸索着写了出来,由于有些参数其实并不需要,我便把它删除了。

#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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值