1. 程式人生 > 實用技巧 >聽說你只知記憶體,而不知快取?CPU表示很傷心!

聽說你只知記憶體,而不知快取?CPU表示很傷心!

一般我們的開發同學們都知道自己機器的CPU是幾核、記憶體是多大。但是對於CPU內部對程式效能影響較大的快取卻是一知半解。有些開發同學都是計算機的快取有L1、L2、L3,但是再詳細一點的問題,可能就很少有同學能答的完整了。如果下面這幾個問題你能脫口而出,請跳過本節。例如:

  • 快取究竟在哪裡?
  • L1有幾種?
  • 你的快取有幾級,分別是多大?
  • 你的24核的機器,一二三級快取分別有幾個,存在共享的情況嗎?

其實快取對計算機程式執行效能影響極大,但是他們在開發同學心目中的存在感卻不如記憶體高。要知道CPU快取以及快取演算法的設計是現代CPU設計的核心任務之一。飛哥覺得快取們一定感到很傷心。

Intel CPU體系結構

其實在286之前的時代的CPU本是沒有快取的,因為當時的CPU和記憶體速度差異沒有現在這麼大,CPU直接訪問記憶體。但是到386時代,CPU和記憶體的速度不匹配了,第一次出現了快取。而且最早的快取並沒有放在CPU模組裡,而是放在主機板上的。再往後CPU越來越快,現在CPU的速度比記憶體要快百倍以上,所以就逐步演化出了L1、L2、L3三級快取結構,而且都整合到的CPU晶片裡,以進一步提高訪問速度。

我們來看下現代Intel的CPU架構的基本結構。

L1最接近於CPU,速度也最快,但是容量最小。一般現代CPU的L1會分成兩個,一個用來cache data,一個用來cache code,這是因為code和data的更新策略並不相同,而且因為CISC的變長指令,code cache要做特殊優化。 一般每個核都有自己獨立的data L1和code L1。
越往下,速度越慢,容量越大。L2一般也可以做到每個核一個獨立的。但是L3一般就是整顆CPU共享的了。
UEFIBlog裡提供了一個比較好的物理解剖圖,比較好地展示了出來:

實際檢視

上面介紹的只是籠統的概念。但是每個CPU的快取都是不一樣的,而且“紙上得來終覺淺”,我覺得我們還是有必要進行下一步的實機勘探工作。

Linux的核心的開發者定義了一套框架模型來完成這一目的,它就是CPUFreq系統。
CPUFreq提供的sysfs介面,可以讓我們看到比/proc/cpuinfo更為詳細的CPU詳細資訊。

# cd /sys/devices/system/cpu/;ll
drwxr-xr-x 7 root root    0 Apr 15 15:29 cpu0  
drwxr-xr-x 7 root root    0 Apr 15 15:29 cpu1  
......
  • L1一級快取檢視:
# cat cpu0/cache/index0/level  
1  
# cat cpu0/cache/index0/size  
32K  
# cat cpu0/cache/index0/type  
Data  
# cat cpu0/cache/index0/shared_cpu_list  
0,12  
# cat cpu0/cache/index1/level  
1
# cat cpu0/cache/index1/size  
32K  
# cat cpu0/cache/index1/type  
Instruction  
# cat cpu0/cache/index1/shared_cpu_list  
0,12

從上面的level介面可以看出index0和index1都是一級快取,只不過一個是Data資料快取,一個是Instruction也就是程式碼快取。
等等,上面提到的是每個Core是獨立的L1快取,為什麼shared_cpu_list顯示有共享?對了我們這裡看到的cpu0並不是物理Core,而是邏輯核,都是超執行緒技術虛擬出來的。 實際上cpu0和cpu12是屬於一個物理Core,所以每個Data L1和Instruction是這兩個邏輯核共享的。
我的這臺電腦裡,總共是有12個Data L1,12個Instrunction L1,大小都是32K。

  • L2二級快取檢視:
# cat cpu0/cache/index2/size  
256K  
# cat cpu0/cache/index2/type 
Unified  
# cat cpu0/cache/index2/shared_cpu_list  
0,12  

二級快取要比一級快取大不少,有256K,但是不分Data和Instruction。另外L2和L1一樣,也是總共有12個,每兩個邏輯核共享一個L2。

  • L3三級快取檢視:
# cat cpu0/cache/index3/size  
12288K  
# cat cpu0/cache/index3/type  
Unified  
# cat cpu0/cache/index3/shared_cpu_list  
0-5,12-17  
#cat cpu6/cache/index3/shared_cpu_list  
6-11,18-23  

L3達到了12M,你去買CPU的時候商品裡能看到的快取屬性一般告訴你的就是這個L3屬性。因為L3要比L2和L1看起來要大的多,能激發你購買的慾望。但實際上我的這臺電腦裡L3只有兩個,每個CPU各一個,不像是L2、L1有很多。第0-5,12-17號邏輯核共享一個L3,因為它們是在一個物理CPU上。6-11,18-23共享另一個。

另外,Linux上還有個dmidecode命令,也能檢視到一些關於CPU快取的資訊,感興趣的小夥伴們可以試試

# dmidecode -t cache

可能有的同學會問了,我用的作業系統是windows啊,怎麼看?開啟cmd命令列,輸入以下命令試試吧,飛哥在windows上知道的就這麼多了,感興趣的話你自己google上搜搜吧。

# wmic cpu get L2CacheSize,L3CacheSize

擴充套件知識

Cache Line:我們前面只介紹了各個級別的快取,但是這裡面有個很重要的概念就是Cache Line,就是本級快取向下一層取資料時的基本單位。可以通過如下方式檢視:

# cd /sys/devices/system/cpu/;ll
# cat cpu0/cache/index0/coherency_line_size
64
# cat cpu0/cache/index1/coherency_line_size
64
# cat cpu0/cache/index2/coherency_line_size
64
# cat cpu0/cache/index3/coherency_line_size
64

可以看到L1、L2、L3的Cache Line大小都是64位元組(注意是位元組)。就是說每次cpu從記憶體獲取資料的時候,都是以該單位來進行的,哪怕你只取一個bit,CPU也是給你取一個Cache Line然後放到各級快取裡存起來。請大家牢牢記住這個概念,以後的文章中我們會用到。



開發內功修煉之CPU篇專輯:


我的公眾號是「開發內功修煉」,在這裡我不是單純介紹技術理論,也不只介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提高你的技術實踐能力。歡迎你來關注我的公眾號,也請分享給你的好友~~~