第七章 存储系统
链接: https://pan.baidu.com/s/1WyftXZzso0_ePWaMDDCUPw
提取码:hu2b
7.1 存储系统的层次结构
7.1.1 存储系统的层次结构概述
7.1.1从单级存储器到多级存储器
1.从用户的角度来看,存储器的三个主要指标:
容量、速度和价格(指每位价格)
2.人们对这三个指标的要求
容量大、速度快、价格低
3.三个要求是相互矛盾的
- 速度越快,每位价格就越高;
- 容量越大,每位价格就越低;
- 容量越大,速度越慢。
多级存储层次
程序访问的局部性原理
7.1.2 存储系统的性能参数
平均每位价格C1
命中率H
平均访问时间T(A)
7.1.3 三级存储系统
“Cache一主存”和“主存一辅存”层次
从主存的角度来看
- “Cache—主存”层次:弥补主存速度的不足
- “主存一辅存”层次:弥补主存容量的不足
1.“Cache----主存”层次
主存与CPU的速度差距
“Cache一主存”层次
2.“主存一辅存”层次
7.1.4 存储层次的四个问题
映像规则 查找算法 替换算法 写策略
7.2 Cache的基本知识
7.2.1 基本结构和原理
Cache是按块进行管理的。Cache和主存均被分割称大小相同的块。信息以块为单位调入Cache。相应的,CPU的访存地址被分割成两部分:块地址和块内位移。
7.2.2 映像规则
1.全相联映象
全相联:主存中的任一块可以被放置到Cache中的任意一个位置。
对比: 阅览室位置——随便坐
特点: 空间利用率最高,冲突概率最低,实现最复杂。
2.直接映象
直接映象:主存中的每一块只能被放置到Gache中唯一的一个位置。
举例:(循环分配)
对比: 阅览室位置——只有一个位置可以坐
特点: 空间利用率最低,冲突概率最高,实现最简单。
3.组相联
7.2.3 查找算法
1.通过查找目录表来实现
目录表的结构
- 主存块的块地址的高位部分,称为标识。
- 每个主存块能唯一地由其标识来确定
7.2.5 替换算法
3种替换策略
随机替换 随机选择被替换的一块
- 硬件容易实现,需要随机数产生器
- 均匀使用一组中的各块
- 可能替换即将被访问的那一块
最近最少使用Least-recently used(LRU) 选择一组中最近最少被访问的块作为被替换块
- 假定最近被访问的块很可能会一再访问
- Cache中需要额外的位记录访问历史
先进先出(FIFO)选择一组中最先进入cache的一块
7.2.6 写策略
两种写策略的比较
写回法的优点: 速度快,所使用的存储器,带宽较低。
**写直达法的优点: ** 易于实现,一致性好。
采用写直达法时,若在进行“写”操作的过程中CPU必须等待,直到“写”操作结束。则称CPU写停顿。
减少写停顿的一种常用的优化技术: 采用写缓冲器
“写”操作时的调块
按写分配(写时取)
写失效时,先把所写单元所在的块调入Cache,再行写入。
不按写分配(绕写法)
写失效时,直接写入下一级存储器而不调块。
写策略与调块
写回法———按写分配
写直达法———不按写分配
7.2.7 Cache性能分析
1.失效率
- 与硬件速度无关
- 容易产生一些误导
2.平均访存时间
平均访存时间=命中时间+失效率×失效开销
3.程序执行时间
CPU时间=〔CPU执行周期数+存储器停顿周期数)×时钟周期时间
其中:
- 存储器停顿时钟周期数=“读”的次数×读失效率×读失效开销+“写”的次数×写失效率×写失效开销
- 存储器停顿时钟周期数=访存次数×失效率×失效开销
7.2.8 改进Cache性能
1.降低不命中率 2.减少不命中开销 3.减少命中时间
7.3 降低Cache的不命中率
7.3.1 三种类型的不命中
1.三种失效(3C)
强制性失效(Compulsory miss)当第一次访问一个块时,该块不在Cache中,需从下一级存储器中调入Cache,这就是强制性失效。(冷启动失效,首次访问失效)
容量失效(Capacity miss )
如果程序执行时所需的块不能全部调入Cache中,则当某些块被替换后,若又重新被访问,就会发生失效。这种失效称为容量失效。
冲突失效(Conflict miss)
在组相联或直接映象Cache中,若太多的块映象到同一组(块)中,则会出现该组中某个块被别的块替换(即使别的组或块有空闲位置),然后又被重新访问的情况。这就是发生了冲突失效。(碰撞失效,干扰失效)
可以看出
- 相联度越高,冲突失效就越少;
- 强制性失效和容量失效不受相联度的影响;
- 强制性失效不受Cache容量的影响,但容量失效却随着容量的增加而减少;
- 表中的数据符合2:1的Cache经验规则,即大小为N的直接映象Cache的失效率约等于大小为N/2的2路组相联Cache的失效率。
减少三种失效的方法
强制性失效:增加块大小,预取(本身很少)
容量失效:增加容量(抖动现象)
冲突失效:提高相联度(理想情况:全相联)
许多降低失效率的方法会增加命中时间或失效开销
7.3.2 增加Cache块大小
降低不命中率最简单的方法是增加块大小
增加块大小会产生双重作用:
-
增加了空间局部性
-
减少了Cache块中的数目,所以有可能会增加冲突不命中
在块大小比较小的情况下,上述的的第一种作用超过第二种作用,从而使不命中率下降。但等到块大小较大时,第二种作用超过了第一种作用,就反而使不命中率上升了。此外,增加块大小也会增加不命中开销。
7.3.3 增加Cache容量
缺点:增加成本,还可能增加命中时间
7.3.4 提高相联度
一般来说,改进访存时间的某一方面是以增加另一方面为代价的。例如,增加块大小会增加不命中开销,而提高相联度则是以增加命中时间为代价的。
7.3.5 伪相联Cache
既能获得多路组相联的低不命中率,又能保持直接映像cache的命中速度。
7.3.6 硬件预取
1.指令和数据都可以预取
2.预取内容既可放入Cache,也可放在外缓冲器中。例如:指令流缓冲器
3.指令预取通常由Gache之外的硬件完成
4.预取效果
Joppi的研究结果
指令预取(4KB,直接映象Cache,块大小=16B)
-
1个块的指令流缓冲器:捕获15%~25%的失效
-
4个块的指令流缓冲器:捕获50%
-
16个块的指令流缓冲器:捕获72%
数据预取(4KB,直接映象Cache)
-
1个数据流缓冲器:捕获25%的失效
-
还可以采用多个数据流缓冲器
7.3.7 编译器控制的预取
在编译时加入预取指令,在数据被用到之前发出预取请求。
1.预取有以下几种类型:
寄存器预取:把数据取到寄存器中。
Cache预取:只将数据取到Cache中。
故障性预取:在预取时,若出现虚地址故障或违反保护权限,就会发生异常。
非故障性预取:在遇到这种情况时则不会发生异常,因为这时它会放弃预取,转变为空操作。
7.3.8 编译优化
- 程序代码和数据重组
- 内外循环交换
- 分块
7.3.9 牺牲Cache
牺牲Cache中存放因冲突而被替换出去的那些块(即“牺牲者”)
7.4 减少Cache的不命中开销
7.4.1 采用两级Cache
7.4.2 让读不命中优先于写
1.Cache中的写缓冲器导致对存储器访问的复杂化
写缓冲器进行的写入操作是滞后进行的,所以该缓冲器也被称为后行写数缓冲器。
7.4.3 写缓冲合并
为了减少访问所花费的时间,写直达cache一般都采用一个写缓冲器。如果该缓冲器不满,就可以把数据和相应地址写入该缓冲器。从CPU的角度来看,这个写操作就算是完成了,CPU可以继续执行后面的指令,而写缓冲器则负责将其写入存储器。
7.4.4 请求字处理技术
7.4.5 非阻塞Cache技术
7.5 减少命中时间
7.5.1 容量小,结构简单的cache
命中时间直接影响到处理器的时钟频率。在当今的许多计算机中,往往是Cache的访问时间限制了处理器的时钟频率。
1.硬件越简单,速度就越快。
2.应使Cache足够小,以便可以与CPU一起放在同一块芯片上。
7.5.2 虚拟cache
1.虚拟Cache
访问Cache的索引以及Cache中的标识都是虚拟地址(一部分)。
2.物理Cache
使用物理地址的传统Cache。
7.5.3 cache访问流水化
1.对第一级Cache的访问按流水方式组织
2.访问Cache需要多个时钟周期才可以完成
例如
- Pentium访问指令Cache需要一个时钟周期
- Pentium Pro到PentiumⅢ需要两个时钟周期
- Pentium4则需要4个时钟周期
7.5.4 踪迹cache
7.5.5 cache优化技术总结