本文回顧了緩存的基本原理,並描述分析了監聽式與目錄式緩存一致性模型。緩存
在瞭解緩存的一致性模型以前,首先要再重溫一下關於Cache的基本概念。dom
在計算機體系結構這門課中已經瞭解了有關Cache如何組織以實現內存地址到對應Cache塊的映射。oop
這裏簡要歸納一下相關概念。性能
直接映射:fetch
直接映射是一種固定的映射方法,即主存中的一個塊只能映射到Cache中特定的塊。設計
全相聯映射:code
全相聯映射是一種偏向隨機的映射方法,即主存中任何一個塊能夠被映射到Cache的任何一個塊中。對象
組相聯映射:事件
組相聯映射是直接映射與全相聯映射的混合體。其將主存與Cache均進行分組,相同的組組內爲全相聯映射,組間爲直接映射,這樣就能夠避免每次都遍歷所有的緩存來找到對應的數據了。ip
除了映射方法,在計算機組成的課程中還描述了Cache使用的基本邏輯:
Cache命中時,能夠直接從Cache中進行讀取,若要對Cache中的內容進行了修改
Cache不命中時,一共有如下幾種可能
在第二種或者第三種狀況下,則須要選擇一個victim(選擇 victim同時也有不一樣策略如:Random,FIFO,LRU或者RR),Wrtie Back策略時並根據其dirty bit決定是否須要寫回。而後再從內存獲取內容的同時將數據寫入Cache,供下次使用。
若是寫入時出現了Cache miss 也提供了兩種策略:
其實這二者只是需不須要將這個數據在Cache中分配一個新的副本的差異。
全部的緩存的基本思想是一致的,性能與命中率緊密相關。Cache有良好的命中率是由於空間與時間的局部性。
本文描述的體系結構中研究的緩存一致性模型,則是創建在緩存基本概念上,支持多處理器對同一數據進行緩存的時候維護該數據在緩存中的一致性。
Cache的一致性要解決的問題能夠用如下狀況簡要表達:
處理器A與處理器B分別擁有地址爲A的數據的緩存D0。當T1時刻,處理器A修改了D0爲D1,可是沒有寫回主存。當T2時刻,處理器B取地址A的數據並將其+1。當T3時候,處理器A與處理器B都進行寫回。
這個簡單的流程中,出現了幾個嚴重的問題:
D1,D0~1,D0
。寫回後也沒法預測內容中保存的值爲多少。Time | Processor A | Processor B | Memory A |
---|---|---|---|
T0 | D0 | D0 | D0 |
T1 | D1 | D0 | D0 |
T2 | D1 | D0+1 | D0 |
T3 | X | X | ? |
涉及到這種多處理器共享存儲器的狀況,有兩個概念來保證其數據的正確:
在看書瞭解具體協議以前,應該能夠抽象出一種維護緩存一致性的基本思路:
相似讀寫鎖,多個處理器擁有同一地址的數據的緩存,若是僅僅進行讀操做的話,不會致使任何問題。可是一旦進行寫,問題就出現了。傳統讀寫鎖的解決方法是阻塞新的讀,並等待如今的讀完了再進行寫操做,這是一種趨向被動的思路,被動等全部讀者讀完後纔開始寫。可是緩存中沒法判斷是否一個緩存塊已經讀完,只有在被當成victim
的時候換出去的時候才能察覺。很顯然這種被動的策略是不科學的。針對緩存這種場景,應該設計一種主動告知的方法,告訴其餘處理器這塊緩存塊已經更新了,不能繼續從裏面讀取數據,而是須要想辦法來取到這個地址的最新值。
緩存一致性模型就是順着這個思路,設計了兩種主動告知的策略:監聽式(Snooping Coherence Protocals) 與 目錄式 (Directory Protocol)。
監聽式
監聽式緩存一致性模型相似一種自治的協議。每個處理器都須要監聽總線上的信息。當一個處理器須要對緩存進行寫的時候,會向總線發送失效信號。其餘處理器監聽到這個消息的時候,會根據這個信號進行狀態轉移。
目錄式
目錄式則擁有一箇中央目錄控制的角色。原來向總線發送的的消息改成向目錄持有者發送消息。而目錄持有者負責改變每一個處理器上緩存數據的狀態。這樣能夠減小總線的使用。
監聽式一致性協議擁有三個狀態:
具體的協議細節這裏直接引用Computer Architecture中的Chapter 5 Thread-Level Parallelsim的內容
其中紅框中的內容是因爲處理器自己的事件致使的,而黑框中是從總線中接收到傳來的各類信息後進行的狀態轉移。紅框中對應的狀態轉移以下圖。
須要注意其中紅線的四個狀況是屬於Cache miss中本來的Conflict Miss,其表示本來放在Cache中的內容被替換,Cache中沒有目的地址的數據(這在上面列表的Type of Cache action的一欄下標註爲Replacement)。
這裏的Write-Back究竟是將誰寫回 不太理解 是指將共享L3上的備份寫回到內存嗎?若是發生了miss的話 本地的Cache已經不包含對應的數據了,應該在後一級緩存中(L3或者memory)那writeback是指的什麼。
這個部分則是監聽式一致性協議的精華。先看Shared模式可能出現的狀況:
另外在Shared模式的時候,一旦收到總線的Invalidate(有的處理器向shared狀態的緩存寫入數據時向總線發送)或者Write miss(有處理器須要向該緩存寫入)時,將該緩存塊的狀態改成Invalid。
總線爭端
若多個處理器要對同一個地址的數據進行更改,其會因爲同一時刻只能有一個設備佔領總線而產生總線爭端,保證了其串行化。
監聽狀態轉移
除了處理器自己產生的事件致使的狀態轉移,監聽式緩存一致性協議最顯著的特點便是每一個處理器還將監聽總線上的內容,並根據此改變對應緩存塊的狀態。這樣保證了同一時刻只有一個處理器可以向其寫入。
上面第一張狀態轉移圖下面提出來的問題。圖中的write back到底是將誰寫回到哪裏?
總線爭端失敗者的行爲?先將狀態進行改變,再進行判斷是否出現miss 仍是 hit,最後再進行處理?
好比兩個處理器都向同一個處於shared狀態的地址的緩衝塊寫入,都會發生write hit,這時只有一個處理器在總線爭端時成功,另外一個是否會從shared變成invalid後產生一個新的write miss,而後再向總線發起write miss?
若是一個處理器正在modified模式修改數據,可能會消耗幾個週期,這時候總線上傳來了read miss 或者write miss,該處理器又要將處理器讓出來?這樣是否存在死循環?
已解決,這個就是後面描述的原子性問題。在single chip或者用bus的狀況下,能夠等操做都結束了後再釋放總線實現簡單的原子性。(並經過一個信號確認全部的處理器均收到了Invalid的信息)
MESI模型:提供了一個新的狀態:Exclusive狀態。
Exclusive狀態表示一個處理器獨佔一個緩存塊,可是沒有修改這個緩衝塊。
若向Exclusive的狀態的緩存塊寫入數據,能夠之間將其狀態轉換爲Modified狀態,而不須要去佔領總線,節約了部分性能。
MOESI模型:除了Exclusive狀態,還提供了Owned狀態。
該狀態針對從Modified狀態轉爲Shared狀態時須要寫回內存,修改成從Modified狀態轉爲Owned狀態,並將之後的read miss從該處理器更新該值的最新狀態。
避免了反覆寫回內存的狀況。
在每一個處理器中,一個具體緩存塊的狀態依然同監聽式相同爲MSI。不一樣的是,在目錄式一致性協議中,有一個處於中央控制地位的處理器,其持有目錄並用於協調各個處理器。其中對於一個具體的緩存塊有三種狀態:Shared、Uncached(這個狀態與Invalid相似,表示沒有處理器緩存了該塊)、Exclusive。
而這些狀態則表明與處理器中的狀態有着細微的差異。Shared狀態中維護了一個bit vector,用位來指明哪些處理器擁有該數據的緩存。而Exclusive的狀態也記錄了具體是哪個處理器獲取了修改緩存的權限。這些狀態是站在一個總體角度來定義的,而非一個單一處理器的角度。
目錄式協議中處理器間通信內容以下:
協議中紅框的是處理器出現事件後,向目錄持有處理器發送的信息。然後面的黑框中是目錄持有處理器接受到請求後的動做。
其中比較特殊的有:
與監聽式不一樣,這裏的全部通信都是點到點的,而不經過總線。
而處理器中具體狀態轉移與所觸發的動做見下圖:
與監聽式相似,狀態轉移都比較好理解。
而做爲中央控制的目錄持有處理器的狀態轉移以下:
其中須要注意的轉移:
在Exclusive狀態下的write miss有可能
統一進行Fetch/invalidate處理能夠cover這兩種狀況。
注意從Uncached或者Shared狀態轉到Exclusive狀態的時候,均將申請擁有的處理器加入到sharers集合中。而在從Exclusive轉到Shared的時候,須要改變兩個地方,一個是以前獨佔緩存的處理器狀態,一個是當前緩存的狀態與sharers集合。