一、微操作μ-op與宏操作macro-op
英特爾SunnyCove內(nèi)核前端
圖片來源:英特爾
上圖為英特爾Sunny Cove內(nèi)核前端。因為CISC的指令長度不確定,且比較復雜,英特爾將這些指令切割成固定長度,這個微指令從Pentium Pro開始在IA架構(gòu)出現(xiàn)。處理器接受的是x86指令(CISC指令,復雜指令集),而在執(zhí)行引擎內(nèi)部執(zhí)行的卻不是x86指令,而是一條一條的類RISC指令,Intel 稱之為Micro Operation,即micro-op或μ-op,一般用比較方便的寫法來替代掉希臘字母: u-op或者uop。相對地,融合了多條指令的操作就稱之為Macro Operation或macro-op,即宏操作。
英特爾逐漸改進微指令,后來加入微指令緩存即uOP cache,也有的地方叫L0級緩存,表面看來,uOP cache被定位為一個2級指令cache單元,是1級指令cache單元的子集。其獨特之處在于它所存儲的是譯碼之后的指令(uOPs)。早期Micro-op cache是由32組8條cacheline組成。每條cacheline最多保留6條uOps,共計1536條uOps,Sunny Cove是48組,也就是2304條uOps。這個Cache是在兩個線程之間共享的,并保留了指向micro sequencer ROM的指針。它也是虛擬地址尋址,是L1指令cache的嚴格的子集。每條cacheline還包括其包含的uop數(shù)量及其長度。
內(nèi)核一直都在處理來自指令流(Instruction Stream)的連續(xù)的32byte信息。同樣地,uOPcache也是基于32byte窗口。因此uOP cache可以基于LRU(Least Recently Used)策略存儲或者放棄整個窗口。英特爾將傳統(tǒng)的流水線稱為“l(fā)egacy decode pipeline”。在首次迭代時,所有的指令都是經(jīng)過“l(fā)egacy decode pipeline”。一旦整個指令流窗口被譯碼并且發(fā)送到分配隊列,窗口的拷貝就被發(fā)送到uOP cache。這是與所有其他操作同時發(fā)生的,因此這個功能沒有增加額外的流水線階段。后續(xù)的迭代,被緩存的已經(jīng)解碼好的指令流就可以直接被發(fā)送到分配隊列了,省卻了取指、預譯碼和譯碼的階段,節(jié)省功耗,增加了吞吐量。這也是一個更短的流水線,延遲也減小了。?
uOP cache有著高于80%的命中率。在取指期間,分支預測器將會讀取uOPscache的tags。如果命中了cache,會可以每周期發(fā)送至多4條uops(可能包含了fused macro-ops)到Instruction Decode Queue(IDQ),繞開了其他所有本該進行的預譯碼和譯碼。
ARMCortex-A77微架構(gòu)
圖片來源:ARM
上圖為ARM Cortex-A77的架構(gòu)圖,自A77開始,ARM也添加了經(jīng)解碼后的指令緩存,與英特爾的uOP緩存高度類似,只不過ARM反其道用之,英特爾是把CISC指令切割成微指令,ARM是融合,把定長定格式的RISC指令融合成宏操作MOP(Macro Operation),然后再分割成uOP。這樣做可能是RISC指令分得太散,有些是可以融合的,這樣效率更高。再有就是解碼器通常比后端吞吐量更高,有足夠的MOP緩存可以讓后端工作更飽和,利用率更高。
A78也是如此,每周期4個指令,6個MOPs,X1則不同,每周期5個指令,8個MOPs。
A78譯碼到分布
圖片來源:互聯(lián)網(wǎng)
二、發(fā)射與執(zhí)行
ARM和AMD的執(zhí)行單元一般將整數(shù)計算(ALU)與浮點計算(FPU)分開,英特爾則是合二為一,執(zhí)行端關(guān)鍵的參數(shù)是發(fā)射寬度(Issue Width),目前最寬的是ARM的V1,多達15位,寬度越寬,ALU和FPU數(shù)量可以越多。通常ALU是4個,整數(shù)運算單元4個就夠。V1有4個ALU,4個針對浮點的NEON,其中包含兩個SVE。3個Load加載,2個寫入Store。還有兩個分支針對特定計算類型。
圖片來源:互聯(lián)網(wǎng)
所有計算機程序的本質(zhì),是指令的執(zhí)行過程,從根本上說,也就是處理器的寄存器(Register)到內(nèi)存之間的數(shù)據(jù)交互過程。這個交互,無非兩個步驟:讀內(nèi)存,也就是加載操作(load), 從內(nèi)存讀到寄存器,寫內(nèi)存,就是存儲操作(store),從寄存器寫入到內(nèi)存,LSU就是Load Store Unit。
LSU部件是指令流水線的一個執(zhí)行部件,其上接收來自內(nèi)核的LSU發(fā)射序列,其下連接著存儲器子系統(tǒng)即數(shù)據(jù)緩存。其主要功能是將來自CPU的存儲器請求發(fā)送到存儲器子系統(tǒng),并處理其下存儲器子系統(tǒng)的應答數(shù)據(jù)和消息。在許多微架構(gòu)中,引入了AGU(尋址生成器)計算有效地址以加速存儲器指令的執(zhí)行,使用ALU(計算單元,通常是標量計算單元)的部分流水處理LSU中的數(shù)據(jù)。而從邏輯功能上看,AGU和ALU所做的工作依然屬于LSU。
三、定點與浮點
所謂定點格式,即約定機器中所有數(shù)據(jù)的小數(shù)點位置是固定不變的。通常將定點數(shù)據(jù)表示成純小數(shù)或純整數(shù),為了將數(shù)表示成純小數(shù),通常把小數(shù)點固定在數(shù)值部分的最高位之前;而為了將數(shù)表示成純整數(shù),則把小數(shù)點固定在數(shù)值部分的最后面。
比如十進制的3.75,那么你可以用011+0.11,但是這種加法首先要對齊位寬,對齊目的就是讓大家的單位一致。你可以把011擴展為011.00,把0.11擴展為000.11,這樣一相加就得到011.11,就是十進制的3.75了,存在電腦的時候,電腦是沒有小數(shù)點的,只會存為01111。如果是定點格式,這個小數(shù)點的位置就固定了,無法變動,由于計算的時候必須對齊位寬,這使得電腦能處理的數(shù)據(jù)范圍受到限制,不能太大,也不能太小。假設以一個字節(jié)表示小數(shù),小數(shù)點固定在5.3的位置,高5位表示整數(shù),低3位表示小數(shù):11001_001 —— 11001.001,轉(zhuǎn)換一下:整數(shù)部分11001= 25,?????????????????? 小數(shù)部分001 = 1(分子部分) 分母是1000(8),所以小數(shù)部分1/8(二級制只有0和1)。最終的小數(shù)表示是 25+ 1/8,即存在 0/8, 1/8,2/8,? …. ?7/8共八個檔,表示精度為1/8,所以定點小數(shù)存在數(shù)值范圍和數(shù)值精度的問題!數(shù)值范圍與精度是一對矛盾,一個變量要想能夠表示比較大的數(shù)值范圍,必須以犧牲精度為代價;而想精度提高,則數(shù)的表示范圍就相應地減小。在實際的定點算法中,為了達到最佳的性能,必須充分考慮到這一點,即權(quán)衡動態(tài)范圍和精度。
如果是邏輯運算或簡單的整數(shù)運算還可以,如果要顯示比較大的變量,小數(shù)點的位置必須可以自由移動,這就是浮點。
圖片來源:互聯(lián)網(wǎng)
比如123.45用十進制科學計數(shù)法可以表示為1.2345x102,其中1.2345為尾數(shù),10為基數(shù),2為指數(shù)。浮點數(shù)利用指數(shù)達到了浮動小數(shù)點的效果,從而可以靈活地表達更大范圍的實數(shù)。IEEE754指定了:兩種基本的浮點格式:單精度和雙精度。其中單精度格式具有24位有效數(shù)字(即尾數(shù))精度,總共占用32位;雙精度格式具有53位有效數(shù)字(即尾數(shù))精度,總共占用64位。
兩種擴展浮點格式:單精度擴展和雙精度擴展。此標準并未規(guī)定這些格式的精確精度和大小,但指定了最小精度和大小,例如IEEE雙精度擴展格式必須至少具有64位有效數(shù)字精度,并總共占用至少79位。
浮點運算和定點運算(整數(shù)運算)不同,它通常是6個步驟:1. 異常檢測:主要檢測NAN(非數(shù)) 2. 對階,尾數(shù)右移:不同階碼尾數(shù)不能直接相加減,所以需要對階,比如1.1 * 2 E 1 ?+ 1.1 * 2 E 2 尾數(shù)就不能運算,對階,尾數(shù)右移,最終階碼一致。3 . 尾數(shù)求和求差,將對階后的尾數(shù)按定點加減運算規(guī)則進行運算。4. 規(guī)格化:把非規(guī)格的小數(shù)轉(zhuǎn)換為規(guī)格化的小數(shù)。5. 在對階和右移過程中,可能會將尾數(shù)的低位丟失,引起誤差,影響精度,為此可用舍入法來提高尾數(shù)的精度。IEEE754標準列出了四種可選的舍入處理方法:向上舍入,向下舍入,向最近舍入,直接截去。6. 溢出檢查,與定點數(shù)運算不同的是,浮點數(shù)的溢出是以其運算結(jié)果的階碼的值是否產(chǎn)生溢出來判斷的。若階碼的值超過了階碼所能表示的最大正數(shù),則為上溢,進一步,若此時浮點數(shù)為正數(shù),則為正上溢。若浮點數(shù)為負數(shù),則為負上溢。進一步,若此時浮點數(shù)為正數(shù),則為正下溢,若浮點數(shù)為負數(shù),則為負下溢。正下溢和負下溢都作為機器零處理,即將尾數(shù)各位強制為零。?
四、具體CPU微架構(gòu)
特斯拉使用AMD的CPU,因此特別對AMD的微架構(gòu)做以說明。
圖片來源:互聯(lián)網(wǎng)
這是Zen 2代微架構(gòu)的前端,ITLB就是 Instruction Translation Lookaside Buffer,另一種說法是指令轉(zhuǎn)換后備緩沖區(qū)。AMD的L0/L1/L2緩存與傳統(tǒng)的緩存定義不同,它解簽了軟件意義上的緩存而非硬件,L1里有BTB緩存,Hash路徑緩存表,ITLB緩存好幾種。Zen3代則將L1的BTB緩存由512條擴展到1024條,提高分支預測準確度。雖然L1緩存異常復雜,但總?cè)萘窟€是32K,分8路。Return Stack是方法返回棧,可能是分支預測異常的返回地址。
分支預測器經(jīng)過Micro tags最終變?yōu)?個宏操作Marco Ops,進入宏操作緩存,緩存量為4K條,指令緩存排成序列,進入譯碼器,譯碼器寬度是4位,8個宏操作和4個譯碼后的指令進入OC/IC,分解為微操作序列,再分別進入堆疊引擎和存儲獨立偵測系統(tǒng)還有微碼序列ROM,再進入分發(fā)站。
圖片來源:互聯(lián)網(wǎng)
Zen2代微架構(gòu)的執(zhí)行端,執(zhí)行端分整數(shù)和浮點兩大執(zhí)行器,綠色為整數(shù),粉色為浮點。整數(shù)部分指令經(jīng)過重命名和定位后進入序列器,完成后提交或者說退出Retire再進入物理寄存器文件,再前向混合,進入ALU4個算數(shù)計算器,3個地址生成器。Zen3代的寄存器條目增加到212個。浮點方面寄存器略少,F(xiàn)ADD和FMA分別是加法和乘法管線,管線有4條,Zen3代增加到6條,不過計算管線還是4條。
圖片來源:互聯(lián)網(wǎng)
最后是加載和寫入部分。
Zen2 Die Shot
圖片來源:互聯(lián)網(wǎng)
Zen 2代一個核的透視圖,可以看到緩存占芯片的面積最大,其次是浮點運算用的SIMD,然后是分支預測,加載與寫入,譯碼,計算用的ALU所占面積很小。