CPU性能優化手段 - 緩存
為了提高程序的運行性能, 現代CPU在很多方面對程序進行了優化
例如: CPU高速緩存, 盡可能的避免處理器訪問主內存的時間開銷, 處理器大多會利用緩存以提高性能
多級緩存
L1 Cache (一級緩存)是CPU第一層高速緩存, 分為數據緩存和指令緩存, 一般服務器CPU的L1緩存的容量通常在32-4096kb
L2 Cache (二級緩存) 由於L1高速緩存的容量限制, 為了再次提高CPU的運算速度, 在CPU外部放置一高速緩存存儲器, 即二級緩存
L3 Cache(三級緩存)現在都是內置的, 而它的實際作用既是, 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處理性能, 可能將后面的讀緩存命令優先執行.
當然也並非隨便重排, 需要遵循as-if-serial語義
as-if-serial語義的意思指: 不管怎么重排序, 程序的執行結果不能被改變
編譯器, runtime和處理器都必須遵守as-if-serial語義, 也就是說, 編譯器和處理器不會對存在數據依賴關系的操作做重排序
兩個問題
-
CPU高速緩存下有一個問題:
緩存中的數據與主內存的數據並不是實時同步的, 各CPU間緩存的數據也不是實時同步. 在同一時間點, 各CPU所看到的同一內存地址的數據的值可能是不一致的. -
CPU執行指令重排序優化的一個問題:
雖然遵守了as-if-serial語義, 但僅在單CPU自己執行的情況下能保證結果正確. 多核多線程中, 指令邏輯無法分辨因果關聯, 可能出現亂序執行, 導致程序運行結果錯誤
解決方法 - 內存屏障
處理器提供了兩個內存屏障指令(Memory Barrier)用於解決上述兩個問題:
寫內存屏障(Store Memory Barrier): 在指令后插入Store Barrier, 能讓寫入緩存中的最新數據更新寫入主內存, 讓其他線程可見
強制寫入主內存, 這種顯示調用, CPU就不會因為性能考慮而進行指令重排
讀內存屏障(Load Memory Barrier): 在指令前插入Load Barrier, 可以讓高速緩存中的數據失效, 強制從新從主內存讀取數據
強制讀取主內存內容, 讓CPU緩存和主內存保持一致, 避免了緩存導致的一致性問題