圖解 CPU-Cache 一致性
本文轉載自微信公眾號「虛機」,作者cloud3。轉載本文請聯系虛機公眾號。
這是圖解系列之CPU cache
本文接著說Cache的一致性
我是cloud3
下面分析一下緩存一致性問題。
本文只討論硬件的cache一致性機制,所以對軟件來說是透明的。
首先來看Cache和內存保持一致性的兩種寫入方式
write through和write back
CPU把數據寫入 Cache 之后,內存與 Cache中 對應的數據就不一致了,所以要在一定的時機要把 Cache 中的數據同步到內存中。
根據寫操作后同步到內存的時機,Cache和內存同步的方法可分為write back和write through。
write through
CPU向cache寫入數據時,同時也寫入memory,使cache和memory的數據保持一致。
優點是簡單,缺點是每次都要訪問memory,速度比較慢。但是讀數據時還是能夠享受Cache帶來的快速優點的。
write back
CPU向cache寫入數據時,只是把更新的cache區標記一下(cache line 被標為dirty),并不同步寫入memory。
只是在cache區要被刷入新的數據時,才更新memory。
優點是CPU執行的效率提高,缺點是實現起來技術比較復雜。
其中write back可以減少不必要的內存寫入,減輕總線壓力。現在大部分場景下,cache多采用write back的方式,本文的介紹都是基于write back的方式。
單核一致性
首先我們看一下單處理器情況下Cache和主存之間如何保持一致性。
讀Cache:
寫Cache:
如果是多處理器呢?
多處理器的一致性問題
舉個例子吧,內存0x48處數據為0x20,處理器0和1都從0x48處讀取內存數據到自己的Cache line中。
然后處理器0寫Cache把0x48數據更新為0x10,處理器1讀0x48自己Cache命中,返回了0x20。
出現兩個處理器讀到的內存數據不一致了!
那么多處理器如何解決緩存一致性問題呢?
多處理器的一致性方法
多處理器一般是采用基于總線監聽機制的高速緩存一致性協議。包括寫無效和寫更新協議。另外還有基于目錄的高速緩存一致性機制。
總線監聽(Bus snooping)
總線監聽(Bus snooping)機制由 Ravishankar 和 Goodman 在 1983 年提出。其工作原理是當一個CPU修改了cache塊之后,此更改必須傳播到所有擁有該Cache 塊副本的Cache上。
所有的監聽者會監視總線上的所有數據廣播。如果總線上出現修改共享Cache塊的事件,所有監聽者會檢查自己的Cache是否緩存有共享Cache塊的副本。
如果緩存有該共享Cache塊的副本,則監聽者執行操作以確保緩存一致性。
這些操作可以是刷新或失效緩存塊,根據緩存一致性協議更改緩存塊狀態。
兩類總線監聽協議
根據管理本地Cache塊副本的方式,有兩類總線監聽協議:
寫更新(Write-update)
寫無效(Write-invalidate)。
寫更新(Write-update)
當處理器寫入Cache塊時,其他Cache監聽到后把自己Cache中的數據副本進行更新。該方法通過總線向所有緩存廣播寫入數據。它比寫無效協議產生更大的總線流量,所有這種方式不常見。Dragon和firefly屬于這一類協議。
寫無效(Write-invalidate)
這是最常用的監聽協議。當處理器寫入Cache塊時,其他Cache監聽到后把自己Cache中的數據副本標記為無效狀態。這樣處理器只能讀取和寫入數據的一個副本,其他緩存中的副本都是無效的。
寫直通無效協議、寫一次協議、MSI、MESI、MOSI、MOESI、MESIF都屬于寫無效這一類協議。
下面以最為常用的MESI協議為例子分析寫無效協議
MESI
MESI協議又叫Illinois協議,MESI,"M", "E", "S", "I"這4個字母代表了一個cache line的四種狀態,分別是Modified,Exclusive,Shared和Invalid。
- Modified (M)
cache line只被當前cache所有,并且是dirty的。
- Exclusive (E)
cache line僅存在于當前緩存中,并且是clean的。
- Shared (S)
cache line在其他Cache中也存在并且都是clean的。
- Invalid (I)
cache line無效,即沒有被任何Cache加載。
有一個著名的狀態標記圖:
這個狀態標記圖什么意思呢?
對同一個Cache line,
我標記它為是M時,你只能標記為I
我標記它為是E時,你只能標記為I
我標記它為是S時,你只能標記為S或I
我標記它為是I時,你能標記為MESI
MESI有一個狀態機:
這個狀態機什么意思呢?它顯示了一種狀態在出現什么Event時轉換成哪一種狀態,自己狀態轉換過程中要向總線上廣播什么消息(這些消息會被其他Cache監聽到)
下面的表是對這個狀態機的詳細說明:
舉個例子:
某Cache上一個cache line的現在狀態是Shared。
如果本地CPU對它Read hit,那它狀態還是Shared。
如果本地CPU對它Write hit,那它的狀態變為Modified,并在總線上廣播它Invalidate。
如果監聽到總線上的Read消息,那它的狀態還是Shared。
如果監聽到總線上的Invalidate消息,那它的狀態變為Invalidate。
其他的狀態轉換也是類似的處理。
總線監聽的優缺點
如果有足夠的帶寬,總線監聽比基于目錄的一致性機制更快,因為所有事務都是直接被所有處理器看到。
總線偵聽的缺點是可擴展性有限。頻繁監聽緩存會導致與處理器的訪問競爭,從而增加緩存訪問時間和功耗。每個請求都必須廣播到系統中的所有節點。這意味著總線帶寬必須隨著系統變大而增長。由于總線偵聽不能很好地擴展,較大的緩存一致性NUMA系統傾向于使用基于目錄的一致性協議。
基于目錄(Directory-based)
基于目錄的一致性方法中,緩存的Cache塊副本信息被保存在稱為目錄的結構中。當處理器寫入Cache塊時,不會向所有Cache廣播請求,而是先查詢目錄以檢索具有該副本的Cache,再發送到特定的處理器。與總線監聽相比,目錄方法可以大量節省總線流量。
在NUMA系統中,通常選擇基于目錄(directory-based)的方式來維護Cache的一致性。