![ad57fa9cdf70690a185d9697eda7160a.png](https://i-blog.csdnimg.cn/blog_migrate/feed544ed34bc152090d968188858f3b.png)
一、高速缓存存储器组织结构
假设一个计算机系统每个存储器地址有m位,形成M=2^m个不同的地址。这样一个机器的高速缓存被组织成一个有S=2^s个高速缓存组(cache set)。每个高速缓存组包含E个高速缓存行(cache line)。每个高速缓存行由一个B=2^b字节的高速缓存块(block)、一个有效位(valid bit:指明这个行是否包含有意义的信息),还有t=m-(b+s)个标记位(唯一的标识存储在这个高速缓存行中的高速缓存块)。
![9f10fc0bd2bfa09ed4350f2199a5c37f.png](https://i-blog.csdnimg.cn/blog_migrate/54a4c70d0da990c83d8383a055b10af8.jpeg)
当一条加载指令指示CPU从主存地址A中读取一个字时,它将地址A发送到高速缓存。如果高速缓存正保存着地址A处字的副本,它立即将这个字发回给CPU。高速缓存的结构能够通过简单地检查地址位,找到所请求的字:
存储器地址如下所示:
![4078830b4859f093df3d3cabc8d641ee.png](https://i-blog.csdnimg.cn/blog_migrate/b6f8872e347d5a09766ce6e4571888e0.png)
地址A中s个组索引位是一个到S个高速缓存组的索引。组索引位被解释为一个无符号整数,它告诉我们这个字必须存储在哪个告诉缓存组中。地址A中的t个标记位告诉我们高速缓存组中的哪一个高速缓存行包含这个字。当且仅当设置了有效位并且该行的标记位与地址A中的标记位相匹配时,组中的这个高速缓存行才包含这个字。地址A中的b个偏移位给出了字在B个字节的缓存块中的字偏移。
二、直接映射高速缓存
根据每个高速缓存组中高速缓存行E的行数,高速缓存被分为不同的类。每个高速缓存组只有一行(E=1)高速缓存行的高速缓存被称为直接映射高速缓存(direct-mapped cache)。
![9131ca2dc1e4bdf4f3ede8133bb3acbd.png](https://i-blog.csdnimg.cn/blog_migrate/fba93956c577fffebc4b7dbc6a4f58bd.jpeg)
高速缓存确定一个请求是否命中,然后抽取出被请求的字的过程,分为三步:1、组选择;2、行匹配;3、字抽取。
2.1 直接映射高速缓存中组选择
高速缓存从m个地址位中间抽取出s个组索引位。
![e00abd05ea9dee7580e2bea406b64043.png](https://i-blog.csdnimg.cn/blog_migrate/02778c9f6bdb84a99d6851aa2e5aa9f1.jpeg)
2.2 直接映射高速缓存中行匹配
当且仅当高速缓存行设置了有效位,并且高速缓存行中的标记与地址中的标记相匹配时,这一高速缓存行包含这个字的一个副本。
![ffa5e52ba796becf8c5d8a60b88a0040.png](https://i-blog.csdnimg.cn/blog_migrate/34113fc0a6a1ae86af81b0163179e980.jpeg)
2.3 直接映射高速缓存中的字选择
块偏移提供了所需要的字的第一个字节的偏移。本例中块偏移为100(二进制),它表明字的副本是从块中的字节4开始的(我们假设字长为4字节)。
2.4 运行中的直接映射高速缓存
假设我们有一个直接映射高速缓存,描述如下:(S,E,B,m)=(4,1,2,4)。即:高速缓存有4个高速缓存组,每个高速缓存组含有一行高速缓存行,每个高速缓存块有2个字节,存储器地址为4位。我们假设每个字都是单字节的。
我们模拟CPU执行一系列读的时候,高速缓存的执行情况,我们假设CPU读1字节的字。初始时,高速缓存是空的(即每个有效位都是0);
![9c01423a98ca3056ca114ee5604ff31d.png](https://i-blog.csdnimg.cn/blog_migrate/b8a846fb799bc1a68683bfa7119c6666.png)
表中的每一行都代表一个高速缓存行。第一列表明该列所属的组,但是请记住提供这个位只是为了方便,实际上它并不是高速缓存的一部分。后面四列代表高速缓存行的实际位。
1、读地址0(0000)的字。因为组0的有效位是0,是缓存不命中。高速缓存从内存(或低一级的高速缓存)取出块0,并把这个块存储在组0中。然后,高速缓存返回新取出的高速缓存行的块[0]的m[0](内存位置0的内容)。
![1d4f67817400d4671c7b2eb17de1350a.png](https://i-blog.csdnimg.cn/blog_migrate/6ed5d59bd49722eed566dc2af7ab15d4.png)
2、读地址1(0001)的字。这次会是高速缓存命中。高速缓存立即从高速缓存行的块[1]中返回m[1]。高速缓存的状态没有变化。
3、读地址13(1100)的字。由于组2中的高速缓存行不是有效的,所以缓存不命中。高速缓存把块6加载到组2中,然后从新的高速缓存行的块[1]中返回m[13]。
![91345d7f1a4e75d6c6a3d3fa12ffe6ee.png](https://i-blog.csdnimg.cn/blog_migrate/43908d2b84de429a22dce734d96b2a80.png)
4、读地址8(1000)的字。这会发生缓存不命中。组0中的高速缓存行确实是有效的,但是标记不匹配。高速缓存将块4加载到组0中(替换读地址0时读入的高速缓存行),然后从新的高速缓存行的块[0]中返回m[8]。
![0aa619f102b3ac7070b8ddb6a05b7be2.png](https://i-blog.csdnimg.cn/blog_migrate/035f8f9448565b595e5e3d3927ec01f6.png)
5、读地址0(0000)的字。又会发生缓存不命中,因为前面引用地址8时,我们刚好替换了块0。这就是冲突不命中的例子。也就是我们有足够的高速缓存空间,但是却交替的引用映射到同一组的块。
![44855b211714db1b9517cb133f0fc767.png](https://i-blog.csdnimg.cn/blog_migrate/3ad9b7cbbe44128a78611f44e85ad709.png)
三、组相联高速缓存
直接映射高速缓存中冲突不命中造成的问题源于每个组只有一行(E=1)这个限制。组相连高速缓存放松了这条限制,一个1<E<C/B的高速缓存成为E路组相连高速缓存。下图为2路组相联高速缓存的结构。
![67df04cdb28d5188a03052d4b1e6eb8f.png](https://i-blog.csdnimg.cn/blog_migrate/26504515a681bd4a3d59eb9947ed310e.jpeg)
1、组相联高速缓存中组的选择
组索引位标识组
![c3ed73e7e2c10adb9425652bb059a46f.png](https://i-blog.csdnimg.cn/blog_migrate/2081862e5bc4a33a1038f0fd81ed196c.jpeg)
2、组相联高速缓存中行匹配和字选择
组中的任何一行都可以包含任何映射到这个组的内存块。所以高速缓存必须搜索组中的每一行,寻找一个有效行,其标记与地址中的标记相匹配。如果高速缓存找到了这样一行,那么我们就命中,块偏移从这个块中选择一个字。
![f7f1122f4aa742ec08ccae5e37a3d76c.png](https://i-blog.csdnimg.cn/blog_migrate/dc828b8acd4f2f2314970b65aadc6522.jpeg)
3、组相联高速缓存中不命中时行替换
最简单的替换策略是随机选择替换。其他更复杂的策略利用了局部性原理,以使在比较近的将来引用被替换的行的概率最小。例如,最不长使用(LFU)策略会替换在过去某个时间窗口内引用次数最少的那一行。最近最少使用(LRU)策略会替换最后一次访问时间最久远的哪一行。
四、全相联高速缓存
全相联高速缓存是由一个包含所有高速缓存行的组(E=C/B)组成的。
![bbfe48f034f907345f7146edef76b5b2.png](https://i-blog.csdnimg.cn/blog_migrate/4766200912c154d813d1f9b36cb20081.jpeg)
1、全相联高速缓存中的组选择
全相联高速缓存中的组选择非常简单,因为只有一个组。地址中没有组索引,地址只被划分为一个标记和一个块偏移。
![d18f86232a72ec7ab02f9b7afa3a14e9.png](https://i-blog.csdnimg.cn/blog_migrate/0f90dce7fe7ce37b6a7cb859ba5513cb.jpeg)
2、全相联高速缓存中的行匹配和字选择
全相联高速缓存中的行匹配与字选择与组相联高速缓存中的是一样的,它们的区别主要是规模大小的问题。
![3967a5d00b16844e3be9ca00661c74a1.png](https://i-blog.csdnimg.cn/blog_migrate/29c19b0ed6f34e11f9b51adf6db78dfb.jpeg)
因为高速缓存电路必须并行地搜索许多相匹配的标记,构造一个又大又快的相联高速缓存很困难,而且价格昂贵。
五、高速缓存读与写
1、高速缓存读
首先,在高速缓存中查找所需字w的副本。如果命中,立即返回字w给CPU。如果不命中,从存储器层次结构中较低层中取出包含字w的块,将这个块存储到某个高速缓存行中,然后返回字w。
2、高速缓存写
写命中
直写(write-through),写一个已经缓存了的字w(写命中,write hit),立即将w的高速缓存块写回到紧接着的低一层中。
写回(write-back),尽可能的推迟更新,只有当替换算法要驱逐这个更新过的块时,才把写到紧接着的低一层中。高速缓存必须为每一个高速缓存行维护一个额外的修改位(dirty bit),表明这个高速缓存块是否被修改过。
写不命中
写分配(write-allocate),加载相应的低一层中的块到高速缓存中,然后更新这个高速缓存块。
非写分配(not-write-allocate),避开高速缓存,直接把这个字写到低一层中。
六、Intel Core i7处理器的高速缓存层次结构
只保存指令的高速缓存称为i-cahce,只保存程序数据的高速缓存称为d-cache。即保存指令又保存数据的高速缓存称为统一高速缓存。
![90e43e1f2b4ba5826898d2182586099f.png](https://i-blog.csdnimg.cn/blog_migrate/c33e44fe8f2490a4d2ed2b1e32df3824.jpeg)
Intel Core i7 处理器每个CPU芯片有四个核。每个核有自己私有的L1 i-cache、L1 d-cache和L2统一的高速缓存。所有的核共享片上的L3统一的高速缓存。
参考:
《深入理解计算机系统》是2016年机械工业出版社的图书,作者是(美)布赖恩特(Bryant,R.E.)。
《Computer Systems A Programmer's perspective》:CSAPP。