CSAPP: CacheLab 实验详解

CacheLab 实验报告

本实验分为两部分,第一部分要求模拟一个cache,第二部分要求根据给定的缓存结构优化矩阵转置函数。

Part A: Writing a Cache Simulator

1. 任务说明与初步思路

​ 根据实验文档,在本部分,我们要在csim.c中编写代码,以valgrind memory trace文件作为输入,在控制台输出总的hit, misseviction数,实现handout中csim-ref的效果:

linux> ./csim-ref -v -s 4 -E 1 -b 4 -t traces/yi.trace 
L 10,1 miss 
M 20,1 miss hit 
L 22,1 hit 
S 18,1 hit 
L 110,1 miss eviction 
L 210,1 miss eviction 
M 12,1 miss eviction hit 
hits:4 misses:5 evictions:3 

linux> ./csim-ref -h
• -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

​ 而Valgrind memory trace文件内容格式如下:

I 0400d7d4,8
 M 0421c7f0,4
 L 04f6b868,8
 S 7ff0005c8,8
/* Each line denotes one or two memory accesses. The format of each line is
[space(only for 'I')]operation address,size */

​ 拆分本任务,可从本任务中提取几个关键部分:

  • 读取命令行参数;
  • 模拟高速缓存的数据结构;
  • 读取trace文件并模拟缓存过程。

​ 通读实验报告后,我们可以获得下面几个提示:

  • 只需要模拟S(data store), L(data load)M(data modify, i.e. data load following by data store)这三个指令;
  • 缓存采用LRU(least-recently used)的替换策略来驱逐缓存块;
  • 由于缓存结构由命令行参数决定,故会用到malloc()函数;
  • 输出采用printSummary函数输出,-v-h命令行参数可选择不实现;
  • 可以采用unistd.hgetopt.h中的getopt()函数读取命令行参数,可参考man 3 getopt

​ 在写代码之前,会有如下问题:

  • 如何管理可变个命令行参数?
    • 使用getopt()函数。
  • S, LM的指令有何区别?
    • 本例中SL指令没有区别,都是检查缓存中是否有地址中的元素,有则hit无则miss后载入缓存;
    • M = L + S,故事实上第二个S一定会hit
    • 容易迷惑的点:miss后会把相应数据载入缓存,但不会再访问缓存命中并打印hiteviciton后会用LRU策略驱逐块,之后会再次访问缓存不命中、再次打印miss,而同样地,miss后会把相应数据载入缓存,但不会再访问缓存命中打印hit
  • 选用什么数据结构来实现cache,需要实现cache的哪部分功能?
    • 初步思路是用结构体实现cacheline,再以二维数组的形式来组织成cache
    • cache的功能不必完全实现,由于不需要存入具体的数据,因此在cacheline结构体中不必添加B和用于存放数据的成员数组cacheblock
    • 可以注意到,参数b的唯一作用就是计算标记位t的值来解析地址,与b相关的参数也不必集成在cache结构体中。

下面分部分完成本任务。

2. 实验过程

部分 1 - 读取命令行参数

​ 根据实验文档,我们要接收的命令行参数为:

Usage: ./csim [-hv] -s <s> -E <E> -b <b> -t <tracefile> 

​ 我们采用getopt函数解析命令行参数,使用方法可参考官方文档。其中,为了方便调试,在这里我们实现-v功能,用一个全局变量int showDetails来判断未来模拟过程中是否输出细节信息。

int showDetails = 0;

void readCommandline(int argc, char* argv[], int *s, int *E, int *b, char *tracefile){
   
    const char *optstr = "hvs:E:b:t:";
    int opt;
    while((opt = getopt(argc, argv, optstr)) != -1){
   
        switch(opt){
   
            case 'h':
                printHelpMenu();	// 打印帮助菜单
                exit(0);
            case 'v':
                showDetails = 1;	// 设置全局变量showDetails为真
                break;
            case 's':
                *s = atoi(optarg);   // 外部变量 optarg - 指向当前选项参数字符串的指针
                break;
            case 'E':
                *E = atoi(optarg);
                break;
            case 'b':
                *b = atoi(optarg);
                break;
            case 't':
                strncpy(tracefile, optarg, strlen(optarg));
                break;
        }
    }
}
部分 2 - 模拟高速缓存的数据结构

​ 高速缓存的最小结构单元是行,即cacheline,它可以用结构体来实现,含有以下成员变量:

typedef struct Cache{
   
    int valid;			// 有效位的值
    unsigned tag;		// 标记位的值
    int recentTimeUsed;	// 用于LRU策略,记录最后一次被访问的'时间'
}Cacheline;

Ecacheline组合成一个setSset组合成一个cache。因此,cache可视为是一个S*Ecacheline二维数组。为了还要集成其他的有关cache的信息如S, EB,我们把cache也做成一个结构体,成员变量如下:

typedef struct Cache{
   
    int S, E;
    Cacheline **cachelines;	// cacheline的二维数组
}Cache;

​ 下面为CachelineCache依次编写初始化方法。

void initCacheline(Cacheline *cacheline){
   
    cacheline->valid = 0;
    cacheline->tag = 0;
    cacheline->recentTimeUsed = 0;
}
void initCache(int S, int E, Cache *cache){
   
    cache->S = S;
    cache->E = E; 
    cache->cachelines = (Cacheline **)malloc(sizeof(Cacheline *)*S);
    for(int i=0;i<S;i++){
   
        cache->cachelines[i] = (Cacheline *)malloc(sizeof(Cacheline)*E);
        // ★易错!注意 &cache->cachelines[i][j] 和 cache->cachelines[i]的关系
        for(int j=0;j<E;j++){
    
            initCacheline(&cache->cachelines[i][j]);
        }
    }
}

​ 由于初始化Cache对象的过程中用了动态内存分配,需要为Cache编写释放内存的函数:

void freeCache(Cache *cache)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值