内容概述:
- 基本概念
- 原理
- 和主存的映射方式
- 替换算法
- 写策略
1.基本概念
其他存储器相较于CPU的速度差距很大
设计更高速的存储单元
Cache通常被集成在CPU内部
用SRAM实现,成本高,但是速度快
要考虑到集成度的原因,Cache不能做的很大,所以空间较小
2.原理
辅存→内存→Cache→CPU
内存中的存放此时运行的程序
但是大部分指令都不会频繁的使用
所以要将频繁使用的一些指令代码复制到Cache里面
让CPU直接在Cache里面取指令和数据
CPU和内存直接的速度差距矛盾就会被缓和
局部性原理(适用于指令和数据)
空间局部性
最近的未来要用到的信息,很可能与现在使用的信息存储空间上是相邻的
eg. 数组元素,顺序执行的指令代码
时间局部性
在最近的未来要用到的信息,很可能是现在正在使用的信息
eg.循环结构的指令代码
基于局部性原理,得出结论
可以把CPU目前访问的地址 周围 的部分数据放入Cache中
如何界定周围:
将主存的存储空间 分块
主存和Cache之间以“块”为单位进行数据交换
每次被访问的主存块,一定会被立即调入Cache
操作系统中,通常将主存里面的一个块,称为一个页
块也可以称为行
主存的地址一共22位
块号 12位 块内地址 10位
所以依据原理,访问二维数组时,行优先相较于列优先,空间局部性差,速度慢
性能分析
如果CPU想要的数据能够直接在Cache中找到
我们称为 命中
命中率H:CPU欲访问的信息已在Cache中的比率
缺失(未命中)率 M = 1-H
假设CPU访问Cache耗时tc
访问主存耗时tm
由于CPU每次都会优先访问Cache
如果Cache未命中,才会去访问主存
平均访问时间=
H tc + (1-H)(tc + tm)
如果同时访问主存和Cache
如果Cache命中了则立刻停止访问主存
平均访问时间=
H tc + (1-H)tm
3.和主存的映射方式
如何区分Cache与主存的数据块的对应关系
Cache有标记位 和 有效位
标记位: 初始置零,主存有存入后,修改为主存的标号(位数与主存块号一致)
有效位: 放入之后从0变为1
主存地址: 主存块号+块内地址
全相联映射
主存块可以放在Cache的任意位置
Cache行(Cache块)与主存块大小相等
CPU访问主存地址的过程
- 访问主存地址的前几位(主存块号),对比Cache所有块的标记
- 如果标记匹配,且有效位为1,则Cache命中,接着访问块内地址
- 未命中,则正常访问主存
直接映射
每个主存块只能放到一个特定的位置
Cache块号 = 主存块号 % Cache总块数
缺点:Cache的其他位置虽然有空闲位置,但是不可以使用,只能传到固定位置
例如,Cache如果有8个行
判断主存中第0块,0%8=0,放到Cache的第0行
第8块,8%8=0,则覆盖第0行的数据,并修改标记
如果Cache的总块数=2的n次幂,
则主存块号末尾的n位(二进制)就直接反映了他在Cache中的位置
则可以优化标记,存储主存块号的其余位作为标记即可
主存块号=标记+行号
CPU访问主存地址的过程
- 根据主存块号的后n位确定Cache行
- 若主存块号的前几位和标记匹配,且有效位为1,则命中,访问存储单元
- 若未命中,则正常直接访问主存
组相联映射
Cache块分为若干组,每个主存块可以放到特定分组中的任意一个位置
组号 = 主存号 % 分组数
常见分法:二路组相联 即两个块为一组
例如,Cache一共有8个行,则分组数为4
优化标记:4=2的2次幂,相当于只看最后两位即可判断是哪一组的
标记位可以不标记最后两位
主存块号=标记+组号
CPU访问主存地址的过程
- 根据主存块号的后几位,确定所属的分组号
- 再判断前几位对比标记,如果匹配且有效位=1,则Cache命中,访问块内地址d
- 若未命中,则正常直接访问主存
4.替换算法
Cache很小,内存很大,如果Cache满了怎么办
全相联映射:Cache完全满了才需要替换,需要在全局选择呢替换哪一块
直接映射:对应位置非空,则可以直接替换,无需考虑替换算法
组相联映射:分组内满了才需要替换,需要在分组内选择替换哪一块
随机算法 RAND
顾名思义,随机选择一块进行替换,完全没有考虑局部性原理,命中率低,效果不稳定
先进先出算法 FIFO
替换最先被调入Cache的块,实现简单,依然没有考虑局部性原理
(抖动现象:频繁的换入换出现象,刚刚被调走的块很快又被调入)
近期最少使用 LRU
为每一个Cache块都设置计数器,用于记录这个块多久没有被访问到了,替换时,优先替换计数器最大的一个块
原理:
1.命中时,命中的行的计数器清零,比其计数器值低的计数器加1,其余不变
因为已经很大的数,没必要再浪费资源+1
2.未命中且有空闲行时,装入新的行,计数器置0,其他空闲行+1
3.未命中且没有空闲行,计数器最大的行信息块被替换,新装入的块计数器置0,其余加1
Cache块的总数=2的n次幂,则计数器需要n位即可
且Cache装满了,计数器的值一定不重复
基于局部性原理,近期被访问过的主存块,在将来也会被再次访问
淘汰最久没有被访问的块是合理的
运行效果很好,Cache命中率高
但是如果频繁访问的主存块数量>Cache行的数量,则可能会发生抖动
最近不经常使用 LFU
为每一个Cache块都设置计数器,用于记录每一个Cache被访问过几次,然后替换计数器最小的
原理:
新调入的计数器置零,每次被访问一次计数器就+1,需要替换时选择计数器最小的一行
若有多个最小,则可以按行号递增顺序或者FIFO策略进行选择
曾经被访问的主存块在未来不一定能用到,但是并没有很好的遵循局部性原理,实际运行效果不如LRU
5.写策略
CPU修改了Cache中的数据副本,怎么样保证与主存中的数据母本的一致性
写命中
- 全写法
写直通法,当CPU对Cache写命中时,必须要将数据同时写入Cache和主存
访存次数增加,速度变慢,但是能保证数据的一致性
写缓冲:用SRAM实现的FIFO队列,先写到写缓冲中,要比直接写到内存里面要块
再利用专门的控制电路逐一写回
淘汰Cache中的内容时,也不需要写回
CPU的速度很快,若写操作不频繁,效果很好,频繁的话,可能会因为写缓冲饱和而发生阻塞
- 写回法
当CPU对Cache写命中时,只修改Cache的内容,而不立即写入内存,只有在当此块被换出再写入内存
未被修改过的块,不必写回
在Cache中添加一个脏位,表示是否被修改过,初始全部置零,修改后,该行置1
减少了访存次数,但是存在数据不一致的隐患
写不命中
- 写分配法
当CPU对Cache没有命中,则把主存对应的整块调入Cache中,在Cache中修改,通常搭配写回法使用
即,如果未命中,正常调入Cache再利用写回法进行后续的修改操作
- 非写分配法
当CPU对Cache没有命中,则只写入内存,不调入Cache,搭配全写法
这样的情况,只有读未命中,才会将内存的数据调入Cache
多级Cache
离CPU越近,速度越快,容量越小
各级Cache之间,采用 全写法+非写分配法
Cache与主存之间,采用 写回法+写分配法