目录
实验目的与要求
1、掌握应用程序性能的优化方法;
2、理解存储器层次结构在程序运行过程中所起的重要作用;
3、让学生更好地理解高速缓存对程序性能的影响;
本实验将帮助了解缓存对C程序性能的影响。实验由两部分组成。在第一部分中,将编写一个模拟高速缓存行为的小型C程序(大约200-300行)。在第二部分中,将优化一个小的矩阵转置函数,目标是最小化缓存未命中的数量。
实验设备与软件环境
1.Linux操作系统---64位 Ubuntu 18.04
-
C编译环境(gcc)
-
计算机
实验过程与结果(可贴图)
第一部分:在csim.c下面编写一个缓存模拟器来模拟cache的行为,并且规定该模拟器用LRU替换策略,即替换某组中最后一次访问时间最久远的一块,还要支持一些输入可选参数
我们知道目前的操作和反馈大概有
操作有四种:
I:加载指令
L:加载数据
S:存储数据
M:修改数据
反馈有三种:
hit:命中
miss:不命中
eviction:替换
首先我们要清楚cache的结构:cache一般分为S组,每组有E块。每块结构为一个有效位v,一个标志位tag,一个数据块data。cache地址分为三部分:标志位tag,组索引s,块偏移b
cache的运作方式是怎样的:
有一个cache地址,这个cache地址提供了标志tag,组索引s和块偏移b
首先根据组索引找到组,然后遍历该组所有块,如果块有效位v为1,则用tag与该块的tag比较,如果相同,那就hit,那就可以匹配
如果遍历完组中所有块,没有hit,那么就miss,这时就需要唤醒替换,把需要的块替换进来
这里替换有一种特殊情况需要判断,就是组满了,组中每一块valid都为1,那么我们要根据LRU策略,选一块最近访问时间最久远的块替换掉
所以,我们的思路就是,需要有一个cache结构,开始构建cache模拟器
定义整个cache。S,E,B分别代表组数,每组块数,每块数据位的字节数
初始化一个cache,这个初始化主要就是申请一个S组,每组E块(一般行和块相等,行是cache的概念,块是主存的概念,我比较喜欢两个都叫块),每块数据B字的cache,然后设置每块的有效位0,标志位-1,时间戳0
根据上面的cache运作机制,我们应当根据cache地址去查找需要的块是否存在,再进行后续操作。该函数遍历该组中所有快,只有v=1且tag相同,那就hit,返回这个块的索引即可。否则miss,且返回-1
我们要排除是否全满这一特殊情况。该函数实现,如果没有全满,则选第一个有效位为0的块作为替换块,返回该索引,如果满了,那返回-1
假设没有满,那我们就设置更新策略,更新返回的索引块即可。这里参数op_set代表第几组,i代表组中第几块。然后LRU的实现策略是更新的这一块的时间戳设置为0,同组中其他有效位位1的块时间戳+1,这样做代表该组中时间戳最大的块为最久没有访问的块
根据上述测实现策略,可以得到LRU策略函数,查找某组中最久没访问的就是找有效位为1的哪一块时间戳最大,查找到该组的索引返回即可,然后再调用update
组装一下update,isfull,findurl三个函数为updateinfo函数
free
gettrace
跑起来后的效果
第二部分
这个需要我们先安装valgrind
sudo apt install valgrind
这道题的要求如下:
1.32×32:miss < 300
2.64×64:miss < 1300
3.61×67:miss < 2000
1.我一开始用的两个for去套,很难实现
A是顺序访问的,每一块8个int会有1个导致miss,剩下7个hit,不用对A的访问进行操作
A在读完一个缓存块的8个int后,会导致B不命中8个缓存块,B会修改这8个缓存块的每一个的第一个int(4字节),这8个缓存块的剩下7个int就没用到
展开循环,A每读一个块的8个int后,我们竖着读下一个块,一共竖着读8个块,这样就能让B修改那8个缓存块的后7个int
2.cache块没有完全利用,我们的cache有8个int啊,4×4展开肯定不能完全利用,那我们还是可以用8×8展开,只不过8×8中再4×4,具体是每一个8×8块中,分别移动左上,右上,左下,右下的4×4块,说白了就是套两层,8×8整体移动,只不过8×8中不是直接用,而是分四次4×4的搬运
3.直接8*8再4*4即可
具体的效果
1.32*32
2.64*64
3.61*67
操作异常问题与解决方案
一开始没有包含对应的unistd导致getopt一致报错,包含一下就可以了。
实验总结
通过实验任务的一步步完成,我仿佛置身于一个编程迷宫,需要用巧妙的策略和算法来解决缓存优化的难题。
替换策略、写回/写分配策略等概念,让我感受到了计算机系统中微妙而又重要的平衡。
通过实现特定的替换策略和写回/写分配策略,我逐渐掌握了如何有效地利用缓存来提高程序性能的技巧。
通过调整缓存策略和优化程序代码,我逐步提高了程序的效率,并体会到了优化对程序性能的重要性。