話說人們在1870年左右開始應(yīng)用黃色火藥,在1900年左右開始大量普及電動(dòng)地鐵,并建成了埃菲爾鐵塔(1898)等偉大工程,但是軍事技術(shù)的發(fā)展、革新最多的僅是二戰(zhàn)前后的1936到1945的這幾年時(shí)間,現(xiàn)在的軍事技術(shù)也大都僅是對二戰(zhàn)時(shí)的軍事技術(shù)體系的深化,如自動(dòng)步槍,噴氣引擎,潛艇,坦克和反坦克等等。所以我們認(rèn)為,高強(qiáng)度的行業(yè)競爭,帶來其領(lǐng)域技術(shù)的深入發(fā)展,而因其深入的發(fā)展,其中的許多設(shè)計(jì)理念和產(chǎn)出,往往惠及了很多的民用領(lǐng)域,如復(fù)雜的渦輪增壓技術(shù)是二戰(zhàn)戰(zhàn)斗機(jī)的標(biāo)配,現(xiàn)在也經(jīng)過簡化,惠及到民用汽車領(lǐng)域。
而現(xiàn)在信息技術(shù)領(lǐng)域中白熱化的競爭莫過于Intel和AMD之間的藍(lán)紅之爭,其競爭讓CPU的設(shè)計(jì)和架構(gòu)經(jīng)過千錘百煉,是一個(gè)現(xiàn)代人類設(shè)計(jì)和實(shí)踐的結(jié)晶。因此我們探究一下CPU底層的實(shí)現(xiàn),其中的思路和理念,特別是現(xiàn)在多核心CPU的設(shè)計(jì),也會(huì)對我們的高性能系統(tǒng),以及分布式系統(tǒng)的設(shè)計(jì)和使用有很多借鑒和幫助。
另外其實(shí)人們也發(fā)現(xiàn)往往一些帶有分形的東西,其不僅廣泛存在,而且也代表著很多我們未知的合理結(jié)構(gòu),如人們所說的黃金分割,宇宙及黑洞等,其也都和分形有關(guān)聯(lián),分形可以簡單理解為不斷深入的底層構(gòu)成,和其上層構(gòu)成有結(jié)構(gòu)上的相似。因此我們探究底層的設(shè)計(jì),也對我們上層系統(tǒng)的設(shè)計(jì)有一定的參考和指導(dǎo)作用。
如下圖所示是Intel的Skylake的CPU架構(gòu),我們可以看到緩存被分為L1、L2、L3這3層,CPU在運(yùn)行中首先使用自己的寄存器,然后使用速度更快的L1緩存,其中:L1D緩存數(shù)據(jù);L1I緩存指令;L1緩存和次快的L2同步數(shù)據(jù);L2緩存和L3緩存同步數(shù)據(jù)(這里L(fēng)2和L3按照內(nèi)核數(shù)量做了等分,分給各個(gè)內(nèi)核使用),我們可以簡單地認(rèn)為L3和內(nèi)存同步數(shù)據(jù)。
Intel的PPT 中Skylake的緩存示意圖的截圖
為什么會(huì)有這么多級的緩存呢?因?yàn)槊考壘彺娴乃俣炔町惡艽螅娇斓木彺嫒萘吭叫?,因此CPU把緩存分成多級,每一級作為上一級的緩存。(其實(shí)在多核的情況下訪問緩存會(huì)有一些同步問題,我們在下文討論)
而我們可以認(rèn)為目前CPU的緩存性能差異如表所示(參考了卡耐基梅隆大學(xué)在2014年的教案等)。
緩存性能表
在上表中要注意以下內(nèi)容:
1. L1、L2、L3的最小讀寫單位是64bit(8字節(jié))。
2. L2的周期已包含L1(miss)的周期,L3的周期已包含L2(miss)的周期。
3. 內(nèi)存訪問應(yīng)該還有TLB(虛擬地址頁表緩存)的miss的情況,會(huì)增加少量周期。
4. 其實(shí)CPU的寄存器的整體大小為2KB左右,在64位下除了RAX、RBX、RCX、RDX、RSI、RDI、RSP、RBP、R8-R15這16個(gè)通用寄存器,如Intel還大概有:MMX:80bit X 8,ZMM(YMM,XMM):512bit X 32等寄存器,還有控制:64bit X 16,調(diào)試:64bit X 16,以及其他零散分類下及系統(tǒng)自用的若干。
因?yàn)檫@些緩存和內(nèi)存在性能上的差異,所以對CPU的密集運(yùn)算則是越少訪問內(nèi)存越好,比如在發(fā)生一次CAS操作時(shí),如果這個(gè)內(nèi)存訪問能命中L2緩存,則還是比較高效的;但是如果L2 miss 連同 L3 miss ,則會(huì)變成一次讀內(nèi)存的重操作,影響并發(fā)的性能(約100ns的耗時(shí)),同理,對于正常的鎖的操作,緩存miss時(shí)會(huì)耗時(shí)較多(約200ns的耗時(shí))。
下面是Intel的Skylake 的架構(gòu)圖,與Sandy Bridge 的架構(gòu)圖,和AMD的ZEN 的架構(gòu)圖。
Intel的Skylake的架構(gòu)圖
Intel的Sandy Bridge 的架構(gòu)圖
AMD的ZEN 的架構(gòu)圖
Intel和AMD的CPU的架構(gòu)圖雖然看著差異挺大,但它們的大結(jié)構(gòu)其實(shí)是一樣的,大概都分為3個(gè)模塊。
1. 前端執(zhí)行(front end):對應(yīng)Intel圖的上面及對應(yīng)AMD圖上面;這個(gè)是L1指令cache處理指令解碼(DECODE),分支預(yù)測,執(zhí)行隊(duì)列,調(diào)度器,等這些指令功能。
2. 計(jì)算:對應(yīng)INTEL圖的左下及對應(yīng)AMD圖的中間;這個(gè)就是整數(shù)計(jì)算單元和浮點(diǎn)計(jì)算單元。
3. 緩存/內(nèi)存:對應(yīng)INTEL圖的右下及對應(yīng)AMD圖的下面;這個(gè)就是內(nèi)存控制器(內(nèi)存讀寫控制器及隊(duì)列,以及TLB(內(nèi)存頁表的虛擬地址轉(zhuǎn)換緩存))及L1數(shù)據(jù)緩存和L2緩存。
從這些圖上我們可以看出,L1命令緩存AMD的Zen是64KB,而Intel是32KB;L2緩存AMD的Zen是512KB,Intel是256KB,這個(gè)和CPU型號也有關(guān)系,但還是說明同一代下AMD的CPU在一些配置上更優(yōu)一些。
這里也說下,網(wǎng)上流傳說,在AMD的Zen之前Intel的CPU的強(qiáng)大的浮點(diǎn)功能(以及除法器),是Intel在跑分上勝利的其中一個(gè)重要因素,AMD認(rèn)為都有顯卡了,顯卡浮點(diǎn)計(jì)算的能力非常強(qiáng)大,因此CPU不需要太強(qiáng)的浮點(diǎn)功能了……。
再有我們在看AMD的PPT時(shí)會(huì)發(fā)現(xiàn),除了L1數(shù)據(jù)緩存到寄存器堆(register
file)還有個(gè)AGU到load/store queues模塊的箭頭,這里可能感覺比較奇怪,其實(shí)這個(gè)AGU的組件AMD和Intel都有,Intel的沒有畫出(之前的架構(gòu)PPT里有,現(xiàn)在應(yīng)該屬于Load Store Data這,但沒有畫出),這個(gè)全稱是Address Generation Unit,用來加速計(jì)算實(shí)際的物理地址,以及計(jì)算數(shù)組中的地址等。(另外,其實(shí)大家知道應(yīng)用程序中的內(nèi)存地址對CPU和操作系統(tǒng)來講都是比較麻煩的虛擬地址)。下圖是AMD的緩存/內(nèi)存單元單元的一個(gè)展開圖(圖中L1數(shù)據(jù)緩存上的To Ex是到整數(shù)計(jì)算單元,To Fp是到浮點(diǎn)計(jì)算單元)。如圖
AMD的緩存/內(nèi)存部分的展開圖
上面介紹了CPU整體的架構(gòu)圖,以及緩存在CPU架構(gòu)圖中的位置,這里先介紹下CPU在單核環(huán)境下的多級緩存的架構(gòu)。
現(xiàn)在CPU都流行多核芯的架構(gòu),而我們先看其中的一個(gè)核心對緩存操作的流程,我們可以整體認(rèn)為:當(dāng)核心(Core)訪問(讀或?qū)懀㎜1緩存時(shí)沒有命中(miss)則訪問L2緩存和L3緩存,在L3緩存也沒有命中時(shí)才操作內(nèi)存。多級緩存在獨(dú)占(exclusive)模式下,L1緩存中通過LRU策略逐出的數(shù)據(jù)會(huì)到L2,在L2中逐出的會(huì)到L3,在L3中逐出的有寫入/修改的數(shù)據(jù)則同步到內(nèi)存。
緩存的操作的最小單元我們可以叫緩存單元,英文是cache line,每個(gè)緩存單元緩存64bit(8Byte)的數(shù)據(jù),訪問緩存時(shí)通過內(nèi)存單元的物理地址。另外我們常看到8WAY,16WAY這種來描述緩存,其實(shí)緩存的在使用時(shí)是個(gè)類似二維數(shù)組的形式,這里的列就是WAY,如8WAY,就是8列。訪問時(shí)通過物理地址的高位和中位從列(WAY)和行(SET)中命中一個(gè)緩存單元(cache line,也可以翻譯成緩存行),可參考下圖示意。
AMD文檔中的緩存操作示意
緩存單元因其一次必須操作連續(xù)的8Byte的數(shù)據(jù),但是我們不希望類似下面這樣的情況,如兩個(gè)相鄰的整型(4Byte)數(shù)據(jù)會(huì)同時(shí)被多個(gè)CPU核心進(jìn)行頻繁修改,而其都在一個(gè)緩存單元內(nèi),其每次修改都會(huì)觸發(fā)我們后面講的核心的緩存到內(nèi)存的同步問題。
我們先看看具體讀寫命中和未命中的情況:
1. 緩存沒有命中的情況:
a). 對于單核心的讀,讀操作會(huì)先檢查緩存,在緩存中沒有數(shù)據(jù)時(shí)會(huì)載入數(shù)據(jù)到緩存(cache line fill)中。
b). 對于單核心的寫,其同讀操作,會(huì)先檢查緩存,在緩存中沒有數(shù)據(jù)時(shí)會(huì)載入數(shù)據(jù)到緩存中,然后執(zhí)行寫操作,這里寫操作只是簡單的寫了載入過來的緩存,并不同步到內(nèi)存(這里需要注意,按照Intel的開發(fā)文檔,老的Pentium默認(rèn)的情況是在緩存miss后寫操作直接寫內(nèi)存,而不是載入數(shù)據(jù)到緩存后寫緩存)。
2. 緩存命中的情況:
a). 如果讀命中(cache hit),則直接使用數(shù)據(jù);
b). 如果這里是寫操命(write hit)時(shí)則也是直接操作緩存,而不主動(dòng)同步到內(nèi)存。
我們也看看CPU的緩存的使用流程:
1. CPU的前端解析L1命令緩存中的指令進(jìn)行預(yù)測和亂序執(zhí)行等
2. 通過這些指令,計(jì)算單元具體處理從L1數(shù)據(jù)緩存到寄存器中的數(shù)據(jù)的計(jì)算
3. 將計(jì)算的結(jié)果更新到L1數(shù)據(jù)緩存,若要同步緩存中的數(shù)據(jù)到內(nèi)存,則通過硬件實(shí)現(xiàn)的寫緩存邏輯(write buffers)可靠地異步刷新數(shù)據(jù)到系統(tǒng)總線及內(nèi)存(可理解為通過一個(gè)消息隊(duì)列寫)。
這里可以看參考下圖所示。
緩存相關(guān)流程,取自AMD技術(shù)文檔
這里則是整個(gè)單核心的的流程,我們注意到,CPU通過緩存提高性能的一個(gè)關(guān)鍵要點(diǎn)是在寫的情況下只寫緩存,不同步緩存數(shù)據(jù)到內(nèi)存。
推薦一起學(xué)習(xí)《分布式服務(wù)架構(gòu):原理、設(shè)計(jì)與實(shí)戰(zhàn)》一書,它是一本不可多得的理論與實(shí)踐相結(jié)合的架構(gòu)秘籍,是作者多年工作經(jīng)驗(yàn)積累的結(jié)晶。京東購買請掃描下方二維碼。
如果你想成為優(yōu)秀的架構(gòu)師
在【云時(shí)代架構(gòu)】精品群免費(fèi)進(jìn)!
我在【云時(shí)代架構(gòu)】技術(shù)社區(qū),你在哪里?
還等什么,趕快加入【云時(shí)代架構(gòu)】技術(shù)社區(qū)!
請猛掃下面二維碼。
云時(shí)代架構(gòu)
做互聯(lián)網(wǎng)時(shí)代最適合的架構(gòu)
開放、分享、協(xié)作