CSAPP cachelab 记录
参考教程
前言
要学的东西实在是太多了,感觉干啥都行,但晃着晃着就啥都没干,斗胆开始尝试一下 csapp 的 cache lab
从下午做到晚上,暂时只做了 part A,等下次有空了再继续做吧。
Cache 复习
cache的3个核心参数:\((S,E,B)\)
- \(S\),Sets,组数,储物柜有\(S\)层抽屉,这个lab里
-
\(E\),Associativity,相联度/每组行数
- \(E=1\),叫直接映射(Direct Mapped),一层就一格
- \(E > 1\),叫组相联(Set Associative),比如\(E=4\),就在4个格子里挨个找
-
\(B\),Block size,块大小,每个格子里装多大的数据块
CPU 向 Cache 发送请求时,只给了一个64位的内存地址
Cache 会把这个64位地址分成3段:Tag, Set Index, Block Offset; \(t + s + b = 64\)
- b: 最低位,告诉cache我要的数据在这个数据块的第几个字节(在lab的模拟器中不用管这一点?)
- s: 中间位,这是抽屉号,cache可以知道应该去\(2^s\)个抽屉中的哪个去找(注意前后两个s不是同一个)
- t: 最高位,剩下的所有位数都是Tag,是身份证号
为什么不直接用地址去找?而是要切分?
因为内存太大了,而cache很小,一定会有成千上万个内存地址算出来的s是相同的,他们都会被挤到同一个抽屉里,为了区分抽屉里目前装的是哪个人,就必须比对高位的t
cache的工作流
当要访问某个地址时,代码讲要执行以下三步:
- 定位组 Set Selection
(使用位运算)把s提取出来,转换成整数,然后去Cache.sets[s]这个组里去找
- 行匹配
在这个组里,一共有\(E\)行,遍历这\(E\)行:
当valid == 1 && line.tag == t,就命中了,需要更新LRU计数器
- 未命中与替换
没有命中就要从主存里把数据搬进来,这时还要分两种情况:
A: 组里还有空位置,遍历发现某一行valid == 0,直接把新数据的Tag写进去,把valid置为1,更新LRU,记录一次Miss
B: 组满员了,找到这组里最久没有被访问过的换掉,记录1次miss 1次eviction淘汰
过完一遍后还有的疑惑
LRU 计数器是什么形式
tag 是什么样的
实际写的时候的疑惑
为什么指令的格式中唯独I前面没有前导空格
为了体现指令的主干和枝叶的关系:
I 0400d7d4,8 <-- CPU 取了一条指令(比如单纯的寄存器加法 add)
I 0400d7d8,4 <-- CPU 取了下一条指令(比如是一条 mov 内存拷贝指令)
M 0421c7f0,4 <-- (缩进)这条 mov 指令导致了内存数据的修改 (Modify)
L 04f6b868,8 <-- (缩进)接着又导致了数据的加载 (Load)
I 0400d7dc,4 <-- CPU 继续取下一条指令
实际写的时候忽略空格就好了,甚至是把I都忽略,因为指令操作和cache无关
如何拆分地址
参数会输入s E b
低b位:block offset
中间s位:set index
高位:tag
我们只需要后两个数,b只是用来定位的
cache 的空间该如何分配
\(S = 2^s\) 个抽屉,每个抽屉\(B = 2^b\)个格子,每个格子是一个结构体,需要维护的数据为:???
地址是怎么映射到cache中的
cpu要这个地址的数据时,cache要回答两个问题:
- 这个地址应该去cache的哪个位置找?
- 这个位置现在装的是不是我想要的那个地址对应的数据
嗯非常对
这就是为什么地址会被拆成几部分:
- 一部分用来确定去哪个 set
- 一部分用来确定 set 里是不是我要的那块 tag
- 一部分表示块内偏移
地址会被拆成3段
s: set index 占几位b: block offset 占几位- 剩下的高位就是
tag
- 最低的 b 位:表示这个地址在一个block内的第几个字节
- 中间的 s 位:表示他映射到哪个 set
- 剩下更高的位:表示它属于哪个 tag
感想

好有用,看那b视频总感觉迷迷糊糊但是一写代码就清楚很多,但是实际跟缓存相关的代码就一小点点,搞那些输入输出都得搞一会儿,要是没有耐心很容易就做不下去了,饺子醋这一块。有了ai好做多了,没有ai的时候我肯定没法做这个