最早的计算机存储器层次结构只有三层:CPU寄存器、DRAM主存储器和磁盘存储。由于CPU和主存之间的速度差距过大,设计者们在这两者之间加入了一个SRAM高速缓存存储器,也就是L1高速缓存。后面又加入了L2、L3高速缓存,本节就是用来研究高速缓存存储器的。
1、通用的高速缓存存储器组织结构
高速缓存被组织成如下的情形:
- 整个高速缓存被分成了若干个组
- 每个组包含若干个高速缓存行
- 每个行包含一个一定数量字节的数据块,以及一个有效位和t个标记位
细节我们后面再说
当CPU要从主存中独取一个字的时候,它将地址A发送至高速缓存。高速缓存需要判断自己是否存储着这个地址的那个字的副本。如何找到一个副本取决于高速缓存是如何存储的。下面介绍高速缓存如何具体存储一个内容。
前面所说的地址A被拆分成三个部分。
- 中间的s位做了组索引,也就是可以通过这s位知道该地址的字所在的组
- 前面的t位作为标记,用来寻找组内哪个行包含该地址的字。只有当行设置了有效位,并且标记匹配的行,才是真正存储字的位置
- 后面的b位代表块偏移,也就是从该行中从第b个字节开始取一个字,就是你想要的内容
上面是相关的参数描述
2、直接映射高速缓存
根据每个组的高速缓存行数E, 高速缓存被分为不同的类。每个组只有一行(E = 1)的高速缓存称为直接映射高速缓存。
1.例子
这里书中举了一个例子我们直接搬过来看:
假设我们有一个直接映射高速缓存, 描述如下(S,E,B,m) = (4,1 ,2,4)。也就是高速缓存有四个组,每个组一行,每行的高速缓存块有两个字节, 地址是4位的,每个字都是单字节的。
第一列表明该行所属的组,但是请记住提供这个位只是为了方便,实际上它并不真是高速缓存的一部分。后面四列代表每个高速缓存行的实际的位。
2.冲突不命中
就是上面例子中读取地址0和地址8的时候发生的情况。术语抖动描述的是这样一种情况, 即高速缓存反复地加载和驱逐相同的高速缓存块的组。
简要来说就是, 即使程序有良好的空间局部性, 而且我们的高速缓存中也有足够的空间,来存放抖动中的块,但每次引用还是会导致冲突不命中, 这是因为这些块被映射到了同一个高速缓存组。
3.为什么用中间的位做索引
如果高位用做索引,那么一些连续的内存块就会映射到相同的高速缓存块。
如果一个程序有良好的空间局部性,顺序扫描一个数组的元素,那么在任何时刻,高速缓存都只保存着一个块大小的数组内容。
3、组相联高速缓存
可以看到,直接映射高速缓存很容易出现冲突不命中的情况,因为每个组只有一行。组相联高速缓存(set associative cache)放松了这条限制,所以每个组都保存有多于一个的高速缓存行。一个1<E<C/B的高速缓存通常称为E路组相联高速缓存。
1.组相联高速缓存中的组选择
2.组相联高速缓存中的行匹配和字选择
传统的内存是一个值的数组, 以地址作为输入, 并返回存储在那个地址的值。另一方面, 相联存储器是一个(key, value)对的数组, 以key为输入, 返回与输入的key相匹配的(key, value)对中的value值。因此,我们可以把组相联高速缓存中的每个组都看成一个小的相联存储器, key是标记和有效位, 而value就是块的内容。
组相联高速缓存必须搜索组中的每一行,寻找一个有效的行, 其标记与地址中的标记相匹配。如果高速缓存找到了这样一行, 那么我们就命中, 块偏移从这个块中选择一个字, 和前面一样。
3. 组相联高速缓存中不命中时的行替换
如果组内有空的行就放空的行,否则有各种策略:例如, 最不常使用(Least-Frequently-Used,
LFU)策略会替换在过去某个时间窗口内引用次数最少的那一行。最近最少使用(LeastRecently-Used, LRU)策略会替换最后一次访问时间最久远的那一行。
4、全相联高速缓存
全相联高速缓存是由一个包含所有高速缓存行的组组成的。
1. 全相联高速缓存中的组选择
全相联高速缓存中的组选择非常简单,因为只有一个组,如图。注意地址中没有组索引位,地址只被划分成了一个标记和一个块偏移。
2. 全相联高速缓存中的行匹配和字选择
全相联高速缓存中的行匹配和字选择与组相联高速缓存中的是一样的,如图6-37所示。它们之间的区别主要是规模大小的问题。
因为高速缓存电路必须并行地搜索许多相匹配的标记,构造一个又大又快的相联高速缓存很困难,而且很昂贵。因此,全相联高速缓存只适合做小的高速缓存,例如虚拟内存系统中的翻译备用缓冲器(TLB),它缓存页表项 。
5、有关写的问题
写的情况就要复杂一些了。
1.写命中
假设我们要写一个已经缓存了的字w(写命中, write hit)。在高速缓存更新了它的w的副本之后, 怎么更新w在层次结构中紧接着低一层中的副本呢?
1.直写
就是立即将w的高速缓存块写回到紧接着的低一层中。虽然简单, 但是直写的缺点是每次写都会引起总线流量。
2.写回
尽可能地推迟更新, 只有当替换算法要驱逐这个更新过的块时, 才把它写到紧接着的低一层中。由于局部性, 写回能显著地减少总线流扯, 但是它的缺点是增加了复杂性。高速缓存必须为每个高速缓存行维护一个额外的修改位(dirty bit), 表明这个高速缓存块是否被修改过。
2. 写不命中
1.写分配
加载相应的低一层中的块到高速缓存中, 然后更新这个高速缓存块。写分配试图利用写的空间局部性,但是缺点是每次不命中都会导致一个块从低一层传送到高速缓存。写回高速缓存通常是写分配的。
2.非写分配
非写分配(not-write-allocate), 避开高速缓存, 直接把这个字写到低一层中。直写高速缓存通常是非写分配的。
6、一个真实的高速缓存层次结构解剖
高速缓存既保存数据, 也保存指令。只保存指令的高速缓存称为i-cache。只保存程序数据的高速缓存称为d-cache。既保存指令又包括数据的高速缓存称为统一的高速缓存(unified cache)
这个层次结构的一个有趣的特性是所有的SRAM高速缓存存储器都在CPU芯片上。
7、高速缓存参数的性能影响