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
的高速度,又有記憶體的大容量的儲存系統了。Cache
對CPU
的效能影響很大,主要是因為CPU
的資料交換順序和CPU
與Cache
間的頻寬引起的。
快取記憶體的工作原理
1. 讀取順序
CPU
要讀取一個數據時,首先從Cache
中查詢,如果找到就立即讀取並送給CPU
處理;如果沒有找到,就用相對慢的速度從記憶體中讀取並送給CPU
處理,同時把這個資料所在的資料塊調入Cache
中,可以使得以後對整塊資料的讀取都從Cache
中進行,不必再呼叫記憶體。
正是這樣的讀取機制使CPU
讀取Cache
的命中率非常高(大多數CPU
可達90%左右),也就是說CPU
下一次要讀取的資料90%都在Cache
CPU
直接讀取記憶體的時間,也使CPU
讀取資料時基本無需等待。總的來說,CPU
讀取資料的順序是先Cache後記憶體。
2. 快取分類
前面是把Cache
作為一個整體來考慮的,現在要分類分析了。Intel
從Pentium
開始將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 Cache
與L1 Cache
在效能上平等,得到更高的傳輸速度。L2Cache
只儲存資料,因此不分資料Cache
和指令Cache
。在CPU
核心不變化的情況下,增加L2 Cache
的容量能使效能提升,同一核心的CPU
高低端之分往往也是在L2 Cache
上做手腳,可見L2 Cache
的重要性。現在CPU
的L1 Cache
與L2 Cache
惟一區別在於讀取順序。
3. 讀取命中率
CPU
在Cache
中找到有用的資料被稱為命中,當Cache
中沒有CPU
所需的資料時(這時稱為未命中),CPU
才訪問記憶體。從理論上講,在一顆擁有2級Cache
的CPU
中,讀取L1 Cache
的命中率為80%
。也就是說CPU
從L1 Cache
中找到的有用資料佔資料總量的80%,剩下的20%從L2 Cache
讀取。由於不能準確預測將要執行的資料,讀取L2的命中率也在80%左右(從L2讀到有用的資料佔總資料的16%)。那麼還有的資料就不得不從記憶體呼叫,但這已經是一個相當小的比例了。在一些高階領域的CPU
(像Intel
的Itanium
)中,我們常聽到L3 Cache
,它是為讀取L2 Cache
後未命中的資料設計的—種Cache
,在擁有L3 Cache
的CPU
中,只有約5%的資料需要從記憶體中呼叫,這進一步提高了CPU
的效率。
為了保證CPU
訪問時有較高的命中率,Cache
中的內容應該按一定的演算法替換。一種較常用的演算法是“最近最少使用演算法”(LRU演算法
),它是將最近一段時間內最少被訪問過的行淘汰出局。因此需要為每行設定一個計數器,LRU
演算法是把命中行的計數器清零,其他各行計數器加1。當需要替換時淘汰行計數器計數值最大的資料行出局。這是一種高效、科學的演算法,其計數器清零過程可以把一些頻繁呼叫後再不需要的資料淘汰出Cache
,提高Cache
的利用率。
快取行填充
CPU
訪問記憶體時,並不是逐個位元組訪問,而是以字長為單位訪問。比如32位的CPU
,字長為4位元組,那麼CPU
訪問記憶體的單位也是4位元組。
這麼設計的目的,是減少CPU
訪問記憶體的次數,加大CPU
訪問記憶體的吞吐量。比如同樣讀取8個位元組的資料,一次讀取4個位元組那麼只需要讀取2次。
我們來看看,編寫程式時,變數在記憶體中是否按記憶體對齊的差異。有2個變數word1、word2
:
圖如下:
我們假設CPU
以4位元組
為單位讀取記憶體。如果變數在記憶體中的佈局按4位元組對齊,那麼讀取a變數只需要讀取一次記憶體,即word1
;讀取b變數也只需要讀取一次記憶體,即word2
。
而如果變數不做記憶體對齊,那麼讀取a變數也只需要讀取一次記憶體,即word1
;但是讀取b變數時,由於b變數跨越了2個word
,所以需要讀取兩次記憶體,分別讀取word1
和word2
的值,然後將word1
偏移取後3個位元組,word2
偏移取前1個位元組,最後將它們做或操作,拼接得到b變數的值。
顯然,記憶體對齊在某些情況下可以減少讀取記憶體的次數以及一些運算,效能更高。
另外,由於記憶體對齊保證了讀取b變數是單次操作,在多核環境下,原子性更容易保證。
但是記憶體對齊提升效能的同時,也需要付出相應的代價。由於變數與變數之間增加了填充,並沒有儲存真實有效的資料,所以佔用的記憶體會更大。這也是一個典型的空間換時間的應用場景。
參考文章
作者:簡棧文化
連結:https://juejin.im/post/6844904071166427143
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。