Cache缓存

缓存CACHE

一、基础知识
c语言中文件读取的顺序需要先打开文件,然后再进行读取操作
1.不带缓冲的文件打开读取
    File* fp;
	fp=fopen(char* filename,char* mode);
	char * fgets (char *s, int size, FILE *fp);
2.带有缓冲的文件打开读取(更加安全),经常使用。返回的是一个文件指针,指向文件读写的起始位置。
    File* fp;
	fp=fopen(char* filename,char* mode);
	char * fgets (char *s, int size, FILE *fp);
	fscanf可以按照特定格式进行读取

Cache相关理解:
1)Cache是由硬件进行管理的,设计cache的目的是能够让最常访问的数据集中在访问速度最快的缓存中,使得alu读写数据速度快,效率高。
一个Cache可以看成是一个二维数组,这个数组内的元素就是一个cache_line结构体,这个cache_line结构体内部保存的有一个valid bit,一些tag bits,以及一个2^b bytes大小的数据块,这个数据块是连续的。

在这里插å¥å›¾ç‰‡æè¿°

二、CACHE LAB
cache lab
目标:做一个缓存模拟器,命令行执行,对-t后面界的文件内容进行解析,打印出命中数,非命中数以及页面驱赶数(即发生页面置换后,被驱逐的次数)。
Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>
• -h: Optional help flag that prints usage info
• -v: Optional verbose flag that displays trace info
• -s <s>: Number of set index bits (S = 2s is the number of sets)
• -E <E>: Associativity (number of lines per set)
• -b <b>: Number of block bits (B = 2b is the block size)
• -t <tracefile>: Name of the valgrind trace to replay

-t 文件的内容格式:
I 0400d7d4,8
M 0421c7f0,4
L 04f6b868,8
S 7ff0005c8,8

[space]operation address,size

I:代表指令,直接跳过,忽略即可。
S:代表存储,需要执行一次命中判断
M:代表修改,需要执行两次命中判断
L:代表加载,需要执行一次命中判断

//第一版本
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
const int maxi=999;


typedef struct{
	unsigned int valid;//有效位
	unsigned int tag_bit;//标识位
	int time_stamp;
} cache_line,*cache_asso,**cache;


cache _cache;
int hits=0;int evictions=0;int mises=0;

int getNum(char* str,int n);
void parse_command(char* argc[],int* S,int* E,int* b,char* filename,int* isVerbose);
void init(int S,int E);
void parse_addr(unsigned int addr);
void parse_trace(char* filename,int S,int E,int s,int b,int isVerbose);
/*
使用LRU算法来寻找victim,LRU算法在具体实现的时候,
可以用权重来看,每一次访问时权重增加1,最终要被
替换的是权重最轻的那一个line
*/

int getNum(char* str,int n){
	int sum=0;
	for(int i=0;i<n;i++){
		sum+=sum*10+str[i]-'0';
	}
	return sum;
}

/*
Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>
• -h: Optional help flag that prints usage info
• -v: Optional verbose flag that displays trace info
• -s <s>: Number of set index bits (S = 2^s is the number of sets)
• -E <E>: Associativity (number of lines per set)
• -b <b>: Number of block bits (B = 2b is the block size)
• -t <tracefile>: Name of the valgrind trace to replay
*/

void parse_command(char* argc[],int* s,int* E,int* b,char* filename,int* isVerbose){
	if(strcmp(argc[1],"-v")==0) {
		*isVerbose=1;
		(*s)=getNum(argc[3],strlen(argc[3]));
		(*E)=getNum(argc[5],strlen(argc[5]));
		(*b)=getNum(argc[7],strlen(argc[7]));
		filename=argc[9];
	} else{
		*isVerbose=0;
		(*s)=getNum(argc[2],strlen(argc[2]));
		(*E)=getNum(argc[4],strlen(argc[4]));
		(*b)=getNum(argc[6],strlen(argc[6]));
		filename=argc[8];
	}
}


void init(int S,int E){
	_cache=(cache)malloc(sizeof(cache_asso)*S);
	for(int i=0;i<S;i++){
		_cache[i]=(cache_asso)malloc(sizeof(cache_line)*E);
		for(int j=0;j<E;j++){
			_cache[i][j].tag_bit=0;
			_cache[i][j].valid=0;
			_cache[i][j].time_stamp=0;
		}
	}

}

/*
memory address format:
高位                 低位
tag == sets_index == block_offset
  t          s          b
命中的原则是:
	1.设置了有效位 
	2.请求地址的标记位与cache地址的标位一致
*/

int bi2decimal(unsigned int sets_index){
	int sum=0;
	while(sets_index){
		sum=sum*2+sets_index%10;
		sets_index=sets_index/10;
	}
	return sum;
}

void exec(unsigned int tag,unsigned int sets_index,int E,int isVerbose){
	int index=bi2decimal(sets_index);
	cache_asso asso=_cache[index];
	for(int i=0;i<E;i++){
		if(asso[i].valid==1 && asso[i].tag_bit==tag){
			asso[i].time_stamp++;
			hits++;
			if(isVerbose) printf("hits\n");
			return;
		}
	}
	if(isVerbose) printf("mise ");
	mises++;
	for(int i=0;i<E;i++){
		if(asso[i].valid==0){
			asso[i].valid=1;
			asso[i].tag_bit=tag;
			asso[i].time_stamp=0;
			printf("\n");
			return;
		}
	}
	int victim_index=-1;int victim_stamp=maxi;
	for(int i=0;i<E;i++){
		if(victim_stamp>asso[i].time_stamp){
			victim_stamp=asso[i].time_stamp;
			victim_index=i;
		}
	}
	evictions++;
	asso[victim_index].tag_bit=tag;
	printf("evict\n");
}


void parse_trace(char* filename,int S,int E,int s,int b,int isVerbose){	
	FILE* fp;
	fp = fopen(filename,"r");
	if(fp==NULL) printf("Error reading file!");
	char op;unsigned int addr;unsigned int offset;
	while(fscanf(fp," %c %d,%d",&op,&addr,&offset)!=EOF){
		unsigned int tag=addr>>(s+b);
		unsigned int sets_index=(addr>>b)&( (unsigned int) (pow(2,s)-1) );
		if(op=='I') continue;
		else if(op=='L') {
			if(isVerbose) printf("%c %d ",op,addr);
			exec(tag,sets_index,E,isVerbose);
		}
		else if(op=='M') {
			if(isVerbose) printf("%c %d ",op,addr);
			exec(tag,sets_index,E,isVerbose);
			exec(tag,sets_index,E,isVerbose);
		} 
		else continue;
		// printf("%c,%d,%d",op,addr,offset);
	}
	fclose(fp);
	for(int i=0;i<S;i++){
		free(_cache[i]);
	}
	free(_cache);
}


int main(int argv,char* argc[]){
	if(argv==1){
		printf("Wrong input!");
		return 0;
	}
	int s;int E;int b;int isVerbose;char filename[maxi];
	parse_command(argc,&s,&E,&b,filename,&isVerbose);
	printf("%s",filename);
	
	int S=pow(2,s);int B=pow(2,b);
	/*test for function parse_command; 
	printf("%d,%d,%d,%d,%s",S,E,B,isVerbose,filename);
	*/

	init(S,E);

	/*test for function init; 
	for(int i=0;i<S;i++){
		for(int j=0;j<E;j++){
	 		printf("%d,%d\n",_cache[i][j].tag_bit,_cache[i][j].valid);
		}
	}
	*/
	
	/*
	test for function bi2decimal 
	printf("%d\n",bi2decimal(11));
	*/
	
	parse_trace(filename,S,E,s,b,isVerbose);
	printf("hits:%d, evictions:%d, mises:%d",hits,evictions,mises);
	return 0;
}
第一版本测试后,出现报错,报错如下图所示。出现段错误报错,初步怀疑是filename读取的问题。尝试放弃自己的parse_command函数,直接用getopt函数来分析,利用man 3 getopt找到,getopt需要include的头文件。
***linux在使用man指令时,可以加上参数: man X funcname
2 系统调用,即由内核提供的函数。
3 例程,即库函数,比如标准C库libc。
getopt寒素需要包含unistd.h的头文件。
在编译c文件的过程中,出现无法编译的问题,因为包含了math.h头文件,所以必须在命令行最后加上-lm。
int getopt(int argc, char * const argv[],const char *optstring);
/*
对于getopt函数,前两个参数和main函数相同,直接从main函数传递给getopt。第三个参数optstring(字符串)是一种排序编码,包含了用户程序想要接收的所有单字母选项。
比如用户程序接收以下的选项: -a -b -c
那么optstring参数将只包含字符串“abc(其中a、b、c字符的顺序以及字符是否存在并不重要,但是字符区分大小写)”
*/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GOiaV53-1629079212302)(C:\Users\zgyd\AppData\Roaming\Typora\typora-user-images\image-20210816002549028.png)]

void parse_command(int argc,char* argv[],int* s,int* E,int* b,char* filename,int* isVerbose){
	int opt;
    while ((opt = getopt(argc, argv, "vs:E:b:t:")) != -1)
    {
        switch (opt)
        {
            case 'v':
                *isVerbose = 1;
                break;
            case 's':
                *s = atoi(optarg);
                break;
            case 'E':
                *E = atoi(optarg);
            	break;
            case 'b':
	            *b = atoi(optarg);
	            break;
	        case 't':
                strcpy(filename,optarg);
                break;
        }
    }
}

//问题解决,是filename读取有问题。最终版本的cache lab如下
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "unistd.h"
const int maxi=999;


typedef struct{
	unsigned int valid;//有效位
	unsigned int tag_bit;//标识位
	int time_stamp;
} cache_line,*cache_asso,**cache;


cache _cache;
int hits=0;int evictions=0;int mises=0;

int getNum(char* str,int n);
void parse_command(int argc,char* argv[],int* s,int* E,int* b,char* filename,int* isVerbose);
void init(int S,int E);
void parse_addr(unsigned int addr);
void parse_trace(char* filename,int S,int E,int s,int b,int isVerbose);
/*
使用LRU算法来寻找victim,LRU算法在具体实现的时候,
可以用权重来看,每一次访问时权重增加1,最重要被
替换的是权重最轻的那一个line
*/

int getNum(char* str,int n){
	int sum=0;
	for(int i=0;i<n;i++){
		sum+=sum*10+str[i]-'0';
	}
	return sum;
}

/*
Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>
• -h: Optional help flag that prints usage info
• -v: Optional verbose flag that displays trace info
• -s <s>: Number of set index bits (S = 2^s is the number of sets)
• -E <E>: Associativity (number of lines per set)
• -b <b>: Number of block bits (B = 2b is the block size)
• -t <tracefile>: Name of the valgrind trace to replay
*/

void parse_command(int argc,char* argv[],int* s,int* E,int* b,char* filename,int* isVerbose){
	int opt;
    while ((opt = getopt(argc, argv, "vs:E:b:t:")) != -1)
    {
        switch (opt)
        {
            case 'v':
                *isVerbose = 1;
                break;
            case 's':
                *s = atoi(optarg);
                break;
            case 'E':
                *E = atoi(optarg);
            	break;
            case 'b':
	            *b = atoi(optarg);
	            break;
	        case 't':
                strcpy(filename,optarg);
                break;
        }
    }
}



void init(int S,int E){
	_cache=(cache)malloc(sizeof(cache_asso)*S);
	for(int i=0;i<S;i++){
		_cache[i]=(cache_asso)malloc(sizeof(cache_line)*E);
		for(int j=0;j<E;j++){
			_cache[i][j].tag_bit=0;
			_cache[i][j].valid=0;
			_cache[i][j].time_stamp=0;
		}
	}

}

/*
memory address format:
高位                 低位
tag == sets_index == block_offset
  t          s          b
命中的原则是:
	1.设置了有效位 
	2.请求地址的标记位与cache地址的标位一致
*/

int bi2decimal(unsigned int sets_index){
	int sum=0;
	while(sets_index){
		sum=sum*2+sets_index%10;
		sets_index=sets_index/10;
	}
	return sum;
}

void exec(unsigned int tag,unsigned int sets_index,int E,int isVerbose){
	int index=bi2decimal(sets_index);
	cache_asso asso=_cache[index];
	for(int i=0;i<E;i++){
		if(asso[i].valid==1 && asso[i].tag_bit==tag){
			hits++;
			asso[i].time_stamp++;
			if(isVerbose) printf("hit\n");
			return;
		}
	}
	if(isVerbose) printf("miss\n");
	mises++;
	for(int i=0;i<E;i++){
		if(asso[i].valid==0){
			asso[i].valid=1;
			asso[i].tag_bit=tag;
			asso[i].time_stamp=1;
			return;
		}
	}
	int victim_index=-1;int victim_stamp=maxi;
	for(int i=0;i<E;i++){
		if(victim_stamp>asso[i].time_stamp){
			victim_stamp=asso[i].time_stamp;
			victim_index=i;
		}
	}
	evictions++;
	asso[victim_index].tag_bit=tag;
	printf("evict\n");
}


void parse_trace(char* filename,int S,int E,int s,int b,int isVerbose){	
	FILE* fp;
	fp = fopen(filename,"r");
	if(fp==NULL) printf("Error reading file!");
	char op;unsigned int addr;unsigned int offset;
	while(fscanf(fp," %c %d,%d",&op,&addr,&offset)!=EOF){
		unsigned int tag=addr>>(s+b);
		unsigned int sets_index=(addr>>b)&( (unsigned int) (pow(2,s)-1) );
		if(op=='I') continue;
		else if(op=='L') {
			if(isVerbose) printf("%c %d,%d ",op,addr,offset);
			exec(tag,sets_index,E,isVerbose);
		}
		else if(op=='M') {
			if(isVerbose) printf("%c %d,%d ",op,addr,offset);
			exec(tag,sets_index,E,isVerbose);
			exec(tag,sets_index,E,isVerbose);
		} 
		else continue;
		// printf("%c,%d,%d",op,addr,offset);
	}
	fclose(fp);
	for(int i=0;i<S;i++){
		free(_cache[i]);
	}
	free(_cache);
}


int main(int argc,char* argv[]){
	if(argc==1){
		printf("Wrong input!");
		return 0;
	}
	int s;int E;int b;int isVerbose=0;char filename[maxi];
	parse_command(argc,argv,&s,&E,&b,filename,&isVerbose);

	// printf("%s",filename);
	
	int S=pow(2,s);int B=pow(2,b);
	/*test for function parse_command; 
	printf("%d,%d,%d,%d,%s",S,E,B,isVerbose,filename);
	*/

	init(S,E);

	/*test for function init; 
	for(int i=0;i<S;i++){
		for(int j=0;j<E;j++){
	 		printf("%d,%d\n",_cache[i][j].tag_bit,_cache[i][j].valid);
		}
	}
	*/
	
	/*
	test for function bi2decimal 
	printf("%d\n",bi2decimal(11));
	*/
	
	parse_trace(filename,S,E,s,b,isVerbose);
	printf("hits:%d, evictions:%d, mises:%d",hits,evictions,mises);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值