CSAPP-CacheLab

实验a

实验一是要我们实现一个模拟缓存。

做实验之前我们先要了解缓存的结构。见下图,图片来自cmu的ppt.实验ppt

一个内存地址会被分为3部分,t,s,b。而缓存的大小由s,E,b三个参数决定。缓存的组(set)数S=2^s,每组的行数=E,组中数据块大小为B=2^b。

实验的介绍文件中告诉我们可以忽略掉b偏移量这个参数(但你还是要接受这个参数,只是不用管他),并且告诉我们保证测试文件的size肯定不会超过块大小。因此实际上我们看一个缓存是命中就只用在意他的地址的s,和t在缓存中是否存在了。

写代码在csim.c中写。

实验的大体思路是这样的:

1.首先你要用getopt函数去接受参数(当然你也可以不用,但确实很方便)。接受完参数之后需要进行一些参数校验,比如s不能为0等等,对了如果参数中有-h是不用进行模拟的,直接输出帮助信息就好了。

2.模拟缓存的数据结构我采用的是二维数组,每一个缓存行我采用的是结构体(结构体的结构cmu的官方ppt已经给出提示了)

3.实验文件要求我们采用LRU算法,我这里用的是时间戳(ppt里面也有提示),大概就是需要淘汰时,淘汰时间戳值最大的,也就是最久没使用的。

4.c程序需要完成这样几个过程,首先接受参数,参数的格式可以去看traces文件夹下的文件,然后I开头的不用处理直接跳过,根据数据访问的类型去缓存里找,把传入的地址进行解析,得到对应的set号和tag位,遍历对应的set,如果有,那么hit++;没有的话miss++,然后看看有没有空行,有的话填入空行,没有空行的话遍历该set的所有行,找到counter最大的,进行替换,eviction++

最后附上代码

#include "cachelab.h"
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include <limits.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>

//缓存结构
typedef struct{
    int valid_bit;//有效位
    int tag; //标识位
    int counter; //计数器,记录被访问了多少次
}Cache_line ,*Cache_set,**Cache;

//接受输入参数
int h = 0; //0表示未传入
int v = 0;
int s = 0; //0表示set大小为0
int E = 0; //表示number of lines per set
int b = 0; //B=2^b
char t[1000];

int S = 0;
int B = 0;

//缓存
Cache cache = NULL;

//存储结果
int hit = 0;
int miss = 0;
int eviction = 0;


void printTips(){
    printf("Usage: ./csim-ref [-hv] -s <num> -E <num> -b <num> -t <file>\n"
            "Options:\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-ref -s 4 -E 1 -b 4 -t traces/yi.trace\n"
            "  linux>  ./csim-ref -v -s 8 -E 2 -b 4 -t traces/yi.trace\n");
}

//初始化缓存
void init_Cache(){
    cache = (Cache)malloc(S*sizeof(Cache_set));
    for(int i =0;i<S;i++){
        cache[i] = (Cache_set)malloc(E*sizeof(Cache_line));
        for(int j=0;j<E;j++){
            cache[i][j].valid_bit = 0;
            cache[i][j].tag = -1;
            cache[i][j].counter = 0;
        }
    }
}

int getParams(int argc,char * argv[]){
    int ch = 0;
    while ((ch = getopt(argc, argv, "hvs:E:b:t:")) != -1){
           switch (ch)
        {
               case 'h':
                       h = 1;
                       break;
               case 'v':
                       v = 1;
                       break;
               case 's':
                       s = atoi(optarg);
                       break;
               case 'E':
                       E = atoi(optarg);
                       break;
               case 'b':
                       b = atoi(optarg);
                       break;
               case 't':
                       strcpy(t, optarg);
                       break;
               default:
                       return 0;
               }
     }
     return 1;
}

void deal_inCache(unsigned address){
    //获取组号
    unsigned mask = 0xffffffffffffffff >> (64 -s);
    int s_num = (address >> b) & mask;
    //获取tag
    mask = 0xffffffffffffffff >> (s + b);
    int tag = (address >> (s+b)) & mask;

    //查看是否在缓存当中
    for(int i=0;i<E;i++){
        if(cache[s_num][i].valid_bit==1&&cache[s_num][i].tag == tag){
                //说明缓存命中
                hit++;
                cache[s_num][i].counter = 0;//重置计数器
                return;
        }
    }
    //执行到这说明缓存不命中
    miss++;
    //查看是否有空行
    for(int i=0;i<E;i++){
         if(cache[s_num][i].valid_bit==0){
                cache[s_num][i].tag = tag;
                cache[s_num][i].valid_bit = 1;
                return;
         }
    }
    //执行到这说明没有空行需要进行驱逐
    eviction++;
    int max = cache[s_num][0].counter;
    int max_index = 0;
    for(int i=1;i<E;i++){
        if(cache[s_num][i].counter > max){
            max = cache[s_num][i].counter;
            max_index = i;
        }
    }
    //进行驱逐
    cache[s_num][max_index].tag = tag;
    cache[s_num][max_index].valid_bit = 1;
    cache[s_num][max_index].counter = 0;

}

void update_timeCounter(){
    for(int i=0;i<S;i++){
        for(int j=0;j<E;j++){
            if(cache[i][j].valid_bit==1){
                cache[i][j].counter++;
            }
        }
    }
}

void simulate(){
    FILE* file = NULL;
    file = fopen(t,"r");
    if(file == NULL)
    {
        printf("open error");
        exit(-1);
    }
    char type = '0';
    unsigned address = 1;
    int size = 0;
    while(fscanf(file," %c %x,%d",&type,&address,&size)>0){
        switch(type){
            case 'L':
                    deal_inCache(address);
                    break;
            case 'M':
                    deal_inCache(address);
            case 'S':
                    deal_inCache(address);
        }
        update_timeCounter();
    }

}

int main(int argc,char * argv[])
{
    //读取参数
    int result = getParams(argc,argv);
    if(!result || h==1 || s<=0||E<=0||b<=0){ //如果参数有不在参数列表的或者用户输入了-h或者参数不正确,给出参数输入提示
        printTips();
        return 0;
    }
    //参数无误进行初始化操作
    S = 1 << s;
    B = 1 << b;
    init_Cache();
    simulate();
    printSummary(hit, miss, eviction);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值