CPU快取和記憶體屏障

小碼農薛堯發表於2019-08-28

CPU效能優化手段-快取

為了提高程式執行的效能,現代CPU在很多方面對程式進行了優化。 例如:CPU快取記憶體。儘可能地避免處理器訪問主記憶體的時間開銷,處理器大多會利用快取(cache)以提高效能。

CPU快取和記憶體屏障

多級快取

L1 Cache(一級快取)是CPU第一層快取記憶體,分為資料快取和指令快取。一般伺服器CPU的L1快取的容量通常在32-4096KB。

L2由於L1級快取記憶體容量的限制,為了再次提高CPU的運算速度,在CPU外部放置-高速儲存器,即二級快取。

L3現在的都是內建的。而它的實際作用即是,L3快取的應用可以進一步降低記憶體延遲,同時提升大資料量計算時處理器的效能。具有較大L3快取的處理器提供更有效的檔案系統快取行為及較短訊息和處理器佇列長度。一般是多核共享一個L3快取!

CPU在讀取資料時,先在L1中尋找,再從L2尋找,再從L3尋找,然後是記憶體,再後是外儲存器。

快取同步協議

多CPU讀取同樣的資料進行快取,進行不同運算之後,最終寫入主記憶體以哪個CPU為準?

在這種快取記憶體回寫的場景下,有一個快取一致性協議多數CPU廠商對它進行了實現。

MESI協議,它規定每條快取有個狀態位,同時定義了下面四個狀態:

  • 修改態(Modified)-此cache行已被修改過(髒行),內容已不同於主存,為此cache專有;
  • 專有態(Exclusive)-此cache行內容同於主存,但不出現於其它cache中;
  • 共享態(Shared)-此cache行內容同於主存,但也出現於其它cache中;
  • 無效態(Invalid)-此cache行內容無效(空行)。

多處理器,單個CPU對快取中資料進行了改動,需要通知給其它CPU。也就是意味著,CPU處理要控制自己的讀寫操作,還要監聽其他CPU發出的通知,從而保證最終一致。

CPU效能優化手段-執行時指令重排

CPU快取和記憶體屏障

指令重排的場景:當CPU寫快取時發現快取區塊正被其他CPU佔用,為了提高CPU處理效能,可能將後面的讀快取命令優先執行。

並非隨便重排,需要遵守as-if-serial語義

as-if-serial語義的意思指:不管怎麼重排序(編譯器和處理器為了提高並行度),(單執行緒)程式的執行結果不能被改變。編譯器,runtime和處理器都必須遵守as-if-serial語義。也就是說:編譯器和處理器不會對存在資料依賴關係的操作做重排序。

兩個問題

1、CPU快取記憶體下有一個問題:

快取中資料與主記憶體的資料並不是實時同步的,各CPU(或CPU核心)間快取的資料也不是實時同步。

在同一個時間點,各CPU所看到同一記憶體地址的資料的值可能是不一致的。

2、CPU執行指令重排序優化下有一個問題:

雖然遵守了as-if-serial語義,單僅在單CPU自己執行的情況下能保證結果正確。多核多執行緒中,指令邏輯無法分辨因果關聯,可能出現亂序執行,導致程式執行結果錯誤。

記憶體屏障

處理器提供了兩個記憶體屏障指令(Memory Barrier)用於解決上述兩個問題:

寫記憶體屏障(Store Memory Barrier):在指令後插入Store Barrier,能讓寫入快取中的最新資料更新寫入主記憶體,讓其他執行緒可見。強制寫入主記憶體,這種顯示呼叫,CPU就不會因為效能考慮而去對指令重排。

讀記憶體屏障(Load Memory Barrier):在指令前插入Load Barrier,可以讓快取記憶體中的資料失效,強制從主記憶體載入資料。強制讀取主記憶體內容,讓CPU快取與主記憶體保持一致,避免了快取導致的一致性問題。

CPU快取和記憶體屏障

相關文章