CACHE Lab
是真的不想写,对C的很多细节都忘了,简直是 折 磨
不写就不会提高了,,,人要变强就要变秃,我还是继续写吧,,,
奥利给干了兄弟们!
Part.A
C补漏
- 从命令行对输入数据的读取用
getopt()
主要用来解析输入的命令。atoi函数是将字符转换成整数的函数。 - C自定义函数放在main前面,否则要加函数原型。
- C中布尔用_Bool,正确与否用1/0。
- FILE 类型管理文件,本次lab中用FILE定义了输入文件的路径
- 利用
fscanf()
来实现对trace文件中字符的读取。函数原型为int fscanf(FILE * stream, const char * format, [argument...]);
这里并不需要提前把所有trace都读进去,只需要每次读一行处理一行 - 利用
malloc()
来实现对内存的申请,C 库函数void *malloc(size_t size)
分配所需的内存空间,并返回一个指向它的指针(指针要经过强制类型转换为需要的指针)。申请完毕后要释放。
下面看看申请一维,二维,三维数组时的例子:
//一维数组m
char *p = (char *)malloc(m*sizeof(char));//申请一个大小为m的char数组
...
free(p);//释放空间
//二维数组m*n
char **p = (char **)malloc(m*sizeof(char*));
for(int i=0;i<m;i++){
p[i]=(char *)malloc(n*sizeof(char));
}//申请一个大小为m*n的char数组
...
for(int i=0;i<m;i++){
free(p[i]);
}
free(p);//释放空间
//三维数组m*n*k
char*** p = (char***)malloc(m*sizeof(char**));
for(int i=0;i<m;i++){
p[i]=(char**)malloc(n*sizeof(char*));
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
p[i][j]=(char*)malloc(k*sizeof(char));
}
}//申请一个m*n*k的三位数组
...
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
free(p[i][j]);
}
}
for(int i=0;i<m;i++){
free(p[i]);
}
free(p);//释放空间
数据结构设计与需要注意的点
- 在动态分配内存时,每一行并不需要分配大小为b的内存,因为我们的缓存模拟器只需要模拟缓存是否命中,而不需要存储里面的实际内容。
- cache_line的设计:cache的每一行用一个cache_line的struct表示,根据1,并不用实际分配内存。cache_line的实际数据结构包含三个量:
tag
用于查看地址是否存在于缓存中
valid_bit
用于标记是否已经初始化
stamp
用于记录该line有多久没有更新,stamp值越大,被替换的优先级就越大。 - Cache[2^s][E] 数组用于存放cache_line。
- 由于地址值要进行右移,用unsigned比较好,否则会引入符号位。
- 时间戳算法:每个cache_line都有一个stamp变量,记录该line有多少轮没有更新。在查找未命中而替换时,替换E个cache_line中stamp值最大的那个。每次只要更新,就把该值置为0。每输入完一个数据,就对Cache数组中的所有cache_line进行时间戳更新。
代码
#include "cachelab.h"
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stddef.h>
typedef struct{
int valid_bits;
unsigned tag;
int stamp;
}cache_line;//定义结构体为cache中的每一行
char* filepath = NULL;//路径
int s,E,b,S;// s is set ,E is line,each line have 2^b bits ,S is 2^s set
int hit=0,miss=0,eviction=0;
cache_line** cache = NULL;//定义cache为代表缓存的数组
void init(){
cache = (cache_line**)malloc(sizeof(cache_line*)*S);
for(int i=0;i<S;i++)
*(cache+i) = (cache_line*)malloc(sizeof(cache_line)*E);//malloc cache[S][E],给数组分配动态空间
for(int i=0;i<S;i++){
for(int j=0;j<E;j++){
cache[i][j].valid_bits = 0; // set all valid_bits is zero
cache[i][j].tag = 0xffffffff; //no address
cache[i][j].stamp = 0; //time is 0;
}
}
}
void update(unsigned address){//cache中的s值可以直接通过地址找到,但是E值却只能通过遍历来看是否匹配
unsigned s_address =(address>>b) & ((0xffffffff)>>(32-s)); //set`s index
unsigned t_address = address>>(s+b); //tag`s index
for(int i=0;i<E;i++){
if((*(cache+s_address)+i)->tag ==t_address){
cache[s_address][i].stamp = 0;
hit++;
return;
}
}//命中,将时间戳记为0
for(int i=0;i<E;i++){
if(cache[s_address][i].valid_bits == 0){
cache[s_address][i].tag = t_address;
cache[s_address][i].valid_bits = 1;
cache[s_address][i].stamp = 0; //now ,this is load
miss++;
return;
}
}//初始化加载
//下面是没有命中,但是缓存已经初始化完的情况,此时开始替换。
int max_stamp=0;
int max_i;
for(int i=0;i<E;i++){
if(cache[s_address][i].stamp >max_stamp){
max_stamp = cache[s_address][i].stamp;
max_i = i;
}
}//遍历整个E,找一个长时间没有更新的(stamp值最大的),对其进行替换。
eviction++;
miss++;
cache[s_address][max_i].tag = t_address;
cache[s_address][max_i].stamp = 0; //更新tag和stamp值
}
void time(){
for(int i=0;i<S;i++){
for(int j=0;j<E;j++){
if(cache[i][j].valid_bits == 1)
cache[i][j].stamp++;
}
}
}//每一轮之后都要更新所有时间戳,统统加一
int main(int argc,char *argv[])
{
int opt;
while((opt = getopt(argc,argv,"s:E:b:t:")) !=-1){ //parse command line arguments
switch(opt){
case 's':
s=atoi(optarg);
break;
case 'E':
E=atoi(optarg);
break;
case 'b':
b=atoi(optarg);
break;
case 't':
filepath = optarg;
break;
}
}
S = 1<<s;
init();
FILE* file=fopen(filepath,"r");
if(file == NULL){ // read trace file
printf("Open file wrong");
exit(-1);
}
char operation;
unsigned address;
int size;
while(fscanf(file," %c %x,%d",&operation,&address,&size)>0){
switch(operation){
case 'L':
update(address);
break;
case 'M':
update(address);//M后面没有break,代表读写两次
case 'S':
update(address);
break;
}
time();
}
for(int i=0;i<S;i++) //free cache[S][E]
free(*(cache+i));
free(cache);
fclose(file); //close file
printSummary(hit,miss,eviction);
return 0;
}