csapp实验记录 - Cachelab partA

Cachelab partA

这是该实验的 partA 部分,主要是用 c 语言模拟 cpu 对cache的存取过程,以及其缓存命中,不命中和不命中时的替换的情况

实验准备

实验的环境在 Linux

具体的实验包可以去 CMU 的csapp实验官网下载
实验

同时该实验 CMU 有相应的辅助材料可以利用
实验指导PPT

解答

本实验就是简单模拟缓存的行为

注意

  1. 本实验需要根据传入的不同的 s , E , b s, E, b s,E,b 值进行模拟
  2. 替换策略使用LRU(最近最少使用)策略

数据结构

在这里插入图片描述
所以根据此可以创建一个存储缓存行的结构体

typedef struct CACHE_LINE {
    short valid;		// 有效位
    unsigned tag;		// 标记
    int stamp;			// 模拟时间戳,用于lru
}cache_line, *cache_asso, **cache;

同时定义该结构体的指针和指针的指针,便于后续 malloc 二维数组来模拟 cache

具体思路

那么结构体有了,我们需要做的就是根据给出的 s , E , b s, E, b s,E,b 的值 malloc 出二维数组

有了二维数组,我们就可以读取每一条指令,将指令的地址字段解析出 标记 和 组索引

根据组索引和标记模拟命中情况,记录命中和不命中,替换的次数

替换策略采用简单版的LRU,具体算法如下:

  1. 对于每一次缓存动作,将定位的块中所有的缓存行的 stamp + 1,模拟时间推移
  2. 对命中的缓存行,stamp = 0
  3. 替换掉 stamp 值最大的缓存行

代码

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

typedef struct CACHE_LINE {
    short valid;
    unsigned tag;
    int stamp;
}cache_line, *cache_asso, **cache;

cache _cache_ = NULL;

int s, S, E, b, v;
char t[1024];
int hits, misses, evictions;

int init_cache();

void free_cache();

unsigned get_block_index(unsigned address);

unsigned get_tag(unsigned address);

void visit_cache();

int hit_cache(unsigned index, unsigned tag);

int main(int argc, char **argv)
{
    int opt;
    while((opt = getopt(argc, argv, "vs:E:b:t:")) != -1) {
        switch(opt) {
            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:
                printf("wrong arg!");
                break;
        }
    }
    if(s <= 0 || E <= 0 || b <= 0 || t == NULL) return -1;
    S = 1 << s;
    init_cache();
    
    visit_cache();

    free_cache();
    printf("hits:%d misses:%d evictions:%d\n",hits,misses,evictions);
    printSummary(hits,misses,evictions);
    return 0;
}


int init_cache() {
    
    _cache_ = (cache)malloc(sizeof(cache_asso) * S);
    if(_cache_ == NULL) return -1;
    
    for(int i = 0;i < S;i ++) {
        _cache_[i] = (cache_asso)malloc(sizeof(cache_line) * E);
        if(_cache_[i] == NULL) return -1;
        for(int j = 0;j < E;j ++) {
            _cache_[i][j].valid = 0;
            _cache_[i][j].tag = -1;
            _cache_[i][j].stamp = 0;
        }
    }

    return 1;
}

void free_cache() {
    
    if(_cache_ != NULL) {
       for(int i = 0;i < S;i ++) {
          if(_cache_[i] != NULL) free(_cache_[i]);
       }

       free(_cache_);
    }
    
}

// 解析缓存块
unsigned get_block_index(unsigned address) {
  
    return address >> b & ((1 << s) - 1);
}

// 解析缓存行
unsigned get_tag(unsigned address) {
    
    return address >>= (b + s);
}

// 模拟缓存动作
void visit_cache() {
    FILE *f;
    f = fopen(t, "r");
    char ident;
    unsigned address;
    int	size;
    int status; 
    while(fscanf(f," %c %x,%d",&ident, &address, &size) > 0) {
        
        unsigned index = get_block_index(address);
        unsigned tag = get_tag(address);
        switch(ident) {
            case 'I':
              continue;
            case 'S':
            case 'L':
              status = hit_cache(index,tag);
              if(status == 0) printf("%c %x,%d hit",ident,address,size);
              else if(status == 1) printf("%c %x,%d miss",ident,address,size);
              else printf("%c %x,%d miss eviction",ident,address,size);
              puts("");
              break;
            case 'M':
              status = hit_cache(index,tag);
              hits ++;
              if(status == 0) printf("%c %x,%d hit hit",ident,address,size);
              else if(status == 1) printf("%c %x,%d miss hit",ident,address,size);
              else printf("%c %x,%d miss eviction hit",ident,address,size);
              puts("");
              break;
        }
    }

    fclose(f);
}

/*
 模拟命中情况
  0 hit
  1 miss
  2 miss eviction

*/
int hit_cache(unsigned index, unsigned tag) {

   cache_asso cache_block = _cache_[index];

   // update lru
   for(int i = 0;i < E;i ++) cache_block[i].stamp ++;

   // hit
   for(int i = 0;i < E;i ++) {
        if(cache_block[i].valid && cache_block[i].tag == tag) {
            cache_block[i].stamp = 0;
            hits ++;
            return 0;
        }
   }
  
   // miss
   for(int i = 0;i < E;i ++) {
        if(!cache_block[i].valid) {
            cache_block[i].valid = 1;
            cache_block[i].tag = tag;
            cache_block[i].stamp = 0;
            misses ++;
            return 1;
        }
   }
  
   int idx = 0;
   int maxv = 0;
   for(int i = 0;i < E;i ++) {
        if(cache_block[i].stamp > maxv) {
            maxv = cache_block[i].stamp;
            idx = i;
        }
   }

   cache_block[idx].tag = tag;
   cache_block[idx].valid = 1;
   cache_block[idx].stamp = 0;
   misses ++;
   evictions ++;
   return 2;
}

结果

满分27分

在这里插入图片描述

总结
partA 部分断断续续花了挺长时间才做完,在学校学 csapp 时间实在是太零碎了,但是一开始很迷茫,看了一下实验指导PPT以及一些细小的地方参考了其它博客,就逐渐清晰了,写代码就很快了。

写完之后测过几个 trace 就去测试了,一遍过了,还是挺有成就感的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值