緩存一致性協議


現代CPU都是多核心+多級緩存架構,比方說我正在使用的這顆i5 6500,就有4顆物理核心,每顆核心獨享32K(數據)+32K(指令)的一級緩存,獨享256K的二級緩存,4顆核心共享6M的三級緩存

如果我們想要保證工作在不同核心上的線程讀取到的數據都是一致的,最簡單的做法是保證所有讀寫操作直接在內存上發生

如果真的這么做,會導致L1/L2/L3全部失效,而且所有讀寫操作全部都會落在內存總線上,效率極其低下

 

下面是一些改進方法

1. 有效位 valid bit

為每個cache line增加一個額外的bit,用於表示這個cache line的狀態:valid/invalid,制定規則如下:

讀:

1. 緩存沒有命中(cache miss或者cache line狀態為invalid),直接從內存讀取數據+寫入到cache+標記cache line為valid

2. 緩存命中 && cache line狀態為valid,直接從cache中讀取數據

寫:

1. 向所有cache發送寫信號

2. 如果有cache中有這條數據 && cache line狀態為valid,將這個cache line的狀態改為invalid

3. 將新數據寫入到內存與cache,並將相關的cache line標記為valid

驅逐:

直接從cache中刪除數據,無視cache line的狀態

優點:減少了從主存中讀取數據的次數

缺點:每次寫操作都要刷回主存

 

2. MSI Modified-Shared-Invalid

Modified:這條cache line已被修改,其數據與主存中不一致,被標記為Modified的cache line在被驅逐時,需要把數據刷回到主存中

Shared:這條cache line與主存中的數據是一致的,並且至少在一個核心中存在,這條cache line的數據在被驅逐時無需做額外操作

Invalid:這塊數據不存在,需要重新從主存中讀取

對應的讀寫規則如下:

讀:

1. 如果緩存不命中(cache miss或者cache line狀態為invalid),詢問其他cache是否含有這條數據且狀態為Modified

    a. 如果有,要求其他cache把數據寫回到內存 + 當前cache更新數據 + 兩個cache的狀態都被設為Shared。

    b. 如果沒有,直接將數據寫到cache中 + cache line標記為Shared

b. 如果緩存命中(cache line狀態為Modified或者Shared),直接從緩存中讀取數據

寫:

1. 如果緩存不命中(cache miss或者cache line狀態為invalid),詢問其他cache是否含有這條數據且狀態為Modified或者Shared

    a. 如果其他cache中有這條數據並且狀態為Modified,要求其他cache把數據寫回內存 + 當前cache獲取最新數據並與想要寫入的數據合並 + 當前cache line被標記為Modified + 其他cache line被標記為Invalid

    b. 如果其他cache中有這條數據並且狀態為Shared,那么要求這些cache將對應的cache line設為Invalid + 當前cache取數據並將對應cache line標記為Modified

    c. 如果其他cache中不含有這條數據(或者含有但是狀態為Invalid),當前cache直接取數據並將對應cache line標記為Modified

2. 如果緩存命中並且cache line的狀態為Modified,直接寫入數據

3. 如果緩存命中並且cache line的狀態為Shared,要求其他cache將這條數據標記為Invalid,向本地cache line寫入數據,並將狀態修改為Modified

驅逐:

如果cache line狀態為Modified,先將數據寫回到內存

如果cache line狀態為Shared或者Invalid,直接刪除這條cache line就可以了

MSI協議的好處是,不是每一條write操作都需要直接寫到內存(如果同一個核心對同一塊內存做連續的write操作,那么這些write操作實際上都是在cache里進行的),減少了對內存寫入的次數

同時我們又發現一個問題,如果我們想要write某條狀態為Shared的cache line,需要先查詢其他cache上是否也有這條數據,但實際上這條數據可能只被當前cache所占有。在這種情況下,其實無需做對其他cache的查詢操作。於是我們可以對MSI協議做進一步的改進,再添加一個狀態用於標記某個cache line中的數據是被當前cache獨占的情況。

於是得到了MESI協議

 

MESI Modified-Exclusive-Shared-Invalid

與MSI協議相比,Invalid不變,Modified有所調整,Shared分裂成了Shared與Exclusive。

Modified:這條cache line只在當前cache中存在,而且是臟的(與主存中的數據不一致)。在這條cache line被回寫到內存之前,禁止對內存中這條數據的read操作。在被回寫到內存中之后,這條cache line被標記為Exclusive。

Exclusive:這條cache line只在當前cache中存在(獨享),這條cache line的數據與主存中一致。如果這條cache line被其他cache讀取,Exclusive會轉為Shared。如果發生寫入,Exclusive會轉換為Modified

Shared:這條cache line可能在多個cache中存在,這個cache line的數據與主存保持一致,這條cache line可以隨時被轉化為Invalid。

Invalid:標記這條cache line是無用的

對應的讀寫規則如下:

讀:

1. 如果緩存未命中(cache miss或者cache line狀態為Invalid),查詢其他cache中是否有對應的cache line處於Modified/Exclusive/Shared模式

    a. 如果其他cache中存在處於Modified狀態的cache line,那么要求這條cache line刷回到主存,再保存到當前cache中,然后兩條cache line的狀態都設置為Shared

    b. 如果其他cache中存在處於Exclusive或者Shared狀態的cache line,那么直接把這些cache line復制到當前cache,然后將所有的cache line都設置為Shared狀態

    c. 如果其他cache中不存在Modified/Exclusive/Shared狀態的cache line,那么從主存中讀取數據寫入到當前cache,並將這條cache line的狀態設置為Exclusive

2. 如果緩存命中(cache line狀態為Modified/Shared/Exclusive),那么直接從cache中讀取數據

寫:

1. 如果緩存未命中(cache miss或者cache line狀態為Invalid),查詢其他cache中是否有對應的cache line處於Modified/Exclusive/Shared模式

     a. 如果其他cache中存在處於Modified狀態的cache line,那么要求其他cache中的cache line刷回到主存並修改狀態為Invalid。這些數據會被保存到當前cache中,然后與寫入的數據合並,當前cache中的cache line的狀態為Modified

    b. 如果其他cache中存在處於Exclusive或者Shared狀態的cache line,那么其他cache中的cache line都被標記為Invalid狀態,當前cache中的cache line被標記為Modified狀態

    c. 如果其他cache中不存在Modified/Exclusive/Shared狀態的cache line,那么直接將當前cache中的cache line標記為Modified狀態

2. 如果緩存命中(cache line的狀態為Modified/Exclusive/Shared)

    a. 如果當前cache line的狀態為Modify或者Exclusive狀態,直接向cache line寫入數據,並且將其標記為Modified狀態

    b. 如果當前cache line的狀態為Shared狀態,那么發起命令,讓其他cache中的Shared狀態的cache line狀態變更為Invalid狀態,然后向當前cache中的cache line寫入數據,並將其標記為Modified狀態

驅逐:

1. 如果cache line狀態為Modified,那么將數據寫回到主存

2. 如果cache line的狀態為Exclusive/Shared/Invalid,那么直接將這條cache line拋棄

MESI協議還是比較復雜的,但是它進一步減少了Cache與主存之間的交互操作

比方說在無競爭的先讀后寫的場景下(i = i++)

MSI協議:先從主存中讀取i的值,這條cache line被標記為Shared。此時如果我們想要修改i,就需要廣播查詢其他cache中是否含有這條cache line(實際上這條cache line是獨享的,沒有必要做廣播查詢)

MESI協議:先從主存中讀取i的值,這條cache line被標記為Exclusive,此時我們可以確定這條cache line只在當前cache中存在,所以就可以放心大膽的直接修改i,無需做廣播查詢操作。

 

參考文獻 

https://zhuanlan.zhihu.com/p/25876351

https://en.wikipedia.org/wiki/MESI_protocol

https://yq.aliyun.com/articles/8061


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM