详细的题目要求和资源可以到 http://csapp.cs.cmu.edu/3e/labs.html 或者 http://www.cs.cmu.edu/~./213/schedule.html 获取。
本次实验难点在Part B的64 * 64部分,主要介绍这一部分。
Part A: 编写缓存模拟器
前期准备:
getopt和fscanf系列库函数对于这次实验很重要,不太明白的可以man一下,或者参考这两篇文章:
Linux下getopt()函数的简单使用
C 库函数 - fscanf()
注意事项:
1.由于我们的模拟器必须适应不同的s, E, b,所以数据结构必须动态申请(malloc系列),注意初始化。
2.测试数据中以“I”开头的行是对指令缓存(i-cache)进行读写,我们编写的是数据缓存(d-cache),这些行直接忽略。
3.这次实验假设内存全部对齐,即数据不会跨越block,所以测试数据里面的数据大小也可以忽略。
4.为了使得评分程序正常运行,main函数最后需要加上:
printSummary(hit_count, miss_count, eviction_count);
5.建议把-v这个选项也实现了,这样自己debug的时候也方便一些。另外,可以先从规模小的测试数据开始,然后用大的。
思路要点及其实现:
1.这次实验只要求我们测试hit/miss/eviction的次数,并没有实际的数据存储 ,所以我们不用实现line中的block部分。
2.这次实验要求使用LRU(least recently used),即没有空模块(valid为0)时替换最早使用的那一个line。所以我们应该在line中实现一个能够记录当前line最后一次写入的时间参量,每次”写入“line的时候就更新一下该参量。(这一点csapp上没有详细说)
3.综上,结合书上对cache的描述,我们可以得到如下数据结构:
注意到cache(sets的入口)和set(lines的入口)都是用指针实现的,sets构成一个指针数组,因为它们不含任何数据,唯一的用处就是通过偏移量寻找到指定的line。
下面结合代码执行的顺序对我实现的程序进行解释,由于写了很多注释,就不详细的说了(我的sublime写不了中文,就用的英文注释的,语法有错还请指出)
更新:一航介绍了一个插件,可以解决Ubuntu下sublime中文输入的问题
–> sublime-text-imfix
头文件:
include “cachelab.h”
include
include
include
include
include
include
define false 0
define true 1
我喜欢用_Bool+宏定义true和false,你也可以使用stdbool.h。
数据结构类型定义:
typedef struct
{
_Bool valid; /* flag whether this line/block is valid, zero at first*/
uint64_t tag; /* identifier to choose line/block */
uint64_t time_counter; /* LRU strategy counter, we should evict the block who has the min time_counter, zero at first */
/* We don’t need to simulate the block, since we just requested to count hit/miss/eviction */
}line;
typedef line *entry_of_lines;
typedef entry_of_lines *entry_of_sets;
time_counter初始化的时候都是0,其值越大代表这个line最近刚刚被写入——我们不应该替换它——所以valid为0的line的time_counter一定也是0(最小值),因为他们连使用都没有被使用过,即我们一定会先替换valid为0的line,这符合书上的策略。
typedef struct
{
int hit;
int miss;
int eviction;
}result;
我将结果设计成了一个结构体,这样函数方便返回一些。(少用全局变量)
main函数的数据类型:
result Result = {0, 0, 0};
const char *help_message = “Usage: \”Your complied program\” [-hv] -s -E -b -t \n” \
“ should all above zero and below 64.\n” \
“Complied with std=c99\n”;
const char *command_options = “hvs:E:b:t:”;
FILE* tracefile = NULL;
entry_of_sets cache = NULL;
_Bool verbose = false; /* flag whether switch to verbose mode, zero for default */
uint64_t s = 0; /* number of sets ndex’s bits */
uint64_t b = 0; /* number of blocks index’s bits */
uint64_t S = 0; /* number of sets */
uint64_t E = 0; /* number of lines */
注释已经写的很清楚了,我解释一下help_message的写法,有的同学可能不知道C中字符串的写法:两个字符串中间只有空格,C编译器会自动将它们合并。例如:
char* test_string = “hello” ” world”
那么test_string就会是“hello world”。
另外,在C中,一行写不下的时候可以使用\字符隔开,编译器会自动合并的。
main函数读取参数:
char ch; /* command options */
while((ch = getopt(argc, argv, command_options)) != -1)
{
switch(ch)
{
case 'h':
{
printf("%s",