Cache和虚拟存储器

Cache的基本概念和原理

CPU缓存 - 维基百科

在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。

基本概念

双端口RAM和多模块存储器提高了存储器的工作速度,但是CPU速度太快了,所以存储器的速度还可以进一步优化,此时我们需要速度更快的存储单元,再结合程序的局部性原理,所以我们引入了"Cache-主存"机制,即引入Cache层。

上面我们提到了存取速度更快的存储单元,我们之前说的双端口RAM和多模块存储器指的是主存,属于DRAM,这里我们可以把DRAM换成SRAM,也就是Cache,速度更快,但是造价更高,当然Cache的容量也更小,一般就几十M,在windows的资源管理器里也可以看到自己电脑的Cache有多大。

Cache和主存的存取速度一般是数量级的差距。(Cache的速度可以比主存快上几十甚至上百倍)

windows下查看高速缓存存储器的容量。

image-20230327143157204

程序的局部性分为空间局部性和时间局部性。简单来说就是CPU访问了一个地址A,CPU之后访问的地址大概率会在A的附近,这就是空间局部性。还有CPU最近未来要用到的信息多半就是现在正在使用的信息(比如循环大概率会重复访问一些存储单元),这就是时间局部性。

程序局部性+SRAM引出了Cache层。既然我现在使用的信息大概率在不久的将来会用到,那就可以把当前地址附近的数据都放入Cache中,使得CPU在同等时间内可以计算更多的数据(同等时间内从Cache中取得比内存更多的数据),也就使得计算机处理任务的速度更快了。

image-20230327144350418

Cache的命中率

上面提到我们把内存里的部分数据放入Cache中使得CPU可以处理更多的数据,但是Cache的容量很小,不可能放下所有需要的数据,所以CPU要访问的数据可能没有放在Cache里面,而依然在主存里面。所以我们可以引出命中率, 命中率 H : C P U 要访问的信息已在 C a c h e 中的比例,缺失率 M = 1 − 命中率 H 命中率H:CPU要访问的信息已在Cache中的比例,缺失率M=1-命中率H 命中率HCPU要访问的信息已在Cache中的比例,缺失率M=1命中率H,从这里也可以看出如果我们提高缓存的命中率可以使得CPU更快的处理数据,提高系统性能。

在这里插入图片描述Cache—主存 系统的平均访问时间t=Htc+(1-H)(tc+tm) ,先访问Cache,没命中再去访问主存

  • H是Cache的命中率

  • tc是CPU访问Cache的耗时

  • (1-H)是缓存的缺失率,tm是CPU访问主存的耗时,tc+tm的意思是访问Cache没找到要的数据,再去访问主存,所以Cache没命中访问主存花费的时间是(1-H)(tc+tm)

t=Htc+(1-H)tm,这种情况的t指的是Cache和主存同时访问,若Cache命中则立即停止访问主存,这种策略性能略高。

待解决的问题

下面贴王道的课件

把目前这个主存地址周围的数据调入Cache中,怎么来定义这个周围?采用分块的方式,比如主存可以以1KB为一个块,然后以块为单位与Cache进行数据交换。比如图中就把主存地址分为块号和块内地址,主存地址存在很多种划分,这些都是逻辑上的,物理上由计算机硬件实现的。软件也可以实现地址划分,比如操作系统里的虚拟内存就是操作系统这个软件实现的。

Cache和主存的映射方式

解决Cache与主存数据块的对应关系。

王道的课件:

image-20230327152155703

前面提到了主存以块为单位来和Cache进行数据交换

图中给了三种策略,分别是全相联映射,直接映射和组相联映射。

  • 全相联映射:主存块可以放在Cache里的任意一个位置。
  • 直接映射:主存块号%Cache总块数 得到Cache的块号,以图中给的例子为例,Cache有8块,那主存里编号为9的块的数据只能放在Cache编号为9%8=1的块里,即每个块会被放在特定的位置。也需要标记位和有效位。
  • 组相联映射:和直接映射类似,不过分组了,主存块号%Cache分组数得到主存块放在Cache的哪个组里。也需要标记位和有效位。

全相联映射、直接映射和组相联映射都需要标记位和有效位来区分Cache中放的是哪个主存块。有效位的出现是因为初始时标记位都为0,那标记位为0是表示没存数据还是主存块为0的数据?这就出现了歧义,所以引入了有效位。
主存与Cache的映射方式不同,标记位的位数可能也不同

访存

特别注意主存地址的划分

  • 全相联映射如何访存?

将地址的前x位(表示块号)和Cache的所有块号进行比对,若标记位匹配且标记位为1则表示Cache命中,否则表示Cache不命中需要访问主存。其中匹配等功能由硬件电路实现,比如比较器。

image-20230327153156903

从图中可知,Cache每行26B,即每个块大小为26B,主存大小256M=228B,所以主存块的编号是0 - 222-1,所以标记位需要22位,还有有效位1位。主存地址就可以被划分为前22位表示块号,后面6位表示块内地址。

访问一个主存地址时时把这个地址的前22位与Cache里的所有块的标记位进行比较,若匹配上了且标记位为1那就说明数据在Cache里,Cache命中,否则就得访问主存去拿到这个地址对应的数据。

  • 直接映射如何访存?

注意地址的划分。

将地址的前x位和Cache的所有块号进行比对,若匹配且标记位为1则表示Cache命中,否则Cache不命中需要访问主存。

image-20230327191022620

这个例子和全相联映射的例子差不多,不过相比于全相联映射需要的22位标记位,直接映射只需要19位。

因为采用取余的办法得到Cache块的位置,所以块地址的后三位就是取余后的结果,所以Cache块的编号天然地可以充当块地址的后三位。所以这里的标记只需19位。

匹配时根据地址块号的后三位确定Cache行,之后再将主存地址与Cache的前19位地址进行比对,若成功匹配且有效位为1则Cache命中。否则Cache未命中需要访问主存。

行号也叫块号、字块号等,标记位也称为Tag,还要注意块内地址是以字节编址的。

  • 组相联映射如何访存?

将地址的前x位和Cache的所有块号进行比对,若匹配且标记位为1则表示Cache命中,否则Cache不命中需要访问主存。

image-20230327191824011

和直接映射类似。

匹配时根据地址块号的后两位确定所属的Cache组,之后再将主存地址与其所属分组内的所有Cache块的标记位地址进行比对,若成功匹配且有效位为1则Cache命中。否则Cache未命中需要正常访问主存。

比较

优点缺点
全相联映射缓存空间利用率高,命中率高比对标记最慢,可能比较所有标记
直接映射查找标记的速度最快缓存空间利用率低,命中率低
组相联映射两种方式的折中,综合效果好一点两种方式的折中

Cache替换算法

解决Cache很小,主存很大,Cache满了怎么办的问题。

采用替换的算法

Cache替换算法则是指当Cache缓存已满时,如何确定哪些数据应该被替换出Cache,以为新的数据腾出空间。

image-20230327195841308

替换时机
全相联映射Cache满了就选择替换某一块
直接映射没有选择,直接替换地址对应的Cache块
组相联映射组满了后再来一个块就需要替换。

抖动现象:刚刚调入Cache的块马上又被替换出去了,出现了一个块频繁地被换入换出这就是抖动。

随机算法(RAND)

Random

看这个例子就能懂了,有疑问的可以看王道的视频讲解。

随机找一个替换,实现简单,但是效果不稳定

image-20230327200407290

先进先出(FIFO)

First In First Out

最先进来的最先被替换,没考虑局部性原理,效果不怎么好。我们要做到最频繁访问的块尽可能的留在Cache里不被替换

image-20230327200536992

近期最少使用算法(LRU)

Least Recently Used

采用计数器实现,计数器的位数记作n,2n就是Cache块的块数。每个块的计数都不同。

规则是:

  • 命中则将命中行的计数器清零,比这个计数小的+1,比这个计数大的不变。(如果让比计数大的加1没有意义,因为大的本来就大,而且如果让最大的加一则会使得计数大于等于2n,这样无法用n位计数器实现)。

让比这个计数的更小+1,可以理解为计数为0的位置归了命中行,原本比这个计数小的都要往上“挪”一个位置。

  • 未命中且有空闲行那就将新插入的行置0,别的行都加一。
  • 未命名没有空闲行,替换计数器最大的(最久没使用的),新插入的行置0,其余的行加一。(类似于0归了命中行,比这个计数小的全部都往上挪一位)

image-20230327201734106

image-20230327202135334

实际运行的效果优秀,也是最常使用的算法。淘汰最久没有使用的块是合理的。但是当频繁访问的块大于Cache块的数据很有可能发生抖动。(一般会采用双端链表来实现LRU算法,链表的长度固定,频繁访问的数量大于链表的长度会导致一些块频繁在链表里出现又消失,也就是抖动)。

与newbing的对话

最不经常使用算法(LFU)

Least Frequently Used.

也是采用计数器实现,块的计数可能相同。

命中一次对应的计数器就加一。淘汰时找命中次数最少的,若有很多个块的命中次数相等且都是最少,比如很多个命中次数为0的,此时可结合FIFO来进行淘汰。

image-20230327204707757

运行效果不如LRU,因为曾经经常被用到的块不一定在未来被用到。但也不是所有场景都不如LRU,比如访问热点数据LFU的效果就比较好,所以具体选择哪种替换策略得根据场景的需求来。

比较

算法优点缺点
RAND实现简单效果不稳定,通常不如LRU
FIFO实现简单不考虑局部性,可能导致Cache命中率降低
LRU考虑了局部性,可以提高系统性能,效果优秀实现复杂,Cache较小时可能会发生抖动
LFU某些场景下效果优秀实现复杂,Cache较小时可能会发生抖动

Cache写策略

CPU修改了Cache的数据副本,如何确保主存中数据母本的数据一致性?Cache的写策略

Cache的写策略只用考虑写命中和写不命中的情况。读命中和读不命中都不会更改数据,所以无需考虑。

image-20230327214158647
  • 全写法:写命中时,CPU同时将数据写入Cache和缓冲。

非写分配法:写不命中时,CPU只将数据写入主存,不调入Cache。

这两种策略通常在一起使用。

  • 写回法:写命中时只修改Cache的内容,只有当此块被换出Cache时才写回主存。(通常Cache和主存之间还有缓冲区,换出后Cache将数据写入缓冲区,等到合适的时机再写回主存。需要一个脏位,即修改位,修改位为1则说明这个cache行被修改过,替换时需要写回主存,脏位为0说明没被修改过可以不用写回主存。

写分配法:写不命中时将主存里的块先调入Cache,在Cache中修改,一般搭配写回法。

页式存储

image-20230327214958364

与操作系统内容有关(课件我也没找到,所以等到操作系统再深究,现在先简单了解)

虚拟存储器

image-20230327215205435 image-20230327215413297 image-20230327215350011

与操作系统内容有关(课件我也没找到,所以等到操作系统再深究,现在先简单了解)

刷题小结

  • 注意Cache和主存的映射方式中主存地址的划分。

  • 1KB=210B=213b,块内地址的位数是10,而不是13,因为一般以字节编址。

  • 采用直接映射时,Cache的地址就等于块号+块内地址。

  • 写选择计算题时可以先把cache和主存的容量写出来,然后把它们的标记位,块号或者组号这些划分出来。

  • cache行里有主存数据、标记位、脏位、替换控制位等。替换控制位常被用于LRU、LFU算法里面,脏位是回写法的。

  • 给一个主存地址问数据对应cache的哪个块其实就是问地址的划分。

  • 有虚拟存储器才会有虚拟地址,CPU在高速缓存、主存、硬盘构成的体系中访问存储系统发送的是主存物理地址。

  • LRU可以和组相联等映射联合起来出题,如果是组相联需要先分组再进行LRU的模拟。

  • 指令Cache和数据Cache的分离的主要目的是减少指令流水线资源冲突

  • 8路组相联说明一组里面有8个cache行,那比较一个组就需要并行的使用8个比较器,比较器的位数就是标记位(Tag)的位数。

  • 包含循环的程序计算Cache命中率不能算容量,得算访问Cache的次数以及命中多少次,而不是算访问的主存容量与Cache容量的比值。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢乙醇的四氯化碳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值