1. cache出现的原因
cpu: 处理速度快, 但是存储容量小,
主存: 处理速度低,但是存储容量大;
为了弥补两者之间的差距, 使用了缓存;
要想充分发挥cache
的能力,
需要保证 cpu 所需要的数据和 指令大多数都能够在cache中获取
,
这里使用到了程序的局部性原理,
1.1 程序的局部性原理
时间的局部性: 当前正在使用的指令和数据,在不久的将来仍会被使用到,
所以当前正在指令的指令和数据应该放到cache中,以便于将来在执行时, 快速的提取出来;
空间局部性
当前正在使用的指令和数据,在不久的将来,空间位置上相邻的指令和数据将会被使用到的概率较大;,
由时间局部性和空间局部性,从而将当前正在执行的指令和数据放到cache中, 并且将相邻的指令和数据也放到cache 缓存当中去
1.2 Cache的工作原理
将主存储器和cache 分别分成多个块;
将主存储器或者cache分成若干块,
则主存分为两部分,
- 一部分为块内偏移地址,其位数决定了块的大小;
- 另一部分为主存的编号,块的编号;
cache地址同样分成块内地址和缓存块号;
而在实际应用当中,并没形成真正的cache地址;
注意到,
内存块内地址部分和缓存中的块内地址部分大小是相同的
所以主存和缓存各自对应的块内地址部分, 位数是完全相同的;
一个在内存和cache中传送时, 是整体按照块传送的;
块内字节的顺序不会发生任何变化,
cache 上的标记,标记了主存快和内存块之间的对应关系,
cpu 要从主存中取出某个主存块号时, 则会先从缓存块号中寻找有无对应的标记, 如果有,则直接从cache缓存块号中取出;
主存与缓存按块存储,块的大小相同,块内地址相同。
1.3 cache 的命中率
缓存共有C 块
主存共有 M块,
M
>
>
C
M>> C
M>>C
命中:
主存块调入缓存;
主存块与缓存块建立了对应关系;
用标记记录 与缓存块建立了对应关系的主存块号;
未命中
主存块未调入缓存
主存块与缓存块 未建立对应关系;
cpu 欲访问的信息在cache中的比率(即另一部分在主存中,没有缓存到cache中), 称为命中率
命中率与cache 的容量与块长有关;
一般每块可取4-8个字;
块长取一个周期内从主存调出的信息长度;
CRAY_1 16体交叉 块长取16个存储字;
IBM 370/168 4体叉 块长取 4个存储字;
1.4 主存系统的效率
主存系统的访问效率与命中率有关;
访问效率使用e
表示,
访问效率的最小值: cpu的命中率为0, 即欲访问的信息在cache中为0, 此时h = 0,
e
=
t
c
/
t
m
e = t_{c} /t_{m}
e=tc/tm;
访问效率的最大值, 命中率为1, cpu每次访问的都是cache, 没有访问主存. 则访问效率此时 = 命中率的倒数;
注意这里的公式, 代表了
访问cache 和 访问主存是并行进行的;
如果cpu先访问cache ,再访问主存, 这里的公式将发生变化
2. Cache 基本结构
cache 是在cpu 和内存之间作为一个信息传送的缓冲;
图中的主存便是实际中的内存为主;
2.1 cache 工作的基本原理
-
cpu 访问内存,需要给出地址,该地址包括块号和块内地址两部分;
-
由于cache 和内存之间是以块为单位,进行数据传送的, 所以此时cpu给出的块内地址便可以直接做为cache的块内地址。
-
然后使用块号, 在cache 的映射机构中(图中右边红色部分)进行确认是否发生命中。 若发生命中,需要进一步确认当前的主存块号保存在哪个 cache 块中, 形成下方的块号当中。
-
若没有命中,需要查阅一下,cache 当中是否还有空间能够装入主存块。 如果cache有空间, 则访问主存,将数据块装入到cache当中。
-
如果此时cache没有空间。 则启动cache的替换机构(图中左边红色部分),由替换机构决定cache 中哪一个数据块写回到主存当中,或者是直接丢弃, 然后将主存当中需要用到的块写入到cache 当中。
2.2 cache 中地址映射和变换机构
如上图中右边红色部分,
- 主存cache的地址映射机构
map
:
给出一种规则,规定主存中的块如果可以放到cache块中, 那么映射机构便规定了该块可以放到cache中哪些块中;
比如说, 同学们去公共教室做实验, 这里便会规定哪些计算机是同学们可以使用的, 哪些是不可以用的,留作管理员使用的。
-
主存cache的地址变换机构:
将主存的块号转换成 cache 的块号,
或者将主存的地址转换成cache 的地址,
在cache 当中找到相应的主存块号。 -
cache的替换机构:
当cache中给定的位置已经 占满, 使用替换算法, 决定将cache哪些块给替换掉,
2.3 主存和cache之间的通信
主存和cache 之间是有一条直接通路的, 通过该直接通路完成主存和cache 之间的信息交换的,
若cpu需要访问的信息不在cache块中, 即发生不命中的情况,
则主存通过下方的数据总线,先将信息传送给cpu , 并且同时将该块的信息放到cache存储体中;
-
cache存储体, 需要用的信息,以块为单位保存在cache存储体当中;
-
映射机构: 主存的块 哪些块可以放到cache的哪些地方
-
变换机构: 主存的块在cache哪一个块中查找;
3. Cache的读写操作
cache 中的块是内存当中某些块的缓存, 即cache 中缓存的信息在内存中也有。
3.1 读操作
那么读操作:
当对cache 中的块进行读操作时,不会对cache块中的任何信息进行修改。主存和cache的信息便是一致的,相同的。
3.2 写操作
写操作,会改变cache块中的内容信息;
为了解决cache和主存的一致性问题;
- 写直达法 write_through
写操作时数据既写入 cache又写入主存,
写操作时间就是访问主存的时间
, cache块退出时,
不需要对主存执行写操作, 更新策略比较容易实现。
不足之处: 当一个for循环,需要求和时, 当和的结果需要保存到某一个内存单元中, 此时,写直达法便会造成,该求和的内存单元频繁的和 cache块之间 发生信息交换。
- 写回法 write -back
写操作时, 只把数据写入cache, 而不写入主存, 当cache数据被替换出去时, 才将数据写回主存。
此时,写操作时间便是访问cache的时间
,
当cache块退出时, 被替换的块需写回主存,增加了cache的复杂性。
不足:并行计算机中, 在多处理器情况下, 每个cpu都会有自己的cache,内存的一个块在各个处理的cache中都会有一个副本。如何保证,这多个副本之间信息一致性的问题。
3.3 cache的改进
增加cache的级数
- 片载cache: 离处理器比较近或者离core核比较近的,可以直接将cache制作在cpu内部当中。甚至会在cpu内部做两级的cache.
现代处理器,都是多核的,每一个核都会有自己的cache.
并且多个核还会另外有公用的cache
统一缓存: 冯诺依曼结构的计算机 是将指令和数据以同等的方式保存在存储器当中, cache也是一个存储器; 冯氏结构 是将指令和数据统一的放到一个cache 当中。
分立缓存: 而现代计算机会使用分立缓存,
指令cache, 数据cache;
与指令执行的控制方式有关, 是否流水。
Pentium 8k 指令cache, 8k 数据cache.
Power PC620, 32k 指令cache, 32k 数据cache.
4. cache和主存之间的地址映射
主存中任意一个块要加载到cache当中的话,可以加载到cache 当中的哪些块中。
4.1直接映射
主存中任意一个给定的块只能装载到cache当中某个指定的块中。
以 cache 存储体为尺度,将主存储体划分为若干个区, 每个区的大小 和cache 存储体的大小相同。
此时,每个区当中包含的字块数和 cache存储体当中包含的字块数是相同的。
每个区中编号,都从0开始编号,一直到
2
c
−
1
2^c -1
2c−1, 在进行映射的时候,
主存储体中任何一个区的字块0 只能 放到 cache中 字块0 当中;
主存储体中任何一个区的字块1 只能 放到 cache中字块1 当中;
上述方式便是直接映射。
此时, cpu 给出一个主存储体的地址,
该地址包含三个部分,
区号 + 块号 + 块内偏移地址
主存地址中:
主存字块标记对应 cache中的标记,
用来鉴别主存中的该块号 是否被放到cache当中。
主存中的字块地址 便是对应cache中的字块;
好处是,检查块是否对应时, 只需要检查主存的区号和cache标记中的 其中一个对应的标记位是否相同就可以。
这种方式的不足:
命中率不高, 如果读入的指令是跳转指令, 正好跳到第二个区中的第一个字块, 则需要将cache当中的字块0替换出来,重新将第二个区中的第一个字块写入到其中, 而此时cache当中的其他字块却是空着的。
造成这个问题的原因便是:
- cache中每个缓存块 可以和若干个 主存块对应
- 但是,实际存储时,每个缓存块却只能存放主存块中的一个;即,虽然对应多个,但只能存放一个;
4.2 全 相联映射
好处是:主存储器中任意一个块可以放到cache存储器中任意一个位置。
不足之处:当需要检查, 主存储器中的块是放到cache存储器中的哪个块时,
此时的标记位 = 主存字块标记 + 字块内地址;
电路实现起来不简单明了。
此时标记位变长了, 则需要和每个标记位进行比较,
比较器的位数变多了。
遍历次数变多了。
4.3 组 相联映射
组相联是直接相联和全相联的配合,
- 现将cache 分块;
- 在将这些cache 块按组进行划分,每组中cache块的数目,可以根据情况设定;
- 将主存储器进行划分,这里进行分区, 此时每个区的大小= 上面cache的组数,表明主存储器中每个区中的块数 = cache的组数
这样,每次将主存储器中的一个区 缓存到 cache块中;
- 映射的时候, 主存储器的一个区中第0块,可以放到cache缓存中第0组中的任意一个块位置;
这里的对应关系是,
主存储器中,在一个区中,每个块在区里的编号决定了该主存块会被放到cache中的哪个组里。
这里用到了直接相联的思想:给定的一个块 只能放到给定的cache一个组里。
也包含了全相联的思想:内存的一个块, 可以放到cache给定一个组中的任何一个位置。
此外, 靠近cpu的cache 要求高速度,此时可以采用直接相联, 中间层次使用组相联, 越远的使用全相联,举例越远要求对cache的利用率越高;
5. 替换算法
选择cache中哪些块可以退出了,腾出位置,用来放入新的内存块到cache中。
替换的核心思想是利用了 程序的局部性原理,
即某段程序中, 离该程序越近的内容,将来越有可能被使用到, 越远的则不会被使用。
4.3 FIFO 先进先出算法
最先放入到 缓存的块,则优先被替换出去;
4.3 LRU 近期最少使用算法
替换出去的块是cpu 不在使用的块,
或者是在cache块当中, 所有的这些块中, 某个块在将来需要被cpu读取该块或写该块, 这个时间间隔越长的块, 则优先将该块替换出去。
小结: 主存和cache之间的 地址映射方法
直接相联映射:某一个主存块只能固定 映射到某一缓存块上。 结构简单, 但是cache的空间利用率低;
全相联: 某一主存块能映射到任一 缓存块当中; 成本高,速度慢,但cache利用率高。
组相联: 某一主存块只能映射到 某一缓存组中的任一块中