Linux内存从0到1学习笔记(三,高速缓存)
Posted 高桐@BILL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内存从0到1学习笔记(三,高速缓存)相关的知识,希望对你有一定的参考价值。
写在前面
我们先来看一张图表,如下:
深入理解计算机系统一书将寄存器划分为L0级缓存,接着依次是L1,L2,L3,ARMv8最多可以支持7级的高速缓存,即L1级~L7级。接着是内存,本地磁盘。越往上的缓存存储空间越小,速度越快,成本也更高;越往下的存储空间越大,速度更慢,成本也更低。从上至下,每一层都可以看做是更下一层的缓存,即:L0寄存器是L1一级缓存的缓存,L1是L2的缓存,依次类推;每一层的数据都是来至它的下一层,所以每一层的数据是下一层的数据的子集。
一、高速缓存存在的意义
由于程序访问的局部性(包括时间局部性,某个内存单元在短时间内可能被再次访问;空间局部性,某个内存单元被访问后,相邻的内存单元在短时间内有可能被访问)。由于CPU和主存在性能上巨大的差异,我们在CPU和主存之间引入了高速缓存。在CPU访问数据时,如果缓存中存在该数据,则直接从缓存中读取,如果缓存中不存在,再从内存中读取数据。
二、高速缓存的原理
高速缓存Cache是非常小容量的存储器,它集成在CPU芯片内。为了便于CPU、高速缓存Cache、内存之间的信息交换,内存按块划分,高速缓存Cache按行或槽划分。
CPU根据查表得到的物理地址,先查询Cache中是否有数据,如果有,直接读取即可。如果Cache中没有,则从内存中读取数据,同时把数据放入Cache中,然后把数据返回给CPU。
2.1 Cache和主存的映射关系
所谓地址映射是指把主存地址空间映射到Cache地址空间,也即把存放在主存中的信息按照某种规则装入Cache。映射方式有三种,如下:
假设某个计算机的主存地址空间大小为256MB,按字节编址,Cache有8个Cache行(也即Cache块),行长(也即块大小)为64B。
这里,块大小为64B(2的6次方),主存为256MB(2的28次方), 那么主存块数=(2的28次方) / (2的6次方) = (2的22次方)。因此主存块号编号范围为从0到2的22次方,其中22位作为主存块号,6位作为块内地址,因此每个主存块的地址范围如下:
2.1.1 全相联映射
主存块可以放在Cache的任意位置,比如0号主存块,它就可以放置到Cache的3号位置,每行的标记号用于指出该行取自主存的哪一块,同时将对应的有效位置为1,后续主存块存放也是如此方式。
那么全相联映射下,以上图紫色主存块为例,其地址为1…1101001110。
首先会取上面的地址的前22位,也就是主存块号,来和Cache中每一行的标记进行对比
- 若标记号=块号其有效位为1:说明Cache命中,也就是说此时访问的数据在Cache中是有副本的,因此接着只需访问后6位地址所定位的单元即可
- 若标记号不匹配或匹配但是有效位为0:此时说明Cache未命中,则正常访问主存
全相联映射下,Cache存储空间利用充分,命中率高;但查找慢,有时可能要比对所有行的标记
2.1.2 直接映射
每个主存块只能放到一个特定的位置,其位置由主存块号%Cache总块数(取模)来确定。比如0号主存储块,由于0 % 8 = 0 ,因此它只能放到Cache的0号位置。
Cache块数=8=2的3次方,其指数部分为3,因此主存块号末尾的后3位就直接反映了它在Cache中的位置,比如上图中的0号和8号,其主存块号的后三位均为000,这也就正好对应了它们在Cache的第0行。
那么直接映射下,以上图橙色主存块为例,其地址为0…01000001110,CPU首先会根据主存块号的后三位确定Cache行,接着会判断前19位和标记号是否匹配并同时判断有效位是否为1,如果是则Cache命中,接下来根据块内地址操作即可,反之会访问主存。
直接映射下,对于任意一个位置,只需对比一个标记,速度最快;但是Cache存储空间利用不充分,命中率低。
2.1.3 组内映射
将Cache块分为若干组,每个主存块可以放到特定分组中的任意一个位置,其中组号=主存块号%分组数。这里我们使用2路组相连映射(2块为一组,分为四组)。比如1号主存块,由于1% 4 = 1,因此它会被放入第一组的任意位置,接着(2的22次方-3)号主存块也会放入第一组,它会放到另一个空闲位置。
那么在组相连映射下,以上图橙色主存块为例,其地址为1…0100001110。CPU首先会根据主存块号的后两位确定所属分组号,若主存块号的前20位与分组内的某个标记号匹配同时判断有效位是否为1,如果是则Cache命中,接下来根据块内地址操作即可,反之会访问主存。
以上是关于Linux内存从0到1学习笔记(三,高速缓存)的主要内容,如果未能解决你的问题,请参考以下文章
Linux内存从0到1学习笔记(6.9,物理内存初始化之Slab分配器)