CPU高速缓存模型

下文讨论的模型与协议将尽量简化,不考虑实际上存在的很多复杂情况与细节

模型演变

单核时代

一个简易模型如下

内存对于CPU来说速度很慢,因此加入高速缓存(cache,下文简称缓存)来避免CPU资源的浪费。在单核时代,即时在多线程环境,不同的线程仍然由同一个CPU执行,使用的是同一个缓存,不存在缓存数据不一致的问题

为了提升缓存的命中率,依据局部性原理,CPU将数据加入缓存时,会将即将使用到的数据连带相邻的一部分数据一起加入,一次加入缓存的数据称为一行缓存行

多核时代

进入多核时代,由于每个CPU内核都会有自己的一块缓存区域,因此出现了基于MESI缓存一致性协议的解决方案,用于协调各个CPU的缓存状态,解决缓存数据不一致的问题

简易的多核模型如下,不同的CPU的缓存通过MESI协议进行状态协调

MESI协议

协议基本内容

简易MESI协议规定缓存行可具有4种不同的状态,分别为

  • Modified,缓存行已被修改,最终会被写回内存
  • Exclusive,缓存行未被修改,且此时只有此CPU缓存了该缓存行
  • Shared,缓存行未被修改,且此时有多个CPU缓存了该缓存行
  • Invalid,缓存行已失效

简易MESI协议规定缓存间的事件信息交流分别为

  • Read,表示请求读取某一缓存行的数据,信息中包含缓存行的地址
  • Read Response,对Read信息的响应,包含某一缓存行的数据,数据可能来源于内存,也可能来源于其它CPU的缓存
  • Invalidate,表示某一缓存行已失效,提示其它CPU将该缓存行的状态置为Invalid,信息中包含失效缓存行的地址
  • Invalidate Acknowledge,对Invalidate信息的响应,表示确认收到某一缓存行的Invalidate信息
  • Read Invalidate,Read与Invalidate的组合
  • Writeback,将缓存行写回内存,缓存空间吃紧时可能还会将该缓存行淘汰出缓存

简易MESI协议的有限状态机如下图

Store Buffer

从MESI协议的有限状态机可以看到,需要修改缓存行的数据时,缓存行必须先处于Exclusive状态,而从Shared状态或Invalid状态转移到Exclusive状态,必须等待其它所有CPU的Invalidate Acknowledge,这有可能导致CPU长时间等待

为了解决这个问题,引入store buffer。修改数据时,CPU不再等待其它所有CPU的Invalidate Acknowledge,而是先修改数据,并把修改后的数据放到store buffer,等到接收了其它所有CPU的Invalidate Acknowledge后,再把store buffer的数据写到缓存中。读取数据时,CPU可以直接从store buffer中读取之前自己所修改的最新数据

Invalidate Queue

为了降低store buffer中的数据等待写入缓存的时间,引入invalidate queue。接收到Invalidate事件的缓存,先把这个事件放到invalidate queue中,然后马上返回Invalidate Acknowledge,后续才去把对应的缓存行状态设置为Invalid

内存重排序(Memory Reordering)

Store Buffer带来的内存重排序

Store buffer带来了内存重排序的情况,试想以下情况,在store buffer中的修改数据等到其它所有CPU的Invalidate Acknowledge并写入缓存之前,CPU继续执行后续的指令,如后续的指令也是修改数据,这次将要修改的数据已在一状态为Exclusive的缓存行中,CPU可以直接修改缓存中的数据,此时新修改的缓存行已对其它所有CPU缓存可见,但更早时候修改的已放进store buffer中的修改数据却未对其它所有CPU缓存可见

Invalidate Queue带来的内存重排序

Invalidate queue也带来了内存重排序的情况,试想以下情况,invalidate queue中存在关于某缓存行的Invalidate事件尚未处理,缓存中存在这一缓存行,状态还是可用的(非Invalid状态),当CPU需要读取该缓存行中的数据时,直接从缓存中读取失效数据,就好像其它CPU对该数据的修改尚未发生

内存重排序(Memory Reordering)