【缓存】CPU高速缓存 之MESI 性协议 Gif 动画
缓存一致性可以分为三个点:
- 在进程每个写入运算时都立刻采取措施保证资料一致性
- 每个独立的运算,假如它造成资料值的改变,所有进程都可以看到一致的改变结果
- 在每次运算之后,不同的进程可能会看到不同的值(这也就是没有一致性的行为)
缓存一致性协议有哪些:
缓存一致性协议有MSI,MESI,MOSI,Synapse,Firefly及DragonProtocol等等
inter采用MESI协议。
注意编程中Valotile关键 的可见性是基于缓存一致原则的,不是基于MESI协议的。
MESI(梅西)协议:
VivioJS 动画旨在帮助您了解 MESI 缓存一致性协议。
描述了一个多处理器系统,包括3个CPU,具有本地缓存和主内存。为简单起见,主存储器包括4个位置a0,a1,a2和a3。缓存是直接映射的,包含两组。偶数地址(a0 和 a2)映射到设置 0,而奇数地址(a1 和 a3)映射到设置 1。
注意:为了简化此动画,缓存行的大小和 CPU 读/写操作的大小是相同的。但是,在写操作未命中时,CPU 会读取内存,即使它将完全覆盖缓存行。这模拟了实际缓存的行为,其中缓存行的大小通常大于 CPU 读/写操作的大小。
每个 CPU 都包含一些按钮,这些按钮在指定的内存位置上启动读取或写入事务。"CPU 写入"将递增值(最初为 1)写入"内存"。
我们的想法是按下按钮,看看是否可以遵循发生的操作和状态转换。可以通过按右上角的"无错误"按钮将错误引入动画中。看看你是否能确定错误是什么!
地址和数据总线上的流量方向分别由蓝色和红色箭头指示。事务中涉及的缓存行和内存位置显示为绿色。陈旧的内存位置显示为灰色。
缓存行可以处于以下 4 种状态之一。无效:缓存中不存在缓存行。EXCLUSIVE:仅此缓存中存在的缓存行,并且与内存中的副本相同。已修改:仅此缓存中存在缓存行,并且内存副本已过期(过时)。SHARED:此缓存中的缓存行以及可能的其他缓存,所有副本都与内存副本相同。对共享高速缓存行的写入是通过写来写的,而对EXCLUSIVE高速缓存行的写入是回写。如果缓存观察它所包含的地址的总线事务,它将断言 SHARED 总线行。MESI 是一种无效的缓存一致性协议。下面是缓存行的状态转换图:
1 CPU0:读取 a0 CPU0 从内存[非共享]读取 a0 - 状态 E
2 CPU0:读取 a0 CPU0 从缓存读取 a0 - 状态 E
3 CPU0: 写入 a0 CPU0 仅在缓存中更新 a0 - 状态 M
4 CPU0: 写入 a0 CPU0 仅在缓存中更新 a0 - 状态 M
5 CPU1: 读取 a0 CPU1 读取 a0,CPU0 高速缓存干预并向高速缓存和内存提供数据 - 状态 S
6 CPU1: 写入 a0 CPU1 更新缓存和内存中的 a0,并使地址为 a0 - 状态 E 的所有其他缓存失效
7 CPU1: 写入 a0 CPU1 仅在缓存中更新 a0 - 状态 M
8 CPU0: 写入 a0 CPU0 读取 a0,CPU1 缓存干预并向缓存和内存 (S) 提供数据,然后 CPU0 写入缓存和内存中的 a0,使地址为 a0 的所有其他缓存失效 - 状态
9 CPU0: 写入 a2 CPU0 从内存 (E) 读取 a2,然后写入 a2 - 状态 M
10 CPU0: 写入 a0 CPU0 将 a2 刷新到内存,从内存 (E) 读取 a2,然后写入 a0 - 状态 M
状态转换和cache操作
下面是缓存行的状态转换图:
素材来源:https://www.scss.tcd.ie/Jeremy.Jones/VivioJS/caches/MESIHelp.htm
如上文内容所述,MESI协议中cache line数据状态有4种,引起数据状态转换的CPU cache操作也有4种,因此要理解MESI协议,就要将这16种状态转换的情况讨论清楚。
初始场景:在最初的时候,所有CPU中都没有数据,某一个CPU发生读操作,此时必然发生cache miss,数据从主存中读取到当前CPU的cache,状态为E(独占,只有当前CPU有数据,且和主存一致),此时如果有其他CPU也读取数据,则状态修改为S(共享,多个CPU之间拥有相同数据,并且和主存保持一致),如果其中某一个CPU发生数据修改,那么该CPU中数据状态修改为M(拥有最新数据,和主存不一致,但是以当前CPU中的为准),其他拥有该数据的核心通过缓存控制器监听到remote write行文,然后将自己拥有的数据的cache line状态修改为I(失效,和主存中的数据被认为不一致,数据不可用应该重新获取)。
(1)modify
场景:当前CPU中数据的状态是modify,表示当前CPU中拥有最新数据,虽然主存中的数据和当前CPU中的数据不一致,但是以当前CPU中的数据为准;
LR:此时如果发生local read,即当前CPU读数据,直接从cache中获取数据,拥有最新数据,因此状态不变;
LW:直接修改本地cache数据,修改后也是当前CPU拥有最新数据,因此状态不变;
RR:因为本地内存中有最新数据,当本地cache控制器监听到总线上有RR发生的时,必然是其他CPU发生了读主存的操作,此时为了保证一致性,当前CPU应该将数据写回主存,而随后的RR将会使得其他CPU和当前CPU拥有共同的数据,因此状态修改为S;
RW:同RR,当cache控制器监听到总线发生RW,当前CPU会将数据写回主存,因为随后的RW将会导致主存的数据修改,因此状态修改成I;
(2)exclusive
场景:当前CPU中的数据状态是exclusive,表示当前CPU独占数据(其他CPU没有数据),并且和主存的数据一致;
LR:从本地cache中直接获取数据,状态不变;
LW:修改本地cache中的数据,状态修改成M(因为其他CPU中并没有该数据,因此不存在共享问题,不需要通知其他CPU修改cache line的状态为I);
RR:本地cache中有最新数据,当cache控制器监听到总线上发生RR的时候,必然是其他CPU发生了读取主存的操作,而RR操作不会导致数据修改,因此两个CPU中的数据和主存中的数据一致,此时cache line状态修改为S;
RW:同RR,当cache控制器监听到总线发生RW,发生其他CPU将最新数据写回到主存,此时为了保证缓存一致性,当前CPU的数据状态修改为I;
(3)shared
场景:当前CPU中的数据状态是shared,表示当前CPU和其他CPU共享数据,且数据在多个CPU之间一致、多个CPU之间的数据和主存一致;
LR:直接从cache中读取数据,状态不变;
LW:发生本地写,并不会将数据立即写回主存,而是在稍后的一个时间再写回主存,因此为了保证缓存一致性,当前CPU的cache line状态修改为M,并通知其他拥有该数据的CPU该数据失效,其他CPU将cache line状态修改为I;
RR:状态不变,因为多个CPU中的数据和主存一致;
RW:当监听到总线发生了RW,意味着其他CPU发生了写主存操作,此时本地cache中的数据既不是最新数据,和主存也不再一致,因此当前CPU的cache line状态修改为I;
(4)invalid
场景:当前CPU中的数据状态是invalid,表示当前CPU中是脏数据,不可用,其他CPU可能有数据、也可能没有数据;
LR:因为当前CPU的cache line数据不可用,因此会发生读内存,此时的情形如下。
A. 如果其他CPU中无数据则状态修改为E;
B. 如果其他CPU中有数据且状态为S或E则状态修改为S;
C. 如果其他CPU中有数据且状态为M,那么其他CPU首先发生RW将M状态的数据写回主存并修改状态为S,随后当前CPU读取主存数据,也将状态修改为S;
LW:因为当前CPU的cache line数据无效,因此发生LW会直接操作本地cache,此时的情形如下。
A. 如果其他CPU中无数据,则将本地cache line的状态修改为M;
B. 如果其他CPU中有数据且状态为S或E,则修改本地cache,通知其他CPU将数据修改为I,当前CPU中的cache line状态修改为M;
C. 如果其他CPU中有数据且状态为M,则其他CPU首先将数据写回主存,并将状态修改为I,当前CPU中的cache line转台修改为M;
RR:监听到总线发生RR操作,表示有其他CPU读取内存,和本地cache无关,状态不变;
RW:监听到总线发生RW操作,表示有其他CPU写主存,和本地cache无关,状态不变;
总结。
MESI协议为了保证多个CPU cache中共享数据的一致性