哈嘍,大家好,我是週末也在肝技術文的吳師兄。
由於在搞算法訓練營的緣故,所以師兄最近跟蹤了字節跳動最喜歡考察的一些算法題,方便給訓練營的同學制定最合理的學習大綱。
這一查,發現接雨水跌出了前十的位置,而LRU緩存機制躋身到第五的位置,真的是面試官的愛好年年都在變。
又順手查了一下LRU緩存機制最近有哪些企業喜歡考察,超級大熱門!
我思考了一下爲什麼這麼多企業喜歡考察這道題目,估計是因爲緩存就是高頻面試考點,無論是前端還是後端,都必然會用到緩存。
所以今天給大家分享一篇關於 Cache
的硬核的技術文。
“作者:桔裏貓
來源:https://zhuanlan.zhihu.com/p/386919471
排版:五分鐘學算法
”
關於 Cache
這方面內容圖比較多,不想自己畫了,所以圖都來自《Computer Architecture : A Quantitative Approach》。
這是一本體系架構方面的神書,推薦大家看一下。
本文主要內容如下,基本涉及了Cache的概念,工作原理,以及保持一致性的入門內容。
1、爲什麼需要 Cache
1.1 爲什麼需要 Cache
我們首先從一張圖來開始講爲什麼需要 Cache
.
上圖是 CPU 性能和 Memory 存儲器訪問性能的發展。
我們可以看到,隨着工藝和設計的演進,CPU 計算性能其實發生了翻天覆地的變化,但是DRAM存儲性能的發展沒有那麼快。
所以造成了一個問題,存儲限制了計算的發展。
容量與速度不可兼得。
如何解決這個問題呢?可以從計算訪問數據的規律入手。
我們隨便貼段代碼:
for (j = 0; j < 100; j = j + 1)
for( i = 0; i < 5000; i = i + 1)
x[i][j] = 2 * x[i][j];
可以看到,由於大量循環的存在,我們訪問的數據其實在內存中的位置是相近的。
換句專業點的話說,我們訪問的數據有局部性。
我們只需要將這些數據放入一個小而快的存儲中,這樣就可以快速訪問相關數據了。
總結起來,Cache是爲了給CPU提供高速存儲訪問,利用數據局部性而設計的小存儲單元。
1.2 實際系統中的 Cache
我們展示一下實際系統中的 Cache 。
如上圖所示,整個系統的存儲架構包括了 CPU 的寄存器,L1/L2/L3 CACHE,DRAM 和硬盤。
數據訪問時先找寄存器,寄存器裏沒有找 L1 Cache, L1 Cache 裏沒有找 L2 Cache 依次類推,最後找到硬盤中。
同時,我們可以看到,速度與存儲容量的折衷關係。容量越小,訪問速度越快!
其中,一個概念需要搞清楚。
CPU 和 Cache 是 word 傳輸的,而 Cache 到主存是以塊傳輸的,一塊大約 64Byte 。
現有 SOC 中的 Cache 一般組成如下。
1.3 Cache 的分類
Cache按照不同標準分類可以分爲若干類。
-
按照數據類型劃分:I-Cache與D-Cache。其中I-Cache負責放置指令,D-Cache負責方式數據。兩者最大的不同是D-Cache裏的數據可以寫回,I-Cache是隻讀的。 -
按照大小劃分:分爲small Cache和large Cache。沒路組(後文組相連介紹)<4KB叫small Cache, 多用於L1 Cache, 大於4KB叫large Cache。多用於L2及其他Cache. -
按照位置劃分:Inner Cache和Outer Cache。一般獨屬於CPU微架構的叫Inner Cache, 例如上圖的L1 L2 CACHE。不屬於CPU微架構的叫outer Cache. -
按照數據關係劃分:Inclusive/exclusive Cache: 下級Cache包含上級的數據叫inclusive Cache。不包含叫exclusive Cache。舉個例子,L3 Cache裏有L2 Cache的數據,則L2 Cache叫exclusive Cache。
2、Cache的工作原理
要講清楚 Cache 的工作原理,需要回答 4 個問題:
-
數據如何放置 -
數據如何查詢 -
數據如何被替換 -
如果發生了寫操作,Cache如何處理
2.1 數據如何放置
這個問題也好解決。我們舉個簡單的栗子來說明問題。
假設我們主存中有 32 個塊,而我們的 Cache 一共有 8 個 Cache 行( 一個 Cache 行放一行數據)。
假設我們要把主存中的塊 12 放到 Cache 裏。
三種方法:
-
全相連(Fully associative)。可以放在Cache的任何位置。 -
直接映射(Direct mapped)。只允許放在Cache的某一行。比如12 mod 8 -
組相連(set associative)。可以放在Cache的某幾行。例如2路組相連,一共有4組,所以可以放在0,1位置中的一個。
可以看到,全相連和直接映射是Cache組相連的兩種極端情況。
不同的放置方式主要影響有兩點:
1、組相連組數越大,比較電路就越大,但Cache利用率更高,Cache miss發生的概率小。2、組相連數目變小,Cache經常發生替換,但是比較電路比較小。
這也好理解,內存中的塊在Cache中可放置的位置多,自然找起來就麻煩。
2.2 如何在Cache中找數據
其實找數據就是一個比對過程,如下圖所示。
我們地址都以 Byte 爲單位的。
但主存於Cache之間的數據交換單位都是塊(block,現代Cache一般一個block大約64Byte)。所以地址對最後幾位是block offset。
由於我們採用了組相連,則還有幾個比特代表的是存儲到了哪個組。
組內放着若干數據,我們需要比較Tag, 如果組內有Tag出現,則說明我們訪問的數據在緩存中,可以開心的使用了。
比如舉個 2 路組相連的例子,如下圖所示。
T表示Tag。直接比較Tag,就能得知是不是命中了。如果命中了,則根據index(組號)將對應的塊取出來即可。
如上圖所示。用index選出位於組相連的哪個組。然後並行的比較Tag, 判斷最後是不是在Cache中。上圖是2路組相連,也就是說兩組並行比較。
那如果不在緩存中呢?這就涉及到另一個問題。
不在緩存中如何替換 Cache ?
2.3 如何替換Cache中的數據
Cache中的數據如何被替換的?這個就比較簡單直接。
-
隨機替換。如果發生Cache miss裏隨機替換掉一塊。 -
Least recently used. LRU。最近使用的塊最後替換。 -
First in, first out (FIFO), 先進先出。
實際上第一個不怎麼使用,LRU 和 FIFO 根據實際情況選擇即可。
Cache 在什麼時候數據會被替換內?也有幾種策略。
-
不在本 Cache 替換。如果Cache miss了,直接轉發訪問地址到主存,取到的數據不會寫到Cache. -
在讀MISS時替換。如果讀的時候Cache裏沒有該數據,則從主存讀取該數據後寫入Cache。 -
在寫MISS時替換。如果寫的時候Cache裏沒有該數據,則將本數據調入Cache再寫。
2.4 如果發生了寫操作怎麼辦
Cache畢竟是個臨時緩存。
如果發生了寫操作,會造成Cache和主存中的數據不一致。如何保證寫數據操作正確呢?
也有三種策略。
-
通寫:直接把數據寫回Cache的同時寫回主存。極其影響寫速度。
-
回寫:先把數據寫回Cache, 然後當Cache的數據被替換時再寫回主存。
-
通寫隊列:通寫與回寫的結合。先寫回一個隊列,然後慢慢往主存儲寫。如果多次寫同一個數據,直接寫這個隊列。避免頻繁寫主存。
3、Cache一致性
Cache 一致性是 Cache 中遇到的比較坑的一個問題。
什麼原因需要 Cache 處理一致性呢?
主要是多核系統中,假如core 0讀了主存儲的數據,寫了數據。core 1也讀了主從的數據。這個時候core 1並不知道數據已經被改動了,也就是說,core 1 Cache中的數據過時了,會產生錯誤。
Cache一致性的保證就是讓多核訪問不出錯。
策略一:基於監聽的一致性策略
這種策略是所有Cache均監聽各Cache的寫操作,如果一個Cache中的數據被寫了,有兩種處理辦法。
寫更新協議:某個Cache發生寫了,就索性把所有Cache都給更新了。
寫失效協議:某個Cache發生寫了,就把其他Cache中的該數據塊置爲無效。
策略 1 由於監聽起來成本比較大,所以只應用於極簡單的系統中。
策略二:基於目錄的一致性策略
這種策略是在主存處維護一張表。記錄各數據塊都被寫到了哪些Cache, 從而更新相應的狀態。一般來講這種策略採用的比較多。又分爲下面幾個常用的策略。
-
SI: 對於一個數據塊來講,有share和invalid兩種狀態。如果是share狀態,直接通知其他Cache, 將對應的塊置爲無效。 -
MSI:對於一個數據塊來講,有share和invalid,modified三種狀態。其中modified狀態表表示該數據只屬於這個Cache, 被修改過了。當這個數據被逐出Cache時更新主存。這麼做的好處是避免了大量的主從寫入。同時,如果是invalid時寫該數據,就要保證其他所有Cache裏該數據的標誌位不爲M,負責要先寫回主存儲。 -
MESI:對於一個數據來講,有4個狀態。modified, invalid, shared, exclusive。其中exclusive狀態用於標識該數據與其他Cache不依賴。要寫的時候直接將該Cache狀態改成M即可。
我們着重講講 MESI。圖中黑線:CPU的訪問。紅線:總線的訪問,其他Cache的訪問。
當前狀態時I狀態時,如果發生處理器讀操作 prrd。
-
如果其他Cache裏有這份數據,如果其他Cache裏是M態,先 把M態寫回主存再讀。否則直接讀。最終狀態變爲S。 -
其他Cache裏沒這個數據,直接變到E狀態。
當前狀態爲S態。
-
如果發生了處理器讀操作,仍然在S態。 -
如果發生了處理器寫操作,則跳轉到M狀態。 -
如果其他Cache發生了寫操作,跳到I態。
當前狀態E態
-
發生了處理器讀操作還是E。 -
發生了處理器寫操作變成M。 -
如果其他Cache發生了讀操作,變到S狀態。
當前狀態M態
-
發生了讀操作依舊是M態。 -
發生了寫操作依舊是M態。 -
如果其他Cache發生了讀操作,則將數據寫回主存儲,變換到S態。
4、總結
Cache 在計算機體系架構中有非常重要的地位,本文講了 Cache中最主要的內容,具體細節可以再根據某個點深入研究。
推薦閱讀:
1、從工地打工,到狂攬10個大廠offer、副業賺100萬:培訓班出來的程序員是怎麼做到的?
3、凡爾賽。。。
本文分享自微信公衆號 - 五分鐘學算法(CXYxiaowu)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。