目录
一、缓存一致性问题
二、一致性实现方案
2.1 目录一致性协议
2.2 嗅探一致性协议
三、CHI协议
3.1 cache state
3.2 snoop维护一致性
四、其他一致性协议
4.1 MSI协议
4.2 MESI 协议
4.3 MOESI协议
本文介绍以下内容:
- 缓存一致性问题
- 一致性实现方案
- CHI协议
- MESI协议
一、缓存一致性问题
cache一致性的问题是什么呢?下图cpu,cache给标了一个号
假设现在所有的cache都没有数据
- cpu0从DDRC读了一个数据到L00,这个数据地址是0x0010,数据是0x1111。那么L2,L10,L00都有这个数据了!
- 然后CPU0对这个地址数据改写了,把这个地址数据改成0x2222,写回到L00 。那么现在,L00里面地址0x0010的数据是0x2222. L10,L2,DDRC里面这个地址的数据是0x1111.
- 然后CPU1也要读一个数据,地址还是这个0x0010,请问!!我CPU读到这个地址的数据是什么呢,应该是L10里的0x1111,还是L00里面的0x2222呢!
- CPU2,CPU3读这个地址应该读到什么数据呢?
cache一致性问题是什么:不同的cpu或进程,读同一个地址,读到的数据不一样,这就是cache一致性的问题。
导致这个问题的原因:是因为多个cache的存在!同一个物理地址只能存一个数据,多级cache的存在造成了同一个物理地址的数据在不同的cache中可能有不同的数据。
cache一致性的目标,是要让所有的CPU都读到最新更新的0x2222这个数据,而不是0x1111这个旧数据。
二、一致性实现方案
缓存一致性是为了保证在多核或多处理器系统中,各个处理器或核心之间共享的数据的一致性。以下是常见的缓存一致性实现方法:
- 目录(Directory)一致性协议
- 嗅探(snoop)一致性协议
2.1 目录一致性协议
目录协议使用一个共享的目录来记录内存块的状态和所在的缓存位置。目录跟踪每个内存块是否被缓存、缓存块的状态以及所在的处理器。当一个处理器对内存进行操作时,它需要先向目录发送请求,并根据目录的响应来决定如何更新缓存。
单纯的Directory没有具体使用过,就不多展开了,可以参考这个链接:
《内存一致性与缓存一致性》笔记(八):目录一致性协议 - 知乎
2.2 嗅探一致性协议
对于soc维持一致性的,一般有两种:
1)基于总线的Snoop机制。
一种是HN只要收到一个请求,就snoop到所有的节点,假设cpu1有数据就回,如果snoop到cpu2,cpu2没有数据,那就不用回数据了,优点是HN不用搞个directory记录各个cacheline的状态。缺点也很明显,所有的请求你都要完整地snoop到各个节点,带宽啥的,有点笨。这种呢,就适合少节点的,要是2,3个节点那你就随便snoop吧,其实现在一般的消费者级别的芯片都是这种,ACE(协议)啥的。
2)基于目录表的Snoop机制。CHI使用这种,HN要搞个directory记录着各个cacheline,所以来了一个请求,我HN是知道哪个cpu有这个地址的数据的,所以每来一个请求,HN就查directory,查到哪个节点有数据,什么状态,就精准的往对应节点发snoop。
所以CHI协议,是基于directory和snoop机制来维持cache一致性的一个系统。
Snoop Filter(嗅探过滤器)是一种用于缓存一致性协议的硬件结构,用于减少嗅探(snoop)操作对总线带宽和处理器性能的影响。
- Snoop Filter 通常位于ICN的Home节点,每个处理器也会记录cacheline的状态。
- 记录缓存行在其他处理器的状态信息,例如是否被修改、是否是共享等。
- Snoop Filter 通过查询确定是否需要执行嗅探操作,从而减少嗅探操作的广播范围和总线带宽开销。
- Snoop Filter 可以记录全地址,也可以采用哈希表等结构来实现,以提供高效的查询和更新操作。
snoop如何维护一致性详见本文3.2
三、CHI协议
3.1 cache state
- I:Invalid,该cacheline的数据不在当前cache中;
- UC:Unique Clean,该cacheline的数据只在当前cache中,且和memory的数据一致,可以不知会其它RN就对该cacheline的数据进行修改。在收到snoop请求时,该cacheline不需要返回数据给HN或fwd data给RN;
- UCE:Unique Clean Empty,该cacheline的数据只在当前cache中,但是所有的数据都是无效的,可以不知会其它RN就对该cacheline的数据进行修改。在收到snoop请求时,该cacheline必须不能返回数据给HN或fwd data给RN;
- UD:Unique Dirty,该cacheline的数据只在当前cache中,且和memory的数据不一致,已经被修改过了;如果该cacheline的数据不用了,那需要写回到下级cache或memory;可以不知会其它RN就对该cacheline的数据进行修改。在收到snoop请求时,该cacheline必须返回数据给HN或fwd data给RN;
- UDP:Unique Dirty Partial,该cacheline的数据只在当前cache中,且和memory的数据不一致,部分被修改且有效;如果该cacheline的数据不用了,那需要和下级cache或memory的数据组成一个完成有效的cacheline;可以不知会其它RN就对该cacheline的数据进行修改。在收到snoop请求时,该cacheline必须返回数据给HN,但不能直接将数据fwd给Requester;
- SC:Shared Clean,其它cache可能也存在该cacheline的拷贝;该cacheline可能已经被修改了;当不需要该cacheline数据时,cache没有义务必须将该数据写回到memory;必须对其它cache的该cacheline进行无效后,获得U态才能将该cacheline进行改写;在收到snoop请求时,该cacheline在RetToSrc没有置位时不需要返回数据,如果RetToSrc置位,则需要返回数据,可以直接fwd数据给Requester;
- SD:Shared Dirty,其它cache可能也存在该cacheline的拷贝;该cacheline相对于memory已经被修改了;当该cacheline不需要的时候,cache需要将它写回下游cache或memory;必须对其它cache的该cacheline进行无效后,获得U态后才能将该cacheline进行改写。在收到snoop请求时,该cacheline必须返回数据给HN和fwd data给Requester;
---CHI协议的更多内容请参见本专栏的其他文章。
3.2 snoop维护一致性
CHI定义了cache state,要求不管哪个PE想要对一个地址写,必须要先获取Unique状态,也就是确保整系统中,其他cache都没有这个数据。也就是独占这个地址,才可以操作这个地址。
下面画个时空图描述下:
具体步骤:
假设某时刻有3个RNF拥有某cacheline,状态都是SC态,RNF-0想要更新该cacheline:
- 1. RNF0发出一个Store请求(CleanUnique)
- 2. HNF收到Store请求,查询Snoop Filter,发现RNF1和RNF2都有该cacheline的副本,然后HNF分别向RNF1和RNF2发出使cacheline无效掉的snoop事务(SnpCleanInvalid)。
- 3. RNF1和RNF2收到SnpCleanInvalid后,将cacheline置为无效I态,并返回snoop响应(SnpResp_I)。
- 4. HNF收到RNF1和RNF2的snoop响应之后,表明目前系统中只有RNF0才有该cacheline,那么向RNF0返回响应(Comp_UC)。
- 5. RNF0收到Comp_UC的响应,表示RNF0已经独占该地址了,就可以进行数据更新。
-
四、其他一致性协议
一致性协议除了上面说的CHI,还有开始使的MSI协议,然后进化到MESI,再到MOESI。这里简单补充一下。
4.1 MSI协议
MSI协议是最基础的协议,只定义了三种状态:
- Modified(修改)
- Shared(共享)
- Invalid(无效)
这是最初级的缓存一致性协议,在现代处理器中已经很少使用了。
Modified:
当前缓存行的数据已被本地处理器修改,并且与内存中的数据不同。如果其他处理器请求这个数据,拥有这个数据的处理器需要将数据写回内存,并且将自己的缓存行标记为Shared。
Shared:
当前缓存行的数据没有被修改,并且可能被其他处理器缓存。
Invalid:
当前缓存行的数据是无效的。
4.2 MESI 协议
MESI协议是最常见的协议之一,它定义了四种状态:
- Modified(修改)
- Exclusive(独占)
- Shared(共享)
- Invalid(无效)
每个缓存行都标记为其中一种状态,根据处理器对该行的操作状态会改变。
Modified:
当前缓存行的数据已被本地处理器修改,并且与内存中的数据不同。如果其他处理器请求这个数据,拥有这个数据的处理器需要将数据写回内存,并且将自己的缓存行标记为Shared。
Exclusive:
当前缓存行的数据没有被修改,并且只有本地处理器有这个数据的缓存。
Shared:
当前缓存行的数据没有被修改,并且可能被其他处理器缓存。
Invalid:
当前缓存行的数据是无效的。
通俗的讲一下。MESI协议是一种常见的缓存一致性协议,用于处理多处理器系统中的数据共享和一致性问题。它定义了四种状态,分别是修改(Modified)、独享(Exclusive)、共享(Shared)和无效(Invalid)。
想象一下,你和你的朋友都有一本书的副本。这本书代表着一个共享的数据块。
修改(Modified):当你想要修改书中的内容时,你拥有该书的独家访问权,并且你的朋友的副本已过时。因此,你可以自由地修改书中的内容,而不必担心其他人看到旧版。
独享(Exclusive):当你只是独自拥有这本书的副本,并且它与主要来源(例如图书馆)保持一致。你可以读取书中的内容,但不能修改它。其他人可能也有相同的书,但与你的副本是独立的,没有冲突。
共享(Shared):当你和你的朋友都有这本书的副本时,它是共享的。这意味着你们都可以读取书中的内容,而且它们应该是一致的。如果你想要修改书中的内容,你需要先将它标记为修改状态,并通知其他人停止使用他们的副本。
无效(Invalid):当你的朋友告诉你他们有一本书的新副本时,你的副本就变得无效了。这意味着你的副本已过时或不再可用。你需要丢弃你的副本,并从他们那里获取最新的副本。
MESI协议通过这些状态的管理和转换,确保多个处理器之间共享数据的一致性。当一个处理器想要修改共享数据时,它必须将其状态设置为修改(Modified),同时通知其他处理器使其副本无效。其他处理器在访问共享数据时,会检查自己的副本状态,以确定是否需要更新或共享。这样,数据的一致性得以维护,避免了冲突和不一致的情况。
MESI协议是一种用于处理多处理器系统中缓存一致性的协议。通过定义不同的状态和相应的转换规则,它确保共享数据的一致性,使多个处理器能够正确地访问和更新数据。类比于你和朋友共享一本书的副本,你需要协调修改和访问的顺序,以保证数据的正确性和一致性。
4.3 MOESI协议
MOESI协议在MESI的基础上增加了一个Owner状态,用于解决在多个处理器都缓存了同一个块的数据时,数据更新的问题。
- M,Modified, Unique Dirty, 只存在于当前cache中(unique),并且该cache line上的数据与下一级存储单元中的数据不同(dirty)。换言之,cache line中最新的数据位于当前cache,其他cache中没有备份 ,cache line中的内容与主存中的不一致。
- O,Owned,Shared Dirty,描述一个cache line为dirty,并且可能存在于多个cache中(不止一个)。一个 Owned 状态的cache line保存着 最新的 而且 正确的(new and correct) 的数据。只有一个core的cache 可以将数据保存为 Owned 状态,其他core 为 shared 状态。
- E,Exclusive, Unique Clean,数据只存在于当前cache line中,并且为clean的。cache中cache line中的数据于主存中的一致,并且其他core中的cache没有该地址的数据 备份,只存在一个cache中。
- S,Shared, Shared ,cache line中的data不一定与主存中的一致,与 Owned状态的cache line相对应,将Owned里的数据复制到shared的cache line中,因此 shared cache line中的数据也是最新的。
- I,Invalid,无效的数据。
下面是状态转换图:
参考链接:
CHI到底有啥用 保证Cache一致性 2.1 Cache一致性问题是啥_chi一致性维护-CSDN博客
CHI到底有啥用 保证Cache一致性 2.1 Cache一致性问题是啥_chi一致性维护-CSDN博客