1. 程式人生 > 實用技巧 >CPU的快取L1、L2、L3與快取行填充

CPU的快取L1、L2、L3與快取行填充

https://juejin.im/post/6844904071166427143

L1,L2,L3 指的都是CPU的快取,他們比記憶體快,但是很昂貴,所以用作快取,CPU查詢資料的時候首先在L1,然後看L2,如果還沒有,就到記憶體查詢一些伺服器還有L3 Cache,目的也是提高速度。

高速緩衝儲存器Cache是位於CPU與記憶體之間的臨時儲存器,它的容量比記憶體小但交換速度快。在Cache中的資料是記憶體中的一小部分,但這一小部分是短時間內CPU即將訪問的,當CPU呼叫大量資料時,就可避開記憶體直接從Cache中呼叫,從而加快讀取速度。由此可見,在CPU中加入Cache是一種高效的解決方案,這樣整個記憶體儲器(Cache+記憶體)

就變成了既有Cache的高速度,又有記憶體的大容量的儲存系統了。CacheCPU的效能影響很大,主要是因為CPU的資料交換順序和CPUCache間的頻寬引起的。



快取記憶體的工作原理

1. 讀取順序

CPU要讀取一個數據時,首先從Cache中查詢,如果找到就立即讀取並送給CPU處理;如果沒有找到,就用相對慢的速度從記憶體中讀取並送給CPU處理,同時把這個資料所在的資料塊調入Cache中,可以使得以後對整塊資料的讀取都從Cache中進行,不必再呼叫記憶體。

正是這樣的讀取機制使CPU讀取Cache的命中率非常高(大多數CPU可達90%左右),也就是說CPU下一次要讀取的資料90%都在Cache

中,只有大約10%需要從記憶體讀取。這大大節省了CPU直接讀取記憶體的時間,也使CPU讀取資料時基本無需等待。總的來說,CPU讀取資料的順序是先Cache後記憶體。

2. 快取分類

前面是把Cache作為一個整體來考慮的,現在要分類分析了。IntelPentium開始將Cache分開,通常分為一級快取記憶體L1二級快取記憶體L2

在以往的觀念中,L1 Cache是整合在CPU中的,被稱為片內Cache。在L1中還分資料Cache(I-Cache)和指令Cache(D-Cache)。它們分別用來存放資料和執行這些資料的指令,而且兩個Cache可以同時被CPU訪問,減少了爭用Cache所造成的衝突,提高了處理器效能。

在P4處理器中使用了一種先進的一級指令Cache——動態跟蹤快取。它直接和執行單元及動態跟蹤引擎相連,通過動態跟蹤引擎可以很快地找到所執行的指令,並且將指令的順序儲存在追蹤快取裡,這樣就減少了主執行迴圈的解碼週期,提高了處理器的運算效率。

以前的L2 Cache沒整合在CPU中,而在主機板上或與CPU整合在同一塊電路板上,因此也被稱為片外Cache。但從PⅢ開始,由於工藝的提高L2 Cache被整合在CPU核心中,以相同於主頻的速度工作,結束了L2 Cache與CPU大差距分頻的歷史,使L2 CacheL1 Cache在效能上平等,得到更高的傳輸速度。L2Cache只儲存資料,因此不分資料Cache和指令Cache。在CPU核心不變化的情況下,增加L2 Cache的容量能使效能提升,同一核心的CPU高低端之分往往也是在L2 Cache上做手腳,可見L2 Cache的重要性。現在CPUL1 CacheL2 Cache惟一區別在於讀取順序。

3. 讀取命中率

CPUCache中找到有用的資料被稱為命中,當Cache中沒有CPU所需的資料時(這時稱為未命中),CPU才訪問記憶體。從理論上講,在一顆擁有2級CacheCPU中,讀取L1 Cache的命中率為80%。也就是說CPUL1 Cache中找到的有用資料佔資料總量的80%,剩下的20%從L2 Cache讀取。由於不能準確預測將要執行的資料,讀取L2的命中率也在80%左右(從L2讀到有用的資料佔總資料的16%)。那麼還有的資料就不得不從記憶體呼叫,但這已經是一個相當小的比例了。在一些高階領域的CPU(像IntelItanium)中,我們常聽到L3 Cache,它是為讀取L2 Cache後未命中的資料設計的—種Cache,在擁有L3 CacheCPU中,只有約5%的資料需要從記憶體中呼叫,這進一步提高了CPU的效率。

為了保證CPU訪問時有較高的命中率,Cache中的內容應該按一定的演算法替換。一種較常用的演算法是“最近最少使用演算法”(LRU演算法),它是將最近一段時間內最少被訪問過的行淘汰出局。因此需要為每行設定一個計數器,LRU演算法是把命中行的計數器清零,其他各行計數器加1。當需要替換時淘汰行計數器計數值最大的資料行出局。這是一種高效、科學的演算法,其計數器清零過程可以把一些頻繁呼叫後再不需要的資料淘汰出Cache,提高Cache的利用率。

快取行填充

CPU訪問記憶體時,並不是逐個位元組訪問,而是以字長為單位訪問。比如32位的CPU,字長為4位元組,那麼CPU訪問記憶體的單位也是4位元組。

這麼設計的目的,是減少CPU訪問記憶體的次數,加大CPU訪問記憶體的吞吐量。比如同樣讀取8個位元組的資料,一次讀取4個位元組那麼只需要讀取2次。

我們來看看,編寫程式時,變數在記憶體中是否按記憶體對齊的差異。有2個變數word1、word2

圖如下:


我們假設CPU4位元組為單位讀取記憶體。如果變數在記憶體中的佈局按4位元組對齊,那麼讀取a變數只需要讀取一次記憶體,即word1;讀取b變數也只需要讀取一次記憶體,即word2

而如果變數不做記憶體對齊,那麼讀取a變數也只需要讀取一次記憶體,即word1;但是讀取b變數時,由於b變數跨越了2個word,所以需要讀取兩次記憶體,分別讀取word1word2的值,然後將word1偏移取後3個位元組,word2偏移取前1個位元組,最後將它們做或操作,拼接得到b變數的值。

顯然,記憶體對齊在某些情況下可以減少讀取記憶體的次數以及一些運算,效能更高。

另外,由於記憶體對齊保證了讀取b變數是單次操作,在多核環境下,原子性更容易保證。

但是記憶體對齊提升效能的同時,也需要付出相應的代價。由於變數與變數之間增加了填充,並沒有儲存真實有效的資料,所以佔用的記憶體會更大。這也是一個典型的空間換時間的應用場景。

參考文章


作者:簡棧文化
連結:https://juejin.im/post/6844904071166427143
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。