算是讀書筆記吧
極客時間--深入淺出計算機組成原理
最簡單的 CPU
1. 首先晌该,我們有一個自動計數(shù)器
這個自動計數(shù)器會隨著時鐘主頻不斷地自增拱层,來作為我們的 PC 寄存器弥臼。
2. 在這個自動計數(shù)器的后面,我們連上一個譯碼器
譯碼器還要同時連著我們通過大量的 D 觸發(fā)器組成的內(nèi)存根灯。
3. 自動計數(shù)器會隨著時鐘主頻不斷自增
從譯碼器當中径缅,找到對應(yīng)的計數(shù)器所表示的內(nèi)存地址,然后讀取出里面的 CPU 指令烙肺。讀取出來的 CPU 指令會通過我們的 CPU 時鐘的控制纳猪,寫入到一個由 D 觸發(fā)器組成的寄存器,也就是指令寄存器當中桃笙。
4. 在指令寄存器后面氏堤,我們可以再跟一個譯碼器
這個譯碼器不再是用來尋址的了,而是把我們拿到的指令搏明,解析成 opcode 和對應(yīng)的操作數(shù)鼠锈。
5. 執(zhí)行具體指令
當我們拿到對應(yīng)的 opcode 和操作數(shù),對應(yīng)的輸出線路就要連接 ALU星著,開始進行各種算術(shù)和邏輯運算购笆。
對應(yīng)的計算結(jié)果,則會再寫回到 D 觸發(fā)器組成的寄存器或者內(nèi)存當中虚循。
指令周期(Instruction Cycle)
計算機每執(zhí)行一條指令所需要的一次循環(huán)同欠,就叫指令周期
計算機每執(zhí)行一條指令的過程样傍,可以分解成這樣幾個步驟:
1.Fetch(取得指令)
由控制器(Control Unit)操作
也就是從 PC 寄存器里找到對應(yīng)的指令地址,根據(jù)指令地址從內(nèi)存里把具體的指令铺遂,加載到指令寄存器中衫哥,然后把 PC 寄存器自增,好在未來執(zhí)行下一條指令娃循。
2.Decode(指令譯碼)
由控制器(Control Unit)操作
也就是根據(jù)指令寄存器里面的指令炕檩,解析成要進行什么樣的操作,是 R捌斧、I、J 中的哪一種指令泉沾,具體要操作哪些寄存器捞蚂、數(shù)據(jù)或者內(nèi)存地址。
3.Execute(執(zhí)行指令)
由算術(shù)邏輯單元(ALU)跷究,也就是運算器進行操作姓迅。
也就是實際運行對應(yīng)的 R、I俊马、J 這些特定的指令丁存,進行算術(shù)邏輯操作、數(shù)據(jù)傳輸或者直接的地址跳轉(zhuǎn)柴我。
不過解寝,如果是一個簡單的無條件地址跳轉(zhuǎn),那么我們可以直接在控制器里面完成艘儒,不需要用到運算器聋伦。
指令寄存器
存放當前正在執(zhí)行的指令,包括指令的操作碼界睁,地址碼觉增,地址信息
PC 寄存器
存放著下一條指令的地址
也叫程序計數(shù)器,是用來計數(shù)的翻斟,指示指令在存儲器的存放位置逾礁,也就是個地址信息。
各種函數(shù)調(diào)用访惜、條件跳轉(zhuǎn)嘹履。其實只是修改 PC 寄存器里面的地址。
PC 寄存器里面的地址一修改疾牲,計算機就可以加載一條指令新指令植捎,往下運行。
譯碼器
- 無論是對于指令進行 decode
- 根據(jù)內(nèi)存地址去獲取對應(yīng)的數(shù)據(jù)或者指令
運算器
可以完成數(shù)據(jù)的存儲阳柔、處理和傳輸?shù)膯卧媸唷MǔS蓛刹糠纸M成:
-
操作元件
ALU,也叫組合邏輯元件(Combinational Element)
在特定的輸入下,根據(jù)不同組合電路的邏輯济锄,生成特定的輸出暑椰。
-
存儲元件
也叫狀態(tài)元件
比如我們在計算過程中需要用到的寄存器,無論是通用寄存器還是狀態(tài)寄存器荐绝,其實都是存儲元件一汽。
控制器
機械地重復(fù)“Fetch - Decode - Execute“循環(huán)中的前兩個步驟,然后把最后一個步驟低滩,通過控制器產(chǎn)生的控制信號召夹,交給 ALU 去處理
時序邏輯電路
任意時刻的輸出僅僅取決于該時刻的輸入,與電路原來的狀態(tài)無關(guān)恕沫。
類似加減乘除法器
時序邏輯電路
任意時刻的輸出不僅取決于當時的輸入信號监憎,而且還取決于電路原來的狀態(tài),或者說婶溯,還與以前的輸入有關(guān)鲸阔。
也就是我們說的記憶功能。
最常見的這個電路就是我們的 D 觸發(fā)器迄委,它也是我們實際在 CPU 內(nèi)實現(xiàn)存儲功能的寄存器的實現(xiàn)方式褐筛。
這也是現(xiàn)代計算機體系結(jié)構(gòu)中的“馮·諾伊曼”機的一個關(guān)鍵,就是程序需要可以“存儲”叙身,而不是靠固定的線路連接或者手工撥動開關(guān)渔扎,來實現(xiàn)計算機的可存儲和可編程的功能。
流水線設(shè)計
通過將一個CPU指令的執(zhí)行步驟曲梗,拆分成多個小步驟的方式赞警。達到縮短單個時鐘周期的目的。
單指令周期處理器
在一個時鐘周期里虏两,確保執(zhí)行完一條最復(fù)雜的 CPU 指令愧旦,也就是耗時最長的一條 CPU 指令
如果 PC 寄存器自增地太快,程序就會出錯定罢。
因為前一次的運算結(jié)果還沒有寫回到對應(yīng)的寄存器里面的時候笤虫,后面一條指令已經(jīng)開始讀取里面的數(shù)據(jù)來做下一次計算了。
這個時候祖凫,如果我們的指令使用同樣的寄存器琼蚯,前一條指令的計算就會沒有效果,計算結(jié)果就錯了惠况。
這樣做的弊端是遭庶,無論是執(zhí)行一條用不到 ALU 的無條件跳轉(zhuǎn)指令,還是一條計算起來電路特別復(fù)雜的浮點數(shù)乘法運算稠屠,我們都等要等滿一個時鐘周期峦睡。
指令流水線
每個步驟獨立運作翎苫,不需要等待整條指令執(zhí)行完畢的這種協(xié)作方式,將原本串行起來的幾個步驟并行執(zhí)行榨了。叫做指令流水線煎谍。
CPU 本身的設(shè)計,是由一個個獨立的組合邏輯電路串接起來形成的龙屉,天然能夠適合這樣采用流水線“專業(yè)分工”的工作方式呐粘。
-
流水線級(Pipeline Stage)
每一個獨立的步驟,我們就稱之為流水線階段或者流水線級(Pipeline Stage)转捕。
如果我們把一個指令拆分成“取指令
- 指令譯碼
- 執(zhí)行指令
”這樣三個部分作岖,那這就是一個三級的流水線
。
如果我們進一步把“執(zhí)行指令
”拆分成“ALU 計算(指令執(zhí)行)
- 內(nèi)存訪問
- 數(shù)據(jù)寫回
”五芝,那么它就會變成一個五級的流水線
鳍咱。
-
這樣,我們不需要確保最復(fù)雜的那條指令在時鐘周期里面執(zhí)行完成与柑,而只要保障一個最復(fù)雜的流水線級的操作,在一個時鐘周期內(nèi)完成就好了蓄坏。
如果某一個操作步驟的時間太長价捧,我們就可以考慮把這個步驟,拆分成更多的步驟涡戳,讓所有步驟需要執(zhí)行的時間盡量都差不多長结蟋。這樣,也就可以解決我們在單指令周期處理器中遇到的渔彰,性能瓶頸來自于最復(fù)雜的指令的問題嵌屎。像我們現(xiàn)代的 ARM 或者 Intel 的 CPU,流水線級數(shù)都已經(jīng)到了 14 級恍涂。
超長流水線
-
Pentium 4與Athlon的CPU大戰(zhàn)
流水線設(shè)計帶來的性能提升也引出了現(xiàn)代桌面 CPU 的最后一場大戰(zhàn)宝惰,也就是 Intel 的 Pentium 4 和 AMD 的 Athlon 之間的競爭
在技術(shù)上,這場大戰(zhàn) Intel 可以說輸?shù)梅浅氐自俨祝琍entium 4 系列以及后續(xù) Pentium D 系列所使用的 NetBurst 架構(gòu)被完全拋棄尼夺,退出了歷史舞臺。但是在商業(yè)層面炒瘸,Intel 卻通過遠超過 AMD 的財力淤堵、原本就更大的市場份額、無所不用的競爭手段顷扩,以及最終壯士斷腕般放棄整個 NetBurst 架構(gòu)拐邪,最終依靠新的酷睿品牌戰(zhàn)勝了 AMD。
在此之后隘截,整個 CPU 領(lǐng)域競爭的焦點扎阶,不再是 Intel 和 AMD 之間的桌面 CPU 之戰(zhàn)汹胃。在 ARM 架構(gòu)通過智能手機的快速普及,后來居上乘陪,超越 Intel 之后统台,移動時代的 CPU 之戰(zhàn),變成了高通啡邑、華為麒麟和三星之間的“三國演義”贱勃。
那 2000 年發(fā)布的 Pentium 4 的流水線深度是多少呢?答案是 20 級谤逼,比 Pentium III 差不多多了一倍贵扰,而到了代號為 Prescott 的 90 納米工藝處理器 Pentium 4,Intel 更是把流水線深度增加到了 31 級流部。
-
超長流水線的弊端
- 功耗問題
需要的寄存器變多戚绕。主頻的提升和晶體管數(shù)量的增加都使得我們 CPU 的功耗變大了。 - 依賴問題很難解決
過長的流水線使得任務(wù)之間的依賴處理復(fù)雜度成指數(shù)級的增長枝冀。
三大冒險
任何一本講解 CPU 的流水線設(shè)計的教科書舞丛,都會提到流水線設(shè)計需要解決的三大冒險,分別是
結(jié)構(gòu)冒險(Structural Hazard)
果漾、數(shù)據(jù)冒險(Data Hazard)
以及控制冒險(Control Hazard)
結(jié)構(gòu)冒險
結(jié)構(gòu)冒險球切,本質(zhì)上是一個硬件層面的資源競爭問題,也就是一個硬件電路層面的問題绒障。
CPU 在同一個時鐘周期吨凑,同時在運行兩條計算機指令的不同階段。但是這兩個不同的階段户辱,可能會用到同樣的硬件電路鸵钝。
最典型的例子就是內(nèi)存的數(shù)據(jù)訪問,訪存(MEM)和取指令(Fetch)都要進行內(nèi)存數(shù)據(jù)的讀嚷洹:
訪存(MEM)和取指令(Fetch)都要進行內(nèi)存數(shù)據(jù)的讀取恩商。而我們的內(nèi)存,只有一個地址譯碼器的作為地址輸入焚鹊,無法同時進行這兩件事痕届。
普林斯頓架構(gòu)(Princeton Architecture)
也就是馮·諾依曼體系結(jié)構(gòu)
的內(nèi)存結(jié)構(gòu)如圖所示
這其實和薄膜鍵盤的“鎖鍵”問題一樣。
常用的最廉價的薄膜鍵盤末患,并不是每一個按鍵的背后都有一根獨立的線路研叫,而是多個鍵共用一個線路。如果我們在同一時間璧针,按下兩個共用一個線路的按鍵嚷炉,這兩個按鍵的信號就沒辦法都傳輸出去。
這也是為什么探橱,重度鍵盤用戶申屹,都要買貴一點兒的機械鍵盤或者電容鍵盤绘证。因為這些鍵盤的每個按鍵都有獨立的傳輸線路,可以做到“全鍵無沖”哗讥。
哈佛架構(gòu)(Harvard Architecture)
把我們的內(nèi)存分成兩部分嚷那,讓它們各有各的地址譯碼器。這兩部分分別是存放指令的程序內(nèi)存和存放數(shù)據(jù)的數(shù)據(jù)內(nèi)存杆煞。
現(xiàn)代CPU的混合架構(gòu)
現(xiàn)代的 CPU 雖然沒有在內(nèi)存層面進行對應(yīng)的拆分魏宽,卻在 CPU 內(nèi)部的高速緩存部分進行了區(qū)分,把高速緩存分成了指令緩存(Instruction Cache)和數(shù)據(jù)緩存(Data Cache)兩部分决乎。
我們的內(nèi)存雖然沒有按照功能拆分队询,但是在高速緩存層面進行了拆分,也就是拆分成指令緩存和數(shù)據(jù)緩存這樣的方式构诚,從硬件層面蚌斩,使得同一個時鐘下對于相同資源的競爭不再發(fā)生。
數(shù)據(jù)冒險
然而還有很多冒險問題范嘱,是程序邏輯層面的事兒送膳。其中,最常見的就是數(shù)據(jù)冒險丑蛤。
數(shù)據(jù)冒險肠缨,其實就是同時在執(zhí)行的多個指令之間,有數(shù)據(jù)依賴的情況盏阶。這些數(shù)據(jù)依賴,我們可以分成三大類:
- 先寫后讀(Read After Write闻书,RAW)名斟,也叫數(shù)據(jù)依賴。
- 先讀后寫(Write After Read魄眉,WAR)砰盐,也叫反依賴。
- 寫后再寫(Write After Write坑律,WAW)岩梳,也較輸出依賴。
流水線停頓(Pipeline Stall)
也叫流水線冒泡(Pipeline Bubbling)晃择,在存在依賴的情況下冀值,讓流水線“再等等“。
這個存在依賴的情況宫屠,確切來講是:
我們在進行指令譯碼的時候列疗,會拿到對應(yīng)指令所需要訪問的寄存器和內(nèi)存地址。所以浪蹂,在這個時候抵栈,我們能夠判斷出來告材,這個指令是否會觸發(fā)數(shù)據(jù)冒險。
不過古劲,我們并不是讓流水線停下來斥赋,而是在執(zhí)行后面的操作步驟前面,插入一個 NOP 操作产艾,也就是執(zhí)行一個其實什么都不干的操作疤剑。
需要注意的是我們不僅要在當前指令里面,插入 NOP 操作胰舆,所有后續(xù)指令也要插入對應(yīng)的 NOP 操作骚露。
就像一路縱隊,前邊有人停下系鞋帶缚窿,后邊所有人都得原地踏步踏棘幸,不然就得踩著腦袋過去了。
不過倦零,流水線停頓這樣的解決方案误续,是以犧牲 CPU 性能為代價的。因為扫茅,實際上在最差的情況下晌纫,我們的流水線架構(gòu)的 CPU壁涎,又會退化成單指令周期的 CPU 了。
操作數(shù)前推(Operand Forwarding)
也較操作數(shù)旁路,更合適的名字應(yīng)該叫操作數(shù)轉(zhuǎn)發(fā)撼泛。當
后一個操作S2
的執(zhí)行依賴前一個操作S1
的執(zhí)行結(jié)果,此時直接將S1的結(jié)果
數(shù)據(jù)傳輸給S2的ALU
進行處理愁憔。
- 當只用流水線冒泡進行處理時:
我們的第 2 條指令抹锄,其實多花了 2 個時鐘周期,運行了兩次空轉(zhuǎn)的 NOP 操作糟描。
- 操作數(shù)前推進行處理時:
它越過(Bypass)了寫入寄存器怀喉,再從寄存器讀出的過程,也為我們節(jié)省了 2 個時鐘周期船响。
轉(zhuǎn)發(fā)(Forwarding)躬拢,其實是這個技術(shù)的邏輯含義。
旁路(Bypassing)见间,則是這個技術(shù)的硬件含義聊闯。為了能夠?qū)崿F(xiàn)這里的“轉(zhuǎn)發(fā)”,我們在 CPU 的硬件里面米诉,需要再單獨拉一根信號傳輸?shù)木€路出來馅袁,使得 ALU 的計算結(jié)果,能夠重新回到 ALU 的輸入里來荒辕。這樣的一條線路汗销,就是我們的“旁路”。
- 操作數(shù)前推+流水線冒泡進行處理時:
有的時候弛针,雖然我們可以把操作數(shù)轉(zhuǎn)發(fā)到下一條指令,但是下一條指令仍然需要停頓一個時鐘周期削茁。
有些時候慰丛,我們的操作數(shù)前推并不能減少所有“冒泡”瘾杭,只能去掉其中的一部分粥烁。我們?nèi)匀恍枰ㄟ^插入一些“氣泡”來解決冒險問題贤笆。
亂序執(zhí)行
不以編譯的代碼順序為
指令執(zhí)行階段
的順序,通過一個類似線程池的保留站讨阻,在保證不破壞數(shù)據(jù)依賴
的前提下讓系統(tǒng)自己去動態(tài)調(diào)度
先執(zhí)行哪些指令芥永。彌補了 CPU 和內(nèi)存之間的性能差異,可以充分利用 CPU 的性能钝吮。
以下這個例子:
a = b + c
d = a * e
x = y * z
第三步計算其實完全不依賴前兩步埋涧,但是卻要在流水線中等待前兩步執(zhí)行完成。
其實我們完全可以將第三步提前執(zhí)行奇瘦。所以在第二條指令等待第一條指令的訪存和寫回階段的時候飞袋,第三條指令就已經(jīng)執(zhí)行完成了。
-
內(nèi)亂外序
指令不再是順序執(zhí)行的链患,而是根據(jù)池里所擁有的資源,以及各個任務(wù)是否可以進行執(zhí)行瓶您,進行動態(tài)調(diào)度麻捻。在執(zhí)行完成之后,又重新把結(jié)果在一個隊列里面呀袱,按照指令的分發(fā)順序重新排序贸毕。即使內(nèi)部是“亂序”的,但是在外部看起來夜赵,仍然是井井有條地順序執(zhí)行明棍。
在亂序執(zhí)行的情況下,只有 CPU 內(nèi)部指令的執(zhí)行層面寇僧,可能是“亂序”的摊腋。只要我們能在指令的譯碼階段正確地分析出指令之間的數(shù)據(jù)依賴關(guān)系沸版,這個“亂序”就只會在互相沒有影響的指令之間發(fā)生。
即便指令的執(zhí)行過程中是亂序的兴蒸,我們在最終指令的計算結(jié)果寫入到寄存器和內(nèi)存之前视粮,依然會進行一次排序,以確保所有指令在外部看來仍然是有序完成的橙凳。
控制冒險
對于if…else 這樣的條件分支蕾殴,或者 for/while 循環(huán),指令無法順序執(zhí)行岛啸。為了確保能取到正確的指令钓觉,之后的取指令和指令譯碼就會被打斷,等待之前的判斷邏輯來決定后面要執(zhí)行的指令坚踩。
縮短分支延遲
本質(zhì)上和前面數(shù)據(jù)冒險的操作數(shù)前推的解決方案類似荡灾,就是在硬件電路層面,把一些計算結(jié)果更早地反饋到流水線中堕虹。這樣反饋變得更快了卧晓,后面的指令需要等待的時間就變短了。
我們可以將條件判斷赴捞、地址跳轉(zhuǎn)逼裆,都提前到指令譯碼階段進行
,而不需要放在指令執(zhí)行階段赦政。
對應(yīng)的胜宇,我們也要在 CPU 里面設(shè)計對應(yīng)的旁路,在指令譯碼階段恢着,就提供對應(yīng)的判斷比較的電路桐愉。
不過,他仍然不夠快:
在流水線里掰派,第一條指令進行指令譯碼的時鐘周期里
从诲,我們其實就要去取下一條指令了。這個時候靡羡,我們其實還沒有開始指令執(zhí)行階段系洛,自然也就不知道比較的結(jié)果。
靜態(tài)分支預(yù)測
最簡單的分支預(yù)測技術(shù)略步,叫作“假裝分支不發(fā)生”描扯。
顧名思義,自然就是仍然按照順序趟薄,把指令往下執(zhí)行绽诚。
如果分支預(yù)測是正確的
我們節(jié)省下來本來需要停頓下來等待的時間如果分支預(yù)測失敗了
那我們就把后面已經(jīng)取出指令已經(jīng)執(zhí)行的部分,給丟棄掉。
這個丟棄的操作恩够,在流水線里面卒落,叫作 Zap 或者 Flush。
CPU 不僅要執(zhí)行后面的指令玫鸟,對于這些已經(jīng)在流水線里面執(zhí)行到一半的指令导绷,我們還需要做對應(yīng)的清除操作。
比如屎飘,清空已經(jīng)使用的寄存器里面的數(shù)據(jù)等等妥曲,這些清除操作,也有一定的開銷钦购。
所以檐盟,CPU 需要提供對應(yīng)的丟棄指令的功能,通過控制信號清除掉已經(jīng)在流水線中執(zhí)行的指令押桃。
只要對應(yīng)的清除開銷不要太大葵萎,我們就是劃得來的。
動態(tài)分支預(yù)測
根據(jù)之前條件跳轉(zhuǎn)的比較結(jié)果來預(yù)測下一次比較結(jié)果唱凯。
-
一級分支預(yù)測(One Level Branch Prediction)
也叫 1 比特飽和計數(shù)(1-bit saturating counter)羡忘。
用一個比特,記錄當前分支的比較情況磕昼,直接用當前分支的比較情況卷雕,來預(yù)測下一次分支時候的比較情況。
如果前一天下雨票从,那么今天就會下雨:
這個表格里一共有 31 天漫雕,那我們就可以預(yù)測 30 次。你可以數(shù)一數(shù)峰鄙,按照這種預(yù)測方式浸间,我們可以預(yù)測正確 23 次,正確率是 76.7%吟榴,比隨機預(yù)測的 50% 要好上不少魁蒜。
-
雙模態(tài)預(yù)測器(Bimodal Predictor)
也叫2 比特飽和計數(shù)。
在一級分支預(yù)測的基礎(chǔ)上吩翻,用多個前置狀態(tài)兜看,預(yù)測當前的分支》乱埃可以通過引入一個狀態(tài)機來達到目的。
連續(xù)發(fā)生兩次相同狀態(tài)她君,才改變狀態(tài)機的狀態(tài):
預(yù)測的結(jié)果的正確率會是 22 次脚作,也就是 73.3% 的正確率。
這個方法雖然簡單,但是卻非常有效球涛。在 SPEC 89 版本的測試當中劣针,使用這樣的飽和計數(shù)方法,預(yù)測的準確率能夠高達 93.5%亿扁。
Intel 的 CPU捺典,一直到 Pentium 時代,在還沒有使用 MMX 指令集的時候从祝,用的就是這種分支預(yù)測方式襟己。
-
for循環(huán)中的預(yù)測冒險
Time spent in first loop is 5ms
Time spent in second loop is 15ms
其他提升CPU性能的技術(shù)
超標量
正常的流水線情況下,我們只能讓CPU在指令執(zhí)行階段可以并行處理牍陌。但是一個時鐘周期內(nèi)擎浴,也只能讀取一條指令。
超標量技術(shù)毒涧,通過添加硬件一次讀取多條指令的方式贮预,讓CPU的IPC(一個時鐘周期里面能夠執(zhí)行的指令數(shù),代表CPU的吞吐率)超過了1契讲。
-
多發(fā)射
我們同一個時間仿吞,可能會同時把多條指令發(fā)射(Issue)到不同的譯碼器或者后續(xù)處理的流水線中去。
-
超標量
本來我們在一個時鐘周期里面捡偏,只能執(zhí)行一個標量(Scalar)的運算唤冈。在多發(fā)射的情況下,我們就能夠超越這個限制霹琼,同時進行多次計算务傲。
超線程
是一個“線程級并行”的解決方案。它通過讓一個物理 CPU 核心枣申,“裝作”兩個邏輯層面的 CPU 核心售葡,使得 CPU 可以同時運行兩個不同線程的指令
超線程技術(shù)一般也被叫作同時多線程(Simultaneous Multi-Threading,簡稱 SMT)技術(shù)忠藤。
在一個物理 CPU 核心內(nèi)部挟伙,會有雙份的 PC 寄存器、指令寄存器乃至條件碼寄存器模孩。
我們并沒有增加真的功能單元尖阔。所以超線程只在特定的應(yīng)用場景下效果比較好。
一般是在那些各個線程“等待”時間比較長的應(yīng)用場景下榨咐。
比如介却,我們需要應(yīng)對很多請求的數(shù)據(jù)庫應(yīng)用,就很適合使用超線程块茁。各個指令都要等待訪問內(nèi)存數(shù)據(jù)齿坷,但是并不需要做太多計算桂肌。
SIMD(Single Instruction Multiple Data)單指令多數(shù)據(jù)流
一種“指令級并行”的加速方案,或者我們可以說永淌,它是一種“數(shù)據(jù)并行”的加速方案崎场。
對于那些在計算層面存在大量“數(shù)據(jù)并行”(Data Parallelism)的計算中,使用 SIMD 是一個很劃算的辦法遂蛀。在這個大量的“數(shù)據(jù)并行”谭跨,其實通常就是實踐當中的向量運算或者矩陣運算。
在實際的程序開發(fā)過程中李滴,過去通常是在進行圖片螃宙、視頻、音頻的處理悬嗓。最近幾年則通常是在進行各種機器學習算法的計算污呼。
正是 SIMD 技術(shù)的出現(xiàn),使得我們在 Pentium 時代的個人 PC包竹,開始有了多媒體運算的能力燕酷。可以說周瞎,Intel 的 MMX苗缩、SSE 指令集,和微軟的 Windows 95 這樣的圖形界面操作系統(tǒng)声诸,推動了 PC 快速進入家庭的歷史進程酱讶。
-
并行讀取
Intel 在引入 SSE 指令集的時候,在 CPU 里面添上了 8 個 128 Bits 的寄存器彼乌。128 Bits 也就是 16 Bytes 泻肯,也就是說,一個寄存器一次性可以加載 4 個整數(shù)慰照。
-
并行計算
4 個整數(shù)各自加 1灶挟,互相之前完全沒有依賴,也就沒有冒險問題需要處理毒租。只要 CPU 里有足夠多的功能單元稚铣,能夠同時進行這些計算,這個加法就是 4 路同時并行的墅垮,自然也省下了時間惕医。
手機CPU霸主--ARM
CISC--復(fù)雜指令集(Complex Instruction Set Computing)
使用類似赫夫曼編碼(Huffman coding)的方式,將機器指令進編碼算色。常用的指令要短一些抬伺,不常用的指令可以長一些。
雖然馮·諾依曼高屋建瓴地提出了存儲程序型計算機的基礎(chǔ)架構(gòu)灾梦,但是實際的計算機設(shè)計和制造還是嚴格受硬件層面的限制峡钓。當時的計算機很慢齐鲤,存儲空間也很小〗烽梗《人月神話》這本軟件工程界的名著,講的是花了好幾年設(shè)計 IBM 360 這臺計算機的經(jīng)驗牡肉。IBM 360 的最低配置捧灰,每秒只能運行 34500 條指令,只有 8K 的內(nèi)存统锤。為了讓計算機能夠做盡量多的工作毛俏,每一個字節(jié)乃至每一個比特都特別重要。
所以饲窿,CPU 指令集的設(shè)計煌寇,需要仔細考慮硬件限制。為了性能考慮逾雄,很多功能都直接通過硬件電路來完成阀溶。為了少用內(nèi)存,指令的長度也是可變的鸦泳。就像算法和數(shù)據(jù)結(jié)構(gòu)里的赫夫曼編碼(Huffman coding)一樣银锻,常用的指令要短一些,不常用的指令可以長一些做鹰。那個時候的計算機击纬,想要用盡可能少的內(nèi)存空間,存儲盡量多的指令钾麸。
RISC--精簡指令集(Reduced Instruction Set Computing)
把指令“精簡”到 20% 的簡單定長指令更振,讓軟件來實現(xiàn)復(fù)雜de硬件的功能。
CPU 的整個硬件設(shè)計就會變得更簡單了饭尝,在硬件層面提升性能也會變得更容易了:
-
更多的通用寄存器
因為 RISC 完成同樣的功能肯腕,執(zhí)行的指令數(shù)量要比 CISC 多,所以芋肠,如果需要反復(fù)從內(nèi)存里面讀取指令或者數(shù)據(jù)到寄存器里來乎芳,那么很多時間就會花在訪問內(nèi)存上。
-
更好的分支預(yù)測
RISC 的 CPU 也可以把更多的晶體管帖池,用來實現(xiàn)更好的分支預(yù)測等相關(guān)功能
-
RISC 降低了 CPU 硬件的設(shè)計和開發(fā)難度
從 80 年代開始奈惑,大部分新的 CPU 都開始采用 RISC 架構(gòu)。從 IBM 的 PowerPC睡汹,到 SUN 的 SPARC肴甸,都是 RISC 架構(gòu)
微指令架構(gòu)
從 Pentium Pro 時代開始,Intel 就開始在處理器里引入了微指令(Micro-Instructions/Micro-Ops)架構(gòu)囚巴。
讓 CISC 風格的指令集原在,在譯碼是翻譯成RISC風格友扰,用 RISC 的形式在RISC架構(gòu)的CPU 里面運行
-
將CISC指令,轉(zhuǎn)化成多條RISC的微指令執(zhí)行
在微指令架構(gòu)里庶柿,我們的指令譯碼器相當于變成了設(shè)計模式里的一個“適配器”(Adaptor)村怪。這個適配器,填平了 CISC 和 RISC 之間的指令差異浮庐。
-
用緩存甚负,替代譯碼器。提升性能
Intel 就在 CPU 里面加了一層 L0 Cache审残。這個 Cache 保存的就是指令譯碼器把 CISC 的指令“翻譯”成 RISC 的微指令的結(jié)果梭域。
于是,在大部分情況下搅轿,CPU 都可以從 Cache 里面拿到譯碼結(jié)果病涨,而不需要讓譯碼器去進行實際的譯碼操作。這樣不僅優(yōu)化了性能璧坟,因為譯碼器的晶體管開關(guān)動作變少了既穆,還減少了功耗。
使用“微指令”設(shè)計思路的 CPU雀鹃,不能再稱之為 CISC 了循衰,而更像一個 RISC 和 CISC 融合的產(chǎn)物。
ARM
ARM 這個名字現(xiàn)在的含義褐澎,是“Advanced RISC Machines”会钝。
你從名字就能夠看出來,ARM 的芯片是基于 RISC 架構(gòu)的
-
手機端ARM能夠戰(zhàn)勝Intel的原因
1. 功耗優(yōu)先
一個 4 核的 Intel i7 的 CPU工三,設(shè)計的時候功率就是 130W迁酸。
而一塊 ARM A8 的單個核心的 CPU,設(shè)計功率只有 2W俭正。兩者之間差出了 100 倍奸鬓。
在移動設(shè)備上,功耗是一個遠比性能更重要的指標掸读,畢竟我們不能隨時在身上帶個發(fā)電機串远。
ARM 的 CPU,主頻更低儿惫,晶體管更少澡罚,高速緩存更小,亂序執(zhí)行的能力更弱肾请。
所有這些留搔,都是為了功耗所做的妥協(xié)。
2. 低價
ARM 并沒有自己壟斷 CPU 的生產(chǎn)和制造铛铁,只是進行 CPU 設(shè)計隔显,然后把對應(yīng)的知識產(chǎn)權(quán)授權(quán)出去却妨,讓其他的廠商來生產(chǎn) ARM 架構(gòu)的 CPU。
它甚至還允許這些廠商可以基于 ARM 的架構(gòu)和指令集括眠,設(shè)計屬于自己的 CPU彪标。像蘋果、三星掷豺、華為捐下,它們都是拿到了基于 ARM 體系架構(gòu)設(shè)計和制造 CPU 的授權(quán)。ARM 自己只是收取對應(yīng)的專利授權(quán)費用萌业。多個廠商之間的競爭,使得 ARM 的芯片在市場上價格很便宜奸柬。
所以生年,盡管 ARM 的芯片的出貨量遠大于 Intel,但是收入和利潤卻比不上 Intel廓奕。
意在打造“CPU 屆的 Linux”的開源ARM架構(gòu)