CSAPP 实验IV CacheLab
更新历史
- 24.03.09:初稿
系列
- CSAPP - 笔记汇总
- I Data Lab - 位操作,数据表示
- II Bomb Lab - 汇编,栈帧与 gdb
- III Attack Lab - 漏洞是如何被攻击的
- IV Cache Lab - 实现一个缓存系统
- V Shell Lab - 实现一个Shell
任务目标
CacheLab实验,第一部分需要模拟Cache计算命中,未命中次数,第二部分实现代码优化,减少未命中次数。
相关内容
Cache
不需要关注
b
bits,使用LRU替换策略。Cache是一个二维数组cache[S][E],S=2^s,组数。
每一个cache行包含:Valid bit, Tag, LRU counter。
用Tag对比E匹配line。
生成内存调试工具命令:
linux> valgrind --log-fd=1 --tool=lackey -v --trace-mem=yes ls -l
参数
ls -l
:打印输出在文件stdout格式为
[space]operation address,size
,除了I操作外,前都有一个空格操作:I-instruction load,L-data load,S-data store, M-data modify。M包含L,S。
address:64-bit 16进制
size:字节数
题目及解法
Part A Writing a Cache Simulator
完成csim.c
文件,使用valgrind
生成测试数据,输出命中,未命中和替换次数,输出格式为hits:4 misses:5 evictions:3
。
相关内容
修改
csim.c
文件可参考的二进制文件
csim-ref
,使用命令./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>
参数:v-打印内存追踪记录
自动评分工具
test-csim
建议代码像参考模拟器显示输出,方便测试。
使用
getopt
分析命令行参数。需包含头文件, , 。可以获取函数参数。 使用
fscanf
按行读取文件使用
malloc
,free
,防止内存泄漏使用
printSummary(hit_count, miss_count, eviction_count);
,打印输出数据是对齐,且不会出现跨块访问。
答案
|
Part B Optimizing Matrix Transpose
完成trans.c
文件,实现一个转置矩阵代码transpose_submit
,尽可能少的产生cache未命中。
相关内容
只允许使用最多12个本地int变量,调用函数中一起计算
不允许使用long或者其他存储数值的方法,不允许使用数组
不能递归
使用参考模拟器来测试代码,cache参数为
s = 5, E = 1, b = 5
int为4个字节。
只有三种形式的矩阵,32*32,64*64,61*67。
-
矩阵乘法的分块技术
两个数组的第一个数据,在cache中存储到相同位置,数组按照行优先存储,数据是对齐的
./test-trans -M 32 -N 32
测试函数./tracegen -M 64 -N 64 -F 0
输出错误信息
思路
数据是对齐的,所以一个cache行包含32个字节,存储8个int数据,cache能存储256个int数据,根据。根据3B^2 << C
,块长为B=82B^2 << C
,块长<=11,由于cache行可以存8个数据,所以选择块长8。
以32*32的矩阵为例,除了处于对角线上的块会产生冲突不命中,其他块都可以优化不命中情况
以上这种情况对32*32是成立的,64*64和61*67不成立,所以重新思考了这道题的解法,根据data lab中数据的操作都是在内存中进行的。
数组的首地址给出后,行优先数据为一维连续存储形式
这道题可以转换为数组A[N][M]在内存中连续存放,每一个位置x的数根据相同的转换方式保存到数组B[M][N]的位置y,转换公式为i_a = x / M
,j_a = x % M
,y = j_a * N + i_a * M
。于是存储公式为B(y) = A(x)
。
示意图如上,cache行存2个数据,3*3的数组中,无法直观看出内存区别,而cache的分块目的是为了在内存中读取到cache时减少miss次数,所以我们根据内存进行重排数组,改为5*2的数组。
所以这道题可以把数组转换为32列的任意数组,由于一行只有32列,远远小于cache的容量256个数据,所以相邻行的上下两个数据不会映射的同一个cache行。
需要把文件放入linux的文件夹中,如果在共享文件夹中会出现运行超时。
32 x 32
基本步骤:
重排数组
处理AB数组中x,y映射相同的位置,先用局部变量保存,然后处理这一行的其他数据,最后保存在B数组的中,cache行自动换出。
分析原因
当
A[i][j]
与B[j][i]
的cache映射相同set内时,取出A[i][j]
中的值,写入B数组时会换出A的cache行,导致下次访问A的同一行cache数据时需要继续换出一次。
解决办法
用局部变量保存访问冲突的值,等循环结束后,在写入B中。
计算所在行,x表示数组一维连续内存的位置(0开始),cache 组号
s=(x%256 ) / 8;
结果
void main(int M, int N, int A[N][M], int B[M][N]) { |
miss数量287,满分
64 x 64
出现一个cache行中两次相同映射的问题
分析原因
在32 x 32的数组中,一个cache行为8,块为8x8,一个cache行最多只有对角线的的一个元素冲突miss,但是64x64的数组中,8x8的块中,前四行与后四行冲突miss,所以一个cache行的8个数据中,最多有两个元素冲突miss
解决办法
继续添加一个局部变量记录冲突位置,一行遍历完后再处理。
继续出现了只遍历到了32,在64 X 64的数组转换为32列时,行数为128。
miss数量为4611,还需要继续调低。
分析原因
错误答案
64X64中,改了内存排列后,第二行与第一行的转置不在同一cache行内。
按照左上右上,左下,右下顺序。
结果
分析原因
没有拿到满分,按照上下划分为两个4X8的数组
下边的4X8数组,一行中的后四列在B数组中会cache冲突行,如图
注意:
上四行转置之后,B数组的下四行正在cache中,为了不换出,先转置A数组的右下,再左下。
结果
减少到1547,但是还没有满分。
继续修改
题目要求减少miss数量,可以利用cache中空闲的地方保存数据 最后在替换出去
如图,A的上半部分的后四列存到B的后四列中
下半部分的第一列,先把B数组的第一行后四列保存到下部分的第一行,这样第一个cache就替换完成,依次完成其他行,最后把右下角转置过去。
结果
miss数1339,差39次满分,没有找到优化位置。
61 X 67
结果
最终得分
拿到了51.5分,之后有时间再来查代码优化的地方。