CSAPP Cache Lab

本 Lab 主要考察对计算机高速缓存(Cache)机制的理解,以及如何针对 Cache 进行程序的优化,对应知识点为书中的 6.4 ~ 6.6 节内容。

Part A: Writing a Cache Simulator

思路

基本流程

Part A 需要实现一个 Cache 模拟器,能够根据 valgrind 工具所生成的访存跟踪数据,模拟在特定参数的 Cache 环境下的命中(hits)次数、不命中(misses)次数和置换(evictions)次数,目标是实现与 csim-ref 同等的功能。模拟器需要具备的几个功能模块如下:

  • 对命令行参数进行参数解析。

  • 读取 trace 文件并解析为地址访问流。

  • 定义 Cache 模拟器数据结构,以及相关的函数操作,包括初始化和地址访问。

  • 遍历解析出来的地址访问流,依次进行访问模拟,计算得到命中次数等信息。

接下来分别对它们进行介绍。

命令行参数解析

根据实验手册的提示,可以使用 getopt 函数进行命令行参数的解析。另外,如果需要支持长选项(形如 --opt arg),则可以使用 GNU C 库提供的扩展版本 getopt_long 函数,其使用方法如下:

  • generated by GPT4o

函数原型

include <getopt.h>

int getopt_long(int argc, char *const argv[],
                const char *optstring,
                const struct option *longopts,
                int *longindex);

参数说明

1. argcargv

与标准 getopt 相同,分别表示命令行参数的个数和数组。

2. optstring

一个字符串,表示短选项的格式规则:

  • 每个选项是一个字符。
  • 如果选项需要参数,在字符后添加一个冒号(:)。
  • 如果选项的参数是可选的,在字符后添加两个冒号(::)。
3. longopts

一个指向 struct option 数组的指针,用于定义长选项。

struct option 定义如下:

struct option {
    
    
    const char *name; // 长选项的名称
    int has_arg;      // 选项是否需要参数(no_argument, required_argument, optional_argument)
    int *flag;        // 如果为 NULL,则返回值为 val;否则将 *flag 设置为 val 并返回 0
    int val;          // 短选项的字符值或自定义值
};
  • name:长选项名称,例如 "help" 对应 --help
  • has_arg
    • no_argument(0):无参数。
    • required_argument(1):需要参数。
    • optional_argument(2):参数可选。
  • flag
    • 如果为 NULLgetopt_long 会返回 val 的值。
    • 如果非 NULLgetopt_long 会将 *flag 设置为 val,并返回 0。
  • val:指定与该长选项关联的返回值(通常与短选项的字符值一致)。
4. longindex

指向一个整型变量的指针,用于存储被解析的长选项在 longopts 数组中的索引位置。如果不需要,可以传 NULL


返回值

  • 返回短选项的字符值,或者由 struct optionval 指定的值。
  • 遇到未知选项时返回 ?
  • 当没有更多选项时,返回 -1

根据 getopt_long 的返回值,以及全局变量 optarg,可以对不同的命令行参数进行分发处理。

// 参数定义
struct option long_options[] = {
   
   
    {
   
    "help", no_argument, NULL, 'h' },
    {
   
    "verbose", no_argument, NULL, 'v' },
    {
   
    "set", required_argument, NULL, 's' },
    {
   
    "lines", required_argument, NULL, 'E' },
    {
   
    "block", required_argument, NULL, 'b' },
    {
   
    "trace", required_argument, NULL, 't' },
    {
   
    0, 0, 0, 0 }
};

// 参数解析
int opt;
while ((opt = getopt_long(argc, argv, "hvs:E:b:t:", long_options, NULL)) != -1) {
   
   
    switch (opt) {
   
   
        case 'h':
            print_usage();
            return 0;
        case 'v':
            vflag = 1;
            break;
        case 's':
            s = atoi(optarg);
            break;
        case 'E':
            E = atoi(optarg);
            break;
        case 'b':
            b = atoi(optarg);
            break;
        case 't':
            trace_file = optarg;
            break;
        default:
            print_usage();
            return 1;
    }
}

trace 文件解析

对 trace 文件进行解析,首先读取文件中的每一行操作,对于 operation 为 I 的访存操作,直接跳过不做处理。由于剩余的 M, L, S 操作都满足格式 [space]operation address,size,因此可以直接使用 sscanf 进行解析,提取出各字段。

对不同操作的处理比较简单:L 和 S 操作需要一次访存,M 操作需要两次访存。

这里我没有考虑一次访存位于多个 Cache 行中的情况,始终视作一次/两次访存,也通过了全部测试样例。

char line[256];
while (fgets(line, sizeof(line), file)) {
   
   
    if (line[0] == '\n' || line[0] != ' ') continue;
    line[strlen(line) - 1] = '\0';  // 去除尾置换行符
    char *pline = line + 1;         // 去除前导空格

    char operation;
    int address, size;
    if (sscanf(pline, " %c %x,%d", &operation, &address, &size) != 3) {
   
   
        fprintf(stderr, "Invalid line format: %s\n", pline);
        continue;
    }

    access_cache(&cache, address);
    if (operation == 'M') {
   
   
        access_cache(&cache, address);
    }
}

Cache 模拟器数据结构设计

整个 Cache 模拟器包含 Cache 数据部分、Cache 的参数和命中次数等模拟结果。

typedef struct {
   
   
    int s;
    int E;
    int b;
    int set_num;
    CacheSet *sets;
    int hit_count;
    int miss_count
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值