缓存一致性协议MESI详解

CPU的缓存结构

我们知道CPU的运算速度是很快的,因为从磁盘获取的数据的速度严重影响着效率,所以此有了DRAM(内存),但是即便是这样,内存的性能也远远跟不上CPU的运行速度,所以CPU的设计者开始在内部加入SRAM (高速缓存) ,来解决CPU运算速度和内存IO的不匹配问题。

作为高速缓存,他的大小和成本都使得缓存的空间有限。我们将要用到的数据放在更加接近CPU的地方,这样每次取的时候就不需要从内存中去拿。一般CPU为我们提供了三级缓存,一般称为L1,L2,L3。其中L1层分为2块:L1P-用于存放程序(program),L1D-用于存放数据(data)。L1和L2是单核独占的(也有部分说法说L2会被相邻的2个core共享,没仔细考究),而L3是单个CPU里面的多核共享的(毕竟土豪的电脑可能有2块cpu)。CPU在获取数据的时候,会先从L1找,找不到再去L2,L3,DRAM这个顺序依次找到为止。

image.png

image-20210827003905479.png

缓存一致性问题

因为CPU的多核存在,然后每个核都有自己的独立的工作空间,所以当两个核都需要处理同一个内存中的数据的时候,他们都会将数据从内存中拷贝到自己的缓存中,我们这里先把他这块叫工作内存,这样如果2个核心对应的线程都需要修改这个值的时候,那么就会出问题,当处理完成后,我们还是要将数据写回到缓存中去的,但是因为这2个互相独立的核心,他们都写回的话,肯定会有一个被另外一个给覆盖了(还有相关的一系列的并发读写引发的问题)。

解决方法

下面列举了一些可以来处理上述缓存一致性问题的一些方案:

共用一个缓存

这种方式就类似于将一个多线程问题,通过同步的方式解决一样,公用一个缓存,那么在某个核心在使用该数据的时候,其他的核心将会被阻塞等待,这样也会降低CPU的效率。

在总线(bus)上加lock锁的方式

这个是在不修改对应硬件结构上,来让DRAM的数据只能由1个核心加载到自己缓存中。我们从前面CPU的工作原理,大概可以得知CPU从RAM获取数据基本都是通过将CPU和RAM通过总线进行连通来通信的。这种方式和上面一样不好,锁住总线会让其他和其不想干的CPU都无法访问RAM,相当于一个悲观锁,效率比较低下。

缓存一致性协议的方式 MESI

通过锁定缓存行的方式来来保证多核CPU和内存读写的一致性问题。其方案类似于读写锁的方式,使得针对同一地址的读内存操作是并发的,而针对同一地址的写内存操作是独占的。

MESI

MESI是Modified、Exclusive、Shared、Invalid这四个单词的首字母。这4个字母分别代表4种状态:

状态 描述 监听任务
Modified(修改) 该缓存行有效,但是该缓存数据已经被当前核心修改,此时和DRAM中数据不一致。我们将其置为M,其他的核中缓存行都会置为I。 监听总线上所有对该缓存行写回DRAM的操作(不希望别人写入),需要将该操作延迟到自己将缓存行写回到主存后变成S状态。
Exclusive(互斥) 该缓存行有效,数据和RAM的数据一致,数据只存在当前内核工作内存中,只有他在使用是独占的。 监听总线上所有从DRAM读取该缓存行的操作,一旦有读的,需要将状态置为S状态。
Shared(共享) 该缓存行有效,不过当前缓存行在多个核中都有,并且大家以及DRAM中的都一样 监听其他的缓存中将该缓存置为I或者为E的事件,将状态置为I状态。
Invalid(无效) 表明该缓存行无效,如果想要获取数据的话,就去DRAM中加载最新的 不需要监听。

先暂时不用去理解描述后面写的内容,我们先得了解2个概念:

缓存行

在CPU缓存中最小的存储单元称为缓存行(cache line),一般大小为64B。我们需要在缓存行中保存上面的4种状态,所以一个缓存行中,都只要有2个Bit位去存储该状态(下图flag标志位,tag用来定位缓存行位置)。

image.png

监听

并且上面我们可以得知当有一个核去修改了自己的缓存行,需要同步到其他的核并更新他们的状态。所以说在MESI中每个cache控制器,不仅需要知道自己的操作,还会监听其他的cache的操作

我们把CPU各个内核对缓存的操作可以总结为4种操作:

  • local read:CPU内核读取自己的本地缓存
  • local write:CPU内核写入自己的本地缓存
  • remote read:其他的CPU内核读取了DRAM中当前内核的缓存行
  • remote write:其他的CPU内核写入了DRAM中当前内核的缓存行

CPU内核中的缓存会监听这些事件来修改自己缓存的缓存行中的Flag标志位。然后通过该标志位来决定CPU如何处理这个缓存数据。

MESI状态转移图

上面的MESI四种状态,在监听到那四种操作之后会依据操作的类型来转换状态:

image.png我们这里用CPU的两个核CA(coreA)和CB(coreB)以及缓存行数据 X 来解释下上面图片的转变,当CA中存在X:

状态是M(修改):此时只有CA内部有X,并且X和RAM的X值是不一致的。

事件 行为 下一个状态
local read 直接从CA的cache中读,状态不发生改变 M
local write 直接修改CA的cache数据,状态不变 M
remote read CB需要最新数据,将CA的X值写回到RAM中 CB从RAM再读取X,CA和CB的缓存行标志为设置为S S
remote write 先将CA的X值写回到RAM中 CB读取X并修改,CA的状态变为I,CB的状态变为M I

状态是S(共享):此时CA和CB都有X,且和RAM的值都一致。

事件 行为 下一个状态
local read 直接从CA的cache中读,状态不发生改变 S
local write CA直接修改cache,状态变为M。CB变为I M
remote read CB读的和CA的一样的数据,状态不变 S
remote write CB对应成了上面CA的local write,CB的cache变为M,CA的变为I I

状态是E(独占):此时只有CA有X,且X和RAM的X值一致(值一致代表着不需要写回RAM)

事件 行为 下一个状态
local read 直接从CA的cache中读,状态不发生改变 E
local write 直接修改CA的cache,状态变为M M
remote read CB发送读事件,CA和CB需要共享X,所以状态都变为S S
remote write CA将X置为I I

状态是I(失效):需要依据CB是否有X,以及响应的状态来决定操作。

事件 行为 下一个状态
local read 如果CB没有X,则CA读取X,状态为E 如果CB有X,状态为M,则CB需要写回到RAM,然后CA读取,状态变为S 如果CB有X,状态为S或者E,那么CA直接读,CA和CB都变为S E or S
local write CA需要从RAM拉取数据 如果CB没有X,那么CA就直接拉取,修改后设置为M 如果CB有X,状态为M,那么CB需要先写回RAM,然后CA读取最新到cache,修改并设置为M,CB变为I 如果CB有X,状态为S或者E,那么CA读取并设置为M,CB为I M
remote read 已经失效,只和自己读写有关,和其他的读写无关,状态不变。 I
remote write 已经失效,只和自己读写有关,和其他的读写无关,状态不变。 I

上面写的可能复杂,但是其实原理很简单!只要了解了原理,你可以自己对着这些状态就能演算出来,主要抓住几个规则:

  1. 当有核心读的时候,需要关注其他核心的状态是否有M的,有M的必须要先让M的写入到RAM,再读最新数据。即:当read操作需要到RAM中取时,整个CPU层面不能有该缓存行状态为M的,有的必须让其先写回到RAM中。
  2. 当有核心写的时候,涉及会比较多,但是核心就是:写的时候CPU层面不能有任何其他核心处于M状态,有就需要将其先写回RAM,拿到最新的数据修改,修改完成,该核心以外的核都变为失效。
  3. 所有的这些操作都是为保证:任何核心的修改不能被覆盖!任何核心的读取,都需要拿到当前CPU缓存层面最新的值!
  4. 上面的状态很多都是相互的对应案例,比如CA的remote read,对应这CB的local read。

大致再简述下这个流程:

CA和CB以缓存行X,CB可以代表若干其他的CPU内核。

先看CA单核情况下:

  • CA第一次读X,此时X状态为E
  • CA修改了X的值,此时X状态为M
  • CA将X值如果再写回到RAM中,那么X状态又变为E

这时候加入CB参与进来:

  • CA第一次读X,此时X状态为E
    • CB也读了X,此时X就应该是共享的,所以CA和CB都是S
    • CB想写入X,那么CB需要先将X读进来,则先2个都变为S,然后B修改了X,状态变为M,并将该修改消息发送到总线,CA监听后将再本地X置为I,因为CB有最新的数据了,但是又没有写到RAM,我们既拿不到,也不能用自己cache里面的了。(个人理解,没有考究)
  • CA修改了X的值,此时X状态为M
    • CB想要读X,CPU中不能存在修改了X但还没有提交到RAM的数据,所以CA需要先将X写回到RAM,状态就会变为E,才是CB再读,CA监听读事件,CA和CB再变为S。
    • CB想要写X,因为CA是先于CB将X修改的,所以需要先将CA的写回到RAM,然后CB重新读取X后,然后再修改X,然后CA的就变成无效的I了,CB获的独占权变为M。

猜你喜欢

转载自blog.csdn.net/wgzblog/article/details/125977687