Cache

CPU很快、内存很慢;内存很快、硬盘很慢;硬盘很快、网络很慢,这个世界总归是不完美的。

Cache的作用是位于速度较快和较慢的两种硬件中,用于协调数据传输的速度差异。本文主要以CPU和内存间的cache为例进行讲解。

cache简介

缓存的结构及机制

CPU的缓存是完全由硬件电路控制的,不能显式对其进行控制,cache的物理结构如下所示:

图片名称

其中,L1和L2cache为Core独有的,L3 Cache是一个cluster内共享的,L1 cache包括Data Cache(D Cache)和Instruction Cache(I Cache),下面我们讨论一下缓存的机制,

Cache经典问题

缓存一致性(重要)

一致性介绍

图片名称

假设我们现在有四个CPU,每个CPU斗有自己的独立缓存,通过BUS与内存相连,数据流是单路的,也就是所有的核通过一条bus读取内存,假设每个核都读取了变量a所在的内存,并进行了修改,那么每个核的私有缓存中保存的内容都是不一致的。所以我们引出了缓存一致性的问题,共享的数据资源在多个局部cache中被保存,所以我们需要维护一致性,当一个核更新了数据,如何保证其他的核上能够同步。所以缓存一致性是由于多个cache引起的

为了解决缓存一致性,我们先要了解cache的结构,cache内部实际上是一条条cache line或者cache block组成的,大小可能是64 Byte或者128 Byte

一致性协议

为了解决一致性带来的问题,计算机使用了总线窥视器监视总线上的读写动作,并根据一些协议修改缓存状态,这里我们介绍经典的snooping协议,在该协议中,缓存行有四个状态,随着读写操作发生变化:

  • 已修改Modified (M):缓存行与主存的值不同。如果别的CPU内核要读主存这块数据,该缓存行必须回写到主存,状态变为共享(S).
  • 独占Exclusive (E):缓存行只在当前缓存中,但是干净的(clean)—缓存数据同于主存数据。当别的缓存读取它时,状态变为共享;当前写数据时,变为已修改状态。
  • 共享Shared (S):缓存行也存在于其它缓存中且是干净的。缓存行可以在任意时刻抛弃。
  • 无效Invalid (I):缓存行是无效的,需要从其他缓存或者内存中读取

MESI协议的状态转换图如下

图片名称

举例:一个CPU A对变量a进行写操作,还未写回memory中,此时状态为Modified,如果CPU B从内存中读取a,得到的是脏数据,而CPU A能够监听到这个读操作,将a的值写入内存,而CPU B由于未得到响应,会重新发起读请求,从memory中读到最新值。

初始状态 操作 响应
Invalid(I) PrRd 给总线发BusRd信号
其他处理器看到BusRd,检查自己是否有有效的数据副本,通知发出请求的缓存
如果其他缓存有有效的副本,状态转换为(S)Shared,否则状态转换为(E)Exclusive
如果其他缓存有有效的副本, 其中一个缓存发出数据;否则从主存获得数据
PrWr 给总线发BusRdX信号
状态转换为(M)Modified
如果其他缓存有有效的副本, 见到BusRdX信号后无效其副本
向缓存块中写入修改后的值
Exclusive(E) PrRd 无总线事务生成
状态保持不变
读操作为缓存命中
PrWr 无总线事务生成
状态转换为(M)Modified
向缓存块中写入修改后的值PrWr
Shared(S) PrRd 无总线事务生成
状态保持不变
读操作为缓存命中
PrWr 发出总线事务BusUpgr
信号状态转换为(M)Modified
其他缓存看到BusUpgr总线信号,标记其副本为(I)Invalid.
Modified(M) PrRd 无总线事务生成
状态保持不变
读操作为缓存命中
PrWr 无总线事务生成
状态保持不变
写操作为缓存命中

缓存命中问题

当CPU申请访问数据,我们要考虑该数据是否已经缓存至cache中,这就是缓存的命中问题。缓存不命中会导致CPU直接访问内存数据,降低运行效率。

graph LR
    node1[Memory]
    node2[Cache]
    node3[CPU]

    node3--hit-->node2
    node3--miss-->node1

缓存不命中发生条件

当发生以下情况时,缓存不命中

  • 数据不在cache中
  • 数据在cache中,但是被移除

如何提高缓存命中率

通过采用一些缓存管理策略,常见缓存管理策略如下:

  • FIFO:先进先出
  • LIFO:后进先出
  • LRU:最近最少使用
  • MRU:最近最多使用

关于Cache的一些术语

冷热缓存

冷缓存代表当前Cache没有保存任何有价值的值,不能提供性能加速;而热缓存代表已经存有一些有用的值,可以提高性能。相应地,我们向缓存中添加数据,就是预热的过程;而从缓存中清理数据,就是冷却的过程。

参考文献

0%