深入理解缓存一致性协议MESI和MOESI
扫描二维码
随时随地手机看文章
缓存一致性简介
对于单核CPU来说,不存在数据一致性问题;然而对于多核系统来说,不同CPU上的cache和ram可能具有同一个数据的多个副本。这就会导致数据观察者(CPU/GPU/DMA)能看到的数据不一致。
因此,维护cache一致性就非常有必要。维护cache一致性的关键是需要跟踪每个Cache Line的状态,并且根据读写操作和总线上相应的传输内容来更新Cache Line在不同CPU核心上的Cache Hit状态。
维护cache一致性有软件和硬件两种方式。现在大多数处理器都采用硬件来维护。在处理器中通过cache一致性协议来实现,这些协议维护了一个有限状态机,根据存储器读写指令/总线上的传输内容,进行状态迁移/相应的cache操作来维护cache一致性。
cache一致性协议本质上是如果通过硬件锁定cache line的协议,以cache line为粒度,提高效率。
MESI协议
MESI协议(Write-Once总线监听协议),MESI这四个字母分别代表Modify、Exclusive、Shared和Invalid。Cache Line的状态必须是这四个中的一种。前三种状态均是数据有效下的状态。Cache Line有两个标志-脏(dirty)和有效(valid)。脏代表该数据和内存不一致。只有干净的数据才能被多个Cache Line共享。
MESI状态描述如下:
| 状态 | 描述 | 监听任务 |
| M 修改(Modify) | 该缓存行有效,数据被修改了,和内存中的数据不一致,该数据只存在于本缓存行中 | 缓存行必须时刻监听所有试图读该缓存行相对应的内存的操作,其他缓存须在本缓存行写回内存并将状态置为E之后才能操作该缓存行对应的内存数据 |
| E 独享、互斥(Exclusive) | 该缓存行有效,数据和内存中的数据一致,该数据只存在于本缓存行中 | 缓存行必须监听其他缓存读主内存中该缓存行相对应的内存的操作,一旦有这种操作,该缓存行需要变成S状态 |
| S 共享(Shared) | 该缓存行有效,数据和内存中的数据一致,数据同时存在于其他缓存中 | 缓存行必须监听其他缓存是该缓存行无效或者独享该缓存行的请求,并将该缓存行置为I状态 |
| I 无效(Invalid) | 该缓存行数据无效 | 无 |
对一条cache line的操作有如下几种:
| 操作类型 | 描述 |
| 本地读(local read) | 本地CPU读取Cache Line |
| 本地写(local write) | 本地CPU更新Cache Line |
| 远程读(Remote read) | 来自其他cpu的读cache信号 |
| 远程写(Remote write) | 来自其他cpu的写cache信号 |
MESI状态及变化
M状态跳变
如果cache line当前状态为M,那么下一个状态有以下几种情况:
|
当前状态 |
操作 |
行为 |
下一个状态 |
|
M |
本地读(local read) |
从该cache line中读数据,状态不变 |
M |
|
M |
本地写(local write) |
往该cache line中写数据,状态不变 |
M |
|
M |
远程读(Remote read) |
如果有其他cpu来读该cache line必须完成如下操作:
|
S |
|
M |
远程写(Remote write) |
如果有其他cpu来写该cache line必须完成如下操作:
|
I |
E状态跳变
如果cache line当前状态为E,那么下一个状态有以下几种情况:
|
当前状态 |
操作 |
行为 |
下一个状态 |
|
E |
本地读(local read) |
从该cache line中读数据,状态不变 |
E |
|
E |
本地写(local write) |
往该cache line中写数据,状态改变成修改过:M |
M |
|
E |
远程读(Remote read) |
如果有其他cpu来读该cache line必须完成如下操作:
|
S |
|
E |
远程写(Remote write) |
如果有其他cpu来写该cache line必须完成如下操作:
|
I |
S状态跳变
如果cache line当前状态为S,那么下一个状态有以下几种情况:
|
当前状态 |
操作 |
行为 |
下一个状态 |
|
S |
本地读(local read) |
从该cache line中读数据,状态不变 |
S |
|
S |
本地写(local write) |
往该cache line中写数据,状态修改为M; 其他拥有该cache line备份的cpu的cache都必须置为无效状态I |
M |
|
S |
远程读(Remote read) |
如果有其他cpu来读该cache line必须完成如下操作:
|
S |
|
S |
远程写(Remote write) |
如果有其他cpu来写该cache line必须完成如下操作:
|
I |
I状态跳变
如果cache line当前状态为S,那么下一个状态有以下几种情况:
|
当前状态 |
操作 |
行为 |
下一个状态 |
|
I |
本地读(local read) |
从内存中读cache line,存在三种情况:
|
S或E |
|
I |
本地写(local write) |
从内存中读cache line,然后修改该cache line,状态修改为M; 如果其他cpu存在该cache line的备份,那么这些备份必须修改为无效I; |
M |
|
I |
远程读(Remote read) |
本地cache为无效状态,其他cpu读不影响本地状态; |
I |
|
I |
远程写(Remote write) |
本地cache为无效状态,其他cpu读不影响本地状态; |
I |
MESI状态机
MESI协议多个状态的最终状态机如下:
MESI协议的缺点
如果由特定块上的各种高速缓存执行连续读取和写入操作,则每次都必须将数据刷新到总线上。因此,主存储器将在每次冲洗时拉动它并保持清洁状态。但这不是一项要求,只是由于MESI的实施而导致的额外开销。MOESI协议克服了这一挑战。
MOESI协议
MOESI协议引入了一个O(Owned)状态,并在MESI协议的基础上,进行了重新定义了S状态,而E、M和I状态和MESI协议的对应状态相同。
-
O位。O位为1表示在当前Cache 行中包含的数据是当前处理器系统最新的数据拷贝,而且在其他CPU中一定具有该Cache行的副本,其他CPU的Cache行状态为S。如果主存储器的数据在多个CPU的Cache中都具有副本时,有且仅有一个CPU的Cache行状态为O,其他CPU的Cache行状态只能为S。与MESI协议中的S状态不同,状态为O的Cache行中的数据与存储器中的数据并不一致。
-
S位。在MOESI协议中,S状态的定义发生了细微的变化。当一个Cache行状态为S时,其包含的数据并不一定与存储器一致。如果在其他CPU的Cache中不存在状态为O的副本时,该Cache行中的数据与存储器一致;如果在其他CPU的Cache中存在状态为O的副本时,Cache行中的数据与存储器不一致。
MOESI协议优点
MOESI协议是MESI协议的一个更复杂的版本,它避免了当另一个处理器尝试读取时,需要将脏缓存行(dirty cache line)写回主内存的情况。相反,Owned状态允许处理器直接向其他处理器提供修改后的数据。当两个CPU之间的通信延迟和带宽显著优于主内存时,这种方式是有益的。一个例子是具有每核L2缓存的多核CPU。
尽管MOESI协议能够快速地从缓存中共享脏缓存行,但它不能快速共享干净的缓存行。如果一个缓存行相对于内存是干净的并且处于共享状态,那么对该缓存行的任何监听请求都将从内存中填充,而不是从缓存中。
如果处理器希望写入一个Owned缓存行,它必须通知其他正在共享该缓存行的处理器。根据具体实现,它可能只是告诉它们使它们的副本失效(将其自己的副本移动到Modified状态),或者它可能告诉它们用新内容更新它们的副本(保留其自己的副本在Owned状态)。
MOESI协议相比于MESI协议的优点是,当在其他CPU cache中发生Read hit时候,不需要将数据写回存储器,而是将数据从一个CPU直接传到另一个CPU,提高了cache利用率。
MOESI具体状态跳变这里就不重复的推演了,有兴趣的可以自己试一下。
ACE 是按照MOESI协议来实现的。
后记
技术很重要,技术背后的思想更重要!
技术背后的某些思想就是你解决以后问题的钥匙。我的文章可能一篇中知识点不太多,但是力求让你能深入理解,为你进阶打下基础。如果有一点点收获,也算是我对中国芯片行业的一点点贡献吧。





