緩存一致性模型:監聽式&目錄式

本文回顧了緩存的基本原理,並描述分析了監聽式與目錄式緩存一致性模型。緩存

Cache的基本邏輯

在瞭解緩存的一致性模型以前,首先要再重溫一下關於Cache的基本概念。dom

Cache的映射

在計算機體系結構這門課中已經瞭解了有關Cache如何組織以實現內存地址到對應Cache塊的映射。oop

這裏簡要歸納一下相關概念。性能

  • 直接映射:fetch

    直接映射是一種固定的映射方法,即主存中的一個塊只能映射到Cache中特定的塊。設計

  • 全相聯映射:code

    全相聯映射是一種偏向隨機的映射方法,即主存中任何一個塊能夠被映射到Cache的任何一個塊中。對象

  • 組相聯映射:事件

    組相聯映射是直接映射與全相聯映射的混合體。其將主存與Cache均進行分組,相同的組組內爲全相聯映射,組間爲直接映射,這樣就能夠避免每次都遍歷所有的緩存來找到對應的數據了。ip

Cache的使用邏輯

除了映射方法,在計算機組成的課程中還描述了Cache使用的基本邏輯:

  • Cache命中時,能夠直接從Cache中進行讀取,若要對Cache中的內容進行了修改

    • Write Back 策略須要對這塊Cache進行標記(dirty bit)。在被當成victim的時候寫回內存。
    • Write Throgh 策略則是同時將數據寫入主存與Cache
  • Cache不命中時,一共有如下幾種可能

    • Compulsory Miss :冷啓動時
    • Capacity Miss :Cache容量不夠用了
    • Conflict Miss:多個存儲器的位置映射到了同一個Cache位置,出現了衝突。

    在第二種或者第三種狀況下,則須要選擇一個victim(選擇 victim同時也有不一樣策略如:Random,FIFO,LRU或者RR),Wrtie Back策略時並根據其dirty bit決定是否須要寫回。而後再從內存獲取內容的同時將數據寫入Cache,供下次使用。

    若是寫入時出現了Cache miss 也提供了兩種策略:

    • Write Allocate 是先將數據讀入Cache後,再將新的修改寫到Cache上。
    • Write Non-Allocate 則是直接寫到主存上。

    其實這二者只是需不須要將這個數據在Cache中分配一個新的副本的差異。

全部的緩存的基本思想是一致的,性能與命中率緊密相關。Cache有良好的命中率是由於空間與時間的局部性。

本文描述的體系結構中研究的緩存一致性模型,則是創建在緩存基本概念上,支持多處理器對同一數據進行緩存的時候維護該數據在緩存中的一致性。

Cache 一致性協議

Cache的一致性要解決的問題能夠用如下狀況簡要表達:

處理器A與處理器B分別擁有地址爲A的數據的緩存D0。當T1時刻,處理器A修改了D0爲D1,可是沒有寫回主存。當T2時刻,處理器B取地址A的數據並將其+1。當T3時候,處理器A與處理器B都進行寫回。

這個簡單的流程中,出現了幾個嚴重的問題:

  • 在T2時刻,處理器B讀取地址A的數據不是最新的數據。
  • 在T3時刻,若是沒有一個一致性協議來維護的話,這時候就出現了三個版本的地址A的值: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 ?

涉及到這種多處理器共享存儲器的狀況,有兩個概念來保證其數據的正確:

  • 一致性(coherence) 一致性用於保證在一個處理器寫了數據之,另外的處理器讀取的數據是寫入的數據。包括了寫入操做可串行化等。
  • 連貫性(consistency)連貫性肯定了一個寫入值何時可以被看到。

在看書瞭解具體協議以前,應該能夠抽象出一種維護緩存一致性的基本思路:

相似讀寫鎖,多個處理器擁有同一地址的數據的緩存,若是僅僅進行讀操做的話,不會致使任何問題。可是一旦進行寫,問題就出現了。傳統讀寫鎖的解決方法是阻塞新的讀,並等待如今的讀完了再進行寫操做,這是一種趨向被動的思路,被動等全部讀者讀完後纔開始寫。可是緩存中沒法判斷是否一個緩存塊已經讀完,只有在被當成victim的時候換出去的時候才能察覺。很顯然這種被動的策略是不科學的。針對緩存這種場景,應該設計一種主動告知的方法,告訴其餘處理器這塊緩存塊已經更新了,不能繼續從裏面讀取數據,而是須要想辦法來取到這個地址的最新值。

緩存一致性模型就是順着這個思路,設計了兩種主動告知的策略:監聽式(Snooping Coherence Protocals) 與 目錄式 (Directory Protocol)。

  • 監聽式

    監聽式緩存一致性模型相似一種自治的協議。每個處理器都須要監聽總線上的信息。當一個處理器須要對緩存進行寫的時候,會向總線發送失效信號。其餘處理器監聽到這個消息的時候,會根據這個信號進行狀態轉移。

  • 目錄式

    目錄式則擁有一箇中央目錄控制的角色。原來向總線發送的的消息改成向目錄持有者發送消息。而目錄持有者負責改變每一個處理器上緩存數據的狀態。這樣能夠減小總線的使用。

監聽式一致性協議

協議細節

監聽式一致性協議擁有三個狀態:

  • Modified 處理器獨佔該數據,能夠讀寫
  • Shared 一個或多個處理器擁有該數據的緩存,只能讀
  • Invalid 處理器不具備讀寫該塊的權限

具體的協議細節這裏直接引用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模式可能出現的狀況:

  • 當總線上出現了Read miss時,須要將當前緩存中的數據寫回,並中斷內存訪問,其餘處理器以當前處理器發送的數據爲準。並將Modified狀態變爲shared狀態
  • 當總線上出現了write miss時,與read miss相同,不過會轉移到Invalid狀態。

另外在Shared模式的時候,一旦收到總線的Invalidate(有的處理器向shared狀態的緩存寫入數據時向總線發送)或者Write miss(有處理器須要向該緩存寫入)時,將該緩存塊的狀態改成Invalid。

確保其正確性

  1. 總線爭端

    若多個處理器要對同一個地址的數據進行更改,其會因爲同一時刻只能有一個設備佔領總線而產生總線爭端,保證了其串行化。

  2. 監聽狀態轉移

    除了處理器自己產生的事件致使的狀態轉移,監聽式緩存一致性協議最顯著的特點便是每一個處理器還將監聽總線上的內容,並根據此改變對應緩存塊的狀態。這樣保證了同一時刻只有一個處理器可以向其寫入。

存在的問題

  1. 上面第一張狀態轉移圖下面提出來的問題。圖中的write back到底是將誰寫回到哪裏?

  2. 總線爭端失敗者的行爲?先將狀態進行改變,再進行判斷是否出現miss 仍是 hit,最後再進行處理?

    好比兩個處理器都向同一個處於shared狀態的地址的緩衝塊寫入,都會發生write hit,這時只有一個處理器在總線爭端時成功,另外一個是否會從shared變成invalid後產生一個新的write miss,而後再向總線發起write miss?

  3. 若是一個處理器正在modified模式修改數據,可能會消耗幾個週期,這時候總線上傳來了read miss 或者write miss,該處理器又要將處理器讓出來?這樣是否存在死循環?

    已解決,這個就是後面描述的原子性問題。在single chip或者用bus的狀況下,能夠等操做都結束了後再釋放總線實現簡單的原子性。(並經過一個信號確認全部的處理器均收到了Invalid的信息)

MSI監聽式一致性協議的變體

  1. MESI模型:提供了一個新的狀態:Exclusive狀態。

    Exclusive狀態表示一個處理器獨佔一個緩存塊,可是沒有修改這個緩衝塊。

    若向Exclusive的狀態的緩存塊寫入數據,能夠之間將其狀態轉換爲Modified狀態,而不須要去佔領總線,節約了部分性能。

  2. MOESI模型:除了Exclusive狀態,還提供了Owned狀態。

    該狀態針對從Modified狀態轉爲Shared狀態時須要寫回內存,修改成從Modified狀態轉爲Owned狀態,並將之後的read miss從該處理器更新該值的最新狀態。

    避免了反覆寫回內存的狀況。

監聽式存在的性能瓶頸與實現

  1. Snooping bandwidth 從bus轉變到Interconnect
  2. 因爲使用了Interconnect而不是單一的bus,因此不能依靠bus來強制串行化。在這種狀況下,咱們再也不關心誰到底贏了這個競爭,而是關心誰的一致性的動做最早完成。依靠廣播全部的缺失,與Interconnect的一些特性(哪些?)來保證原子性。
  3. 也能夠在chip之間採用目錄式,chip中採用監聽式。(這個貌似後面說共享L3的分爲一組,在高層次抽象成一個對象思惟差很少)。

目錄式一致性協議

協議細節

在每一個處理器中,一個具體緩存塊的狀態依然同監聽式相同爲MSI。不一樣的是,在目錄式一致性協議中,有一個處於中央控制地位的處理器,其持有目錄並用於協調各個處理器。其中對於一個具體的緩存塊有三種狀態:Shared、Uncached(這個狀態與Invalid相似,表示沒有處理器緩存了該塊)、Exclusive。

而這些狀態則表明與處理器中的狀態有着細微的差異。Shared狀態中維護了一個bit vector,用位來指明哪些處理器擁有該數據的緩存。而Exclusive的狀態也記錄了具體是哪個處理器獲取了修改緩存的權限。這些狀態是站在一個總體角度來定義的,而非一個單一處理器的角度。

目錄式協議中處理器間通信內容以下:

協議中紅框的是處理器出現事件後,向目錄持有處理器發送的信息。然後面的黑框中是目錄持有處理器接受到請求後的動做。

其中比較特殊的有:

  • Fetch:當有處理器處於Modified狀態時,其餘處理器須要讀數據,就須要獲取修改後的數據,並將其狀態改成share
  • Fetch & invalidate :當有處理器處於Modified狀態時,其餘處理器須要寫數據,就須要獲取修改後的數據,並將其狀態改成Invalidate
  • 最後一條write back出現有兩種狀況
    • 一個是replacement的時候的寫回
    • 一個是fetch請求時的寫回。

與監聽式不一樣,這裏的全部通信都是點到點的,而不經過總線。

而處理器中具體狀態轉移與所觸發的動做見下圖:

與監聽式相似,狀態轉移都比較好理解。

而做爲中央控制的目錄持有處理器的狀態轉移以下:

其中須要注意的轉移:

  • 在Exclusive狀態下的write miss有可能

    • 當前擁有緩存塊的處理器出現Replacement
    • 其餘處理器但願可以寫

    統一進行Fetch/invalidate處理能夠cover這兩種狀況。

  • 注意從Uncached或者Shared狀態轉到Exclusive狀態的時候,均將申請擁有的處理器加入到sharers集合中。而在從Exclusive轉到Shared的時候,須要改變兩個地方,一個是以前獨佔緩存的處理器狀態,一個是當前緩存的狀態與sharers集合。

    • 經過Fetch使得以前獨佔的處理器中的狀態改編成shared並獲取最新的數據。
    • 經過在sharers集合中添加申請讀取的處理器維護sharers集合(如上所述,sharers集合中已經有了以前獨佔處理器,至關於這裏提早記錄了該處理器在shared狀態中) 這裏的細節設計比較巧妙。

存在的問題

  1. 緩存是硬件底層實現的,那麼這個擁有目錄,做爲中央控制的處理器是如何決定的?
  2. 何時開啓的緩存一致性同步?以前基於總線的能夠猜想一通電就能夠開啓,可是在SMP,一開始其餘的核都沒有起來,只有boot核在運行,這時候目錄式的一致性協議是否生效?
相關文章
相關標籤/搜索