0%

《操作系统》CPU高速缓存

每个缓存行由三部分组成

  1. 索引位。用来定位哪个缓存行
  2. 地址标记位。用来明确key的值,通过索引位定位到缓存行后,如果key对不上,则会抢走缓存行
  3. 数据。因为前两者的存在,这里只能保存小于64b大小的数据

下面是8个缓存行

因为高速缓存容量珍贵,缓存行的数量不多,所以并不会安排一个缓存行中保存一个key跟一个value

而是使用索引位来定位缓存行,比如某32位地址,一次会读取这个地址往后64字节(缓存行大小一般都是64字节,取决于cpu,cpu取数据是以缓存行大小为单位存取的)

假设将地址的最后3位作为索引位(多少个位作为索引位是由组的个数决定的,8个组就使用3个位作为索引位,这样可以保证每个索引分到不同的组),则查找缓存行位置的方法就是 最后3位的数值对缓存行的个数取模

这样很显然,最后3位一样的地址都将会定位到同一个缓存行,缓存行会被互相覆盖

所以需要地址标记为来判断定位到的缓存行中的内容是不是请求的地址中的内容

剩余的29个位就是地址标记位,下面看整个CPU取数据的过程

  1. CPU拿着地址A(这里已经是物理地址了)访问一级缓存
  2. A最后3位对一级缓存中缓存行个数取模,定位到哪个缓存行
  3. A前面29个位与缓存行中的地址标记位比较,看是否相等,相等说明命中了缓存,不相等说明缓存行中数据不是自己的数据,没有命中
  4. 如果命中了,则数据取出来,过程结束。如果没命中,则拿着地址A访问二级缓存,使用同样的办法定位缓存行
  5. 如果二级缓存、三级缓存都没有命中,则往内存中取数据
  6. 取到后分别在三级、二级、一级缓存中留下缓存,过程结束

多路关联

从上面不难看出,缓存行被覆盖的概率非常高,从而导致命中率降低

于是出现了多路关联,来缓解这个问题

多路关联的意思就是将缓存行分组,每个索引位具有n个缓存行,他们组成一组。这就叫n-way关联

每个组中同一个索引位对应多个不同的地址标记位,这样的话当定位完组之后,需要遍历整个组,找出对应的地址标记位,没找到说明没命中,这样的话,n越大,对性能的影响就越大

所以现在n一般都是2、4、8,比较折中

下面是4个组8个缓存行

上图就是2-way关联

其实前面讲的就是1-way关联的极端情况,也就是直接映射高速缓存,每个组只有一个缓存行,组的个数就是缓存行的个数。缓存空间越小,缓存行数量就越少,覆盖的频率就越高,命中的概率就越低

还有另一个极端情况,就是缓存中只有一个组,这叫全关联高速缓存,索引位是0个位,所有地址都索引到这唯一的组中,整个32位都成了地址标记位,完全不存在覆盖情况,但是缓存空间越小,地址标记位能够覆盖到的地址范围就越小,命中的概率就越低。而缓存大小非常珍贵,一般容量不大,所以这种缓存基本不使用。

缓存命中

缓存命中有3次命中

  1. 组选择
  2. 行匹配
  3. 字抽取

拿一个32k(64个组,每组8行,缓存行大小为64字节。64 * 8 * 64 = 32k)的缓存举例

索引位用来定位组,所以索引位使用64位地址中的6位(6位二进制最大值为64,刚好每个值对应一个组)用来索引

缓存行大小为64字节的话,命中数据中的每个字节则需要6个位来定位

前面已经使用了6个位来定位组、6个为来定位字节,那么剩下的 64-6-6=52 个位用作标记位,用来进行行匹配。一个组中只有8个行,标记位却有52个位,很明显覆盖率将会很高

下面看整个CPU取数据的过程

  1. CPU拿着地址A(这里已经是物理地址了)访问一级缓存
  2. A开始6位对一级缓存中缓存行个数取模,定位到哪个组
  3. A拿着最后52个位与组中每个缓存行中的地址标记位比较,看是否相等,相等说明命中了缓存行,不相等说明组中没有自己的数据,没有命中
  4. 如果命中了缓存行,则使用A剩下的6个位对缓存行大小64取模,定位到哪个字节,然后把数据按数据大小(int64对应MOVQ指令,int8对应MOVB指令)取出来,过程结束。如果没命中,则拿着地址A访问二级缓存,使用同样的办法定位缓存行
  5. 如果二级缓存、三级缓存都没有命中,则往内存中取数据
  6. 取到后分别在三级、二级、一级缓存中留下缓存(会覆盖掉组中某一个缓存行),过程结束



微信关注我,及时接收最新技术文章