計(jì)算機(jī)的基本硬件組成
早年领虹,要自己組裝一臺(tái)計(jì)算機(jī)规哪,要先有三大件求豫,CPU塌衰、內(nèi)存和主板诉稍。
在這三大件中,我們首先要說(shuō)的是CPU最疆,它是計(jì)算機(jī)最重要的核心配件杯巨,全名叫中央處理器(Central Processing Unit)。為什么說(shuō)CPU是"最重要"的呢努酸?因?yàn)橛?jì)算機(jī)的所有"計(jì)算"都是由CPU來(lái)進(jìn)行的服爷。自然,CPU也是整臺(tái)計(jì)算機(jī)中造價(jià)最昂貴的部份之一获诈。
第二個(gè)重要的配件仍源,就是內(nèi)存(Memory)。你撰寫的程序舔涎、打開(kāi)的瀏覽器笼踩、運(yùn)行的游戲,都要加載到內(nèi)存里才能運(yùn)行亡嫌。程序讀取的數(shù)據(jù)嚎于、計(jì)算得到的結(jié)果,也都要放在內(nèi)存里挟冠。內(nèi)存越大于购, 能加在的東西自然也就越多。
存放在內(nèi)存里的程序和數(shù)據(jù)知染,需要被CPU讀取肋僧,CPU計(jì)算完之后,還要把數(shù)據(jù)寫回到內(nèi)存持舆。然而CPU不能直接插到內(nèi)存上色瘩,反之亦然。于是逸寓,就帶來(lái)了最后一個(gè)大件----主板(Motherboard)居兆。
主板是一個(gè)有著各種各樣,有時(shí)候多達(dá)數(shù)十乃至上百個(gè)插槽的配件竹伸。我們的CPU要插在主板上泥栖,內(nèi)存也要插在主板上。主板的芯片組(Chipset)和總線(Bus)解決了CPU和內(nèi)存之間如何通信的問(wèn)題勋篓。芯片組控制了數(shù)據(jù)傳輸?shù)牧鬓D(zhuǎn)吧享,也就是數(shù)據(jù)從哪里到哪里的問(wèn)題∑┫總線則是實(shí)際數(shù)據(jù)傳輸?shù)母咚俟犯炙獭R虼恕?b>總線速度(Bus Speed)決定了數(shù)據(jù)能傳輸多快。
有了三大件拜银,只要配上電源供電殊鞭,計(jì)算機(jī)差不多就可以跑起來(lái)了遭垛。但是現(xiàn)在還缺少各類輸入(Input)/輸出(Output)設(shè)備,也就是我們常說(shuō)的I/O設(shè)備操灿。如果你用的是自己的個(gè)人電腦锯仪,那顯示器肯定必不可少,只有有了顯示器我們才能看到計(jì)算機(jī)輸出的各種圖像趾盐、文字庶喜,這也就是所謂的輸出設(shè)備。
同樣的救鲤,鼠標(biāo)和鍵盤也都是必不可少的配件久窟。
最后,你自己配的個(gè)人計(jì)算機(jī)本缠,還要配上一個(gè)硬盤瘸羡。這樣各種數(shù)據(jù)才能持久地保存下來(lái)。絕大部分人都會(huì)給自己的機(jī)器裝上一個(gè)機(jī)箱搓茬,配上風(fēng)扇犹赖,解決灰塵和散熱的問(wèn)題。不過(guò)機(jī)箱和風(fēng)扇卷仑,算不上計(jì)算機(jī)的必備硬件峻村。
還有一個(gè)很特殊的設(shè)備,就是顯卡(Graphics Card)∥現(xiàn)在粘昨,使用圖形界面操作系統(tǒng)的計(jì)算機(jī),無(wú)論是Windows窜锯、Mac OS還是Linux张肾,顯卡都是必不可少的。有人可能要說(shuō)了锚扎,我裝機(jī)的時(shí)候沒(méi)有買顯卡吞瞪,計(jì)算機(jī)一樣可以正常跑起來(lái)啊驾孔!那是因?yàn)樯指眩F(xiàn)在的主板都帶了內(nèi)置的顯卡。如果你用計(jì)算機(jī)玩游戲翠勉,做圖形渲染或者跑深度學(xué)習(xí)應(yīng)用妖啥,你多半就需要買一張單獨(dú)的顯卡,插在主板上对碌。顯卡之所以特殊荆虱,是因?yàn)轱@卡里有除了CPU之外的另一個(gè)"處理器",也就是GPU(Graphics Processing Unit,圖形處理器)怀读,GPU一樣可以做各種"計(jì)算"的工作酥郭。
鼠標(biāo)、鍵盤以及硬盤愿吹,這些都插在主板上的。作為外部I/O設(shè)備惜姐,它們通過(guò)主板上的南橋(SouthBridge)芯片組犁跪,來(lái)控制和CPU之間的通信。"南橋"芯片的名字很直觀歹袁,一方面坷衍,它在主板上的位置,通常在主板的"南面"条舔。另一方面枫耳,它的作用就是作為"橋",來(lái)連接鼠標(biāo)孟抗、鍵盤以及硬盤這些外部設(shè)備和CPU之間的通信迁杨。
有了南橋,自然對(duì)應(yīng)著也有"北橋"凄硼。是的铅协,以前的主板上通常也有"北橋"芯片,用來(lái)作為"橋"摊沉,連接CPU和內(nèi)存狐史、顯卡之間的通信。不過(guò)说墨,隨著時(shí)間的變遷骏全,現(xiàn)在的主板上的"北橋"芯片的工作,已經(jīng)被遷移到了CPU的內(nèi)部尼斧,所以你在主板上姜贡,已經(jīng)看不到北橋芯片了。
馮·諾伊曼體系結(jié)構(gòu)
剛才我們講了一臺(tái)計(jì)算機(jī)的硬件組成棺棵,這說(shuō)的是我們平時(shí)用的個(gè)人電腦或者服務(wù)器鲁豪。那我們平時(shí)最常用的智能手機(jī)的組成,也是這樣嗎律秃?
我們手機(jī)里只有SD卡(Secure Digiral Memory Card)這樣類似硬盤功能的存儲(chǔ)卡插槽爬橡,并沒(méi)有內(nèi)存插槽、CPU插槽這些東西棒动。沒(méi)錯(cuò)糙申,因?yàn)槭謾C(jī)尺寸的原因,手機(jī)制造商們選擇把CPU船惨、內(nèi)存柜裸、網(wǎng)絡(luò)通信缕陕,乃至攝像頭芯片,都封裝到一個(gè)芯片疙挺,然后再嵌入到手機(jī)主板上扛邑。這種方式叫SOC,也叫System on a Chip(系統(tǒng)芯片)铐然。
這樣看起來(lái)蔬崩,個(gè)人電腦和智能手機(jī)的硬件組成方式不太一樣〔笫睿可是沥阳,我們寫智能手機(jī)上的App,和寫個(gè)人電腦的客戶端應(yīng)用似乎沒(méi)有什么差別自点,都是通過(guò)"高級(jí)語(yǔ)言"這樣的編程語(yǔ)言撰寫桐罕、編譯之后,一樣是把代碼和數(shù)據(jù)加載到內(nèi)存里來(lái)執(zhí)行桂敛。這是為什么呢功炮?因?yàn)椋瑹o(wú)論是個(gè)人電腦术唬、服務(wù)器死宣、智能手機(jī),還是Raspberry Pi這樣的微型卡片機(jī)碴开,都遵循著同一個(gè)"計(jì)算機(jī)"的抽象概念毅该。這是怎么樣一個(gè)"計(jì)算機(jī)"呢?這其實(shí)就是潦牛,計(jì)算機(jī)祖師爺之一馮·諾伊曼體系結(jié)構(gòu)(Von Neumann architecture)眶掌,也叫存儲(chǔ)程序計(jì)算機(jī)。
什么是存儲(chǔ)程序計(jì)算機(jī)呢巴碗?這里面其實(shí)暗含了兩個(gè)概念朴爬,一個(gè)是"可編程"計(jì)算機(jī),一個(gè)是"存儲(chǔ)"計(jì)算機(jī)橡淆。
說(shuō)到"可編程"召噩,估計(jì)你會(huì)有點(diǎn)懵,你可以先想想逸爵,什么是"不可編程"具滴。計(jì)算機(jī)是由各種門電路組合而成的,然后通過(guò)組裝出一個(gè)固定的電路板师倔,來(lái)完成一個(gè)特定的計(jì)算程序构韵。一旦需要修改功能,就要重新組裝電路。這樣的話疲恢,計(jì)算機(jī)就是"不可編程"的凶朗,因?yàn)槌绦蛟谟?jì)算機(jī)硬件層面是"寫死"的。最常見(jiàn)的就是老式計(jì)算器显拳,電路板設(shè)計(jì)好了加減乘除棚愤,做不了任何計(jì)算邏輯固定之外的事情。
我們?cè)賮?lái)看"存儲(chǔ)"計(jì)算機(jī)杂数。這其實(shí)是說(shuō)宛畦,程序本身是存儲(chǔ)在計(jì)算機(jī)內(nèi)存里,可以通過(guò)加載不同的程序來(lái)解決不同的問(wèn)題耍休。有"存儲(chǔ)程序計(jì)算機(jī)",自然也有不能存儲(chǔ)程序的計(jì)算機(jī)货矮。典型的就是早年的"Plugboard"這樣的插線板式的計(jì)算機(jī)羊精。整個(gè)計(jì)算機(jī)就是一個(gè)巨大的插線板,通過(guò)在板子上不同的插頭后者接口的位置插入線路囚玫,來(lái)實(shí)現(xiàn)不同的功能喧锦。這樣的計(jì)算機(jī)自然是"可編程"的,但是編寫好的程序不能存儲(chǔ)下來(lái)供下一個(gè)加載使用抓督,不得不每次要用到和當(dāng)前不同的"程序"的時(shí)候燃少,重新插板子,重新"編程"铃在。
可以看到阵具,無(wú)論是"不可編程"還是"不可存儲(chǔ)",都會(huì)讓使用計(jì)算機(jī)的效率大大下降定铜。而這個(gè)對(duì)于效率的追求阳液,也就是"存儲(chǔ)程序計(jì)算機(jī)"的由來(lái)。
于是我們的祖師爺揣炕,基于當(dāng)是在秘密開(kāi)發(fā)的EDVAC寫了一篇報(bào)告First Draft of a Report on the EDVAC帘皿,描述了他心目中的一臺(tái)計(jì)算機(jī)應(yīng)該長(zhǎng)什么樣。這篇報(bào)告在歷史上有個(gè)很特殊的簡(jiǎn)稱畸陡,叫First Draft鹰溜,翻譯成中文,其實(shí)就是《第一份草案》丁恭。這樣曹动,現(xiàn)代計(jì)算機(jī)的發(fā)展就從祖師爺寫的一份草案開(kāi)始了。
First Fraft里面說(shuō)了一臺(tái)計(jì)算機(jī)應(yīng)該有哪些組成牲览,我們一起來(lái)看看仁期。
首先是一個(gè)包含算術(shù)邏輯單元(Arithmetic Logic Unit,ALU)和處理器寄存器(Processor Register)的處理器單元(Processing Unit),用來(lái)完成各種算術(shù)和邏輯運(yùn)算跛蛋。因?yàn)樗軌蛲瓿筛鞣N數(shù)據(jù)的處理或者計(jì)算工作熬的,因此也有人把這個(gè)叫做數(shù)據(jù)通路(Datapath)或者運(yùn)算器。
然后是一個(gè)包含指令寄存器(Instruction Register)和 程序計(jì)數(shù)器(Program Counter)的控制器單元(Control Unit赊级, CU)押框,用來(lái)控制程序的流程,通常就是不同條件下的分支和跳轉(zhuǎn)理逊。在現(xiàn)在的計(jì)算機(jī)里橡伞,上面的算術(shù)邏輯單元和這里的控制器單元,共同組成了我們說(shuō)的CPU晋被。
接著是用來(lái)存儲(chǔ)數(shù)據(jù)(Data)和指令(Instruction)的內(nèi)存兑徘。以及更大容量的外部存儲(chǔ),在過(guò)去羡洛,可能是磁帶挂脑、磁鼓這樣的設(shè)備,現(xiàn)在通常就是硬盤欲侮。
最后就是各種輸入和輸出設(shè)備崭闲,以及對(duì)應(yīng)的輸入輸出機(jī)制。我們現(xiàn)在無(wú)論是使用什么樣的計(jì)算機(jī)威蕉,其實(shí)都是和輸入輸出設(shè)備在打交道刁俭。個(gè)人電腦的鼠標(biāo)鍵盤是輸入設(shè)備,顯示器是輸出設(shè)備韧涨。我們用的智能手機(jī)牍戚,觸摸屏即是輸入設(shè)備,又是輸出設(shè)備虑粥。而跑在各種云上的服務(wù)器翘魄,則是通過(guò)網(wǎng)絡(luò)來(lái)進(jìn)行輸入和輸出。這個(gè)時(shí)候舀奶,網(wǎng)卡即是輸入設(shè)備又是輸出設(shè)備暑竟。
任何一臺(tái)計(jì)算機(jī)的任何一個(gè)部件都可以歸到運(yùn)算器、控制器育勺、存儲(chǔ)器但荤、輸入設(shè)備和輸出設(shè)備中,而所有現(xiàn)代計(jì)算機(jī)也是基于這個(gè)基礎(chǔ)架構(gòu)來(lái)設(shè)計(jì)開(kāi)發(fā)的涧至。
而所有的計(jì)算機(jī)程序腹躁,也都可以抽象為從輸入設(shè)備讀取輸入信息,通過(guò)運(yùn)算器和控制器來(lái)執(zhí)行存儲(chǔ)在存儲(chǔ)器里的程序南蓬,最終把結(jié)果輸出到輸出設(shè)備中纺非。而我們所有撰寫的無(wú)論高級(jí)還是低級(jí)語(yǔ)言哑了,也都是基于這樣一個(gè)抽象框架來(lái)進(jìn)行運(yùn)行的。
總結(jié)延伸
可以說(shuō)烧颖,馮·諾伊曼體系結(jié)構(gòu)確立了我們現(xiàn)在使用的計(jì)算機(jī)的基礎(chǔ)架構(gòu)弱左。因此,學(xué)習(xí)計(jì)算機(jī)組成原理炕淮,其實(shí)就是學(xué)習(xí)和拆解馮·諾伊曼體系結(jié)構(gòu)拆火。
具體來(lái)說(shuō),學(xué)習(xí)組成原理涂圆,其實(shí)就是學(xué)習(xí)控制器们镜、運(yùn)算器的工作原理,也就是CPU是怎么工作的润歉,以及為何這樣設(shè)計(jì)模狭;學(xué)習(xí)內(nèi)存的工作原理,從最基本的電路踩衩,到上層抽象給到CPU乃至應(yīng)用程序的結(jié)構(gòu)是怎樣的嚼鹉;學(xué)習(xí)CPU是怎么和輸入設(shè)備、輸出設(shè)備打交道的九妈。
學(xué)習(xí)組成原理反砌,就是在理解從控制器雾鬼、運(yùn)算器萌朱、存儲(chǔ)器、輸入設(shè)備和輸出設(shè)備策菜,從電路這樣的硬件晶疼,到最終開(kāi)放給軟件的接口,是怎么運(yùn)作的又憨,為什么要設(shè)計(jì)成這樣翠霍,以及在軟件開(kāi)發(fā)層面盡可能用好它。
在這圖中蠢莺,整個(gè)計(jì)算機(jī)組成原理拆分為四大部分寒匙,分別是計(jì)算機(jī)的基本組成、計(jì)算機(jī)的指令和計(jì)算躏将、處理器的設(shè)計(jì)以及存儲(chǔ)器和I/O設(shè)備锄弱。
“性能”這個(gè)詞,不管是在日常生活還是寫程序的時(shí)候祸憋,都經(jīng)常被提到会宪。比方說(shuō),買新電腦的時(shí)候蚯窥,我們會(huì)說(shuō)“原來(lái)的電腦性能跟不上了”掸鹅;寫程序的時(shí)候塞帐,我們會(huì)說(shuō),“這個(gè)程序性能需要優(yōu)化一下“巍沙。那么葵姥,”性能“到底指的是什么?
什么是性能赎瞎?時(shí)間的倒數(shù)
計(jì)算機(jī)的性能牌里,其實(shí)和我們干體力勞動(dòng)很像,好比是我們要搬東西务甥。對(duì)于計(jì)算機(jī)的性能牡辽,我們需要有個(gè)衡量標(biāo)準(zhǔn),這個(gè)標(biāo)準(zhǔn)主要有兩個(gè)指標(biāo)敞临。
第一個(gè)是響應(yīng)時(shí)間(Response time)或者叫執(zhí)行時(shí)間(Execution time)态辛。想要提升響應(yīng)時(shí)間這個(gè)性能指標(biāo),你可以理解為讓計(jì)算機(jī)”跑得更快“挺尿。
第二個(gè)是吞吐率(Throughput)或者帶寬(Bandwidth)奏黑,想要提升這個(gè)指標(biāo),你可以理解為讓計(jì)算機(jī)”搬得更多“编矾。
所以說(shuō)熟史,響應(yīng)時(shí)間指的就是,我們執(zhí)行一個(gè)程序窄俏,到底需要花多少時(shí)間蹂匹。花的時(shí)間越少凹蜈,自然性能就越好限寞。
而吞吐率就是指我們?cè)谝欢ǖ臅r(shí)間范圍內(nèi),到底能處理多少事情仰坦。這里的”事情“履植,在計(jì)算機(jī)里就是處理的數(shù)據(jù)或者執(zhí)行的程序指令。
和搬東西來(lái)做對(duì)比悄晃,如果我們的響應(yīng)時(shí)間短玫霎,跑得快,我們可以來(lái)回多跑幾趟多搬幾趟妈橄。所以說(shuō)庶近,縮短程序的響應(yīng)時(shí)間,一般來(lái)說(shuō)都會(huì)提升吞吐率眷细。
除了縮短響應(yīng)時(shí)間拦盹,我們還有別的方法嗎?當(dāng)然有溪椎,比如說(shuō)普舆,我們還可以找?guī)讉€(gè)人一起來(lái)搬恬口,這就類似現(xiàn)代的服務(wù)器都是8核、16核的沼侣。人多力量大祖能,同時(shí)處理數(shù)據(jù),在單位時(shí)間內(nèi)就可以處理更多數(shù)據(jù)蛾洛,吞吐率自然也就上去了养铸。
提升吞吐率的辦法有很多。大部分時(shí)候轧膘,我們只要多加一些機(jī)器钞螟,多堆一些硬件就好了。但是響應(yīng)時(shí)間的提升卻沒(méi)有那么容易谎碍,因?yàn)镃PU的性能提升其實(shí)在10年前就處于”擠牙膏“的狀態(tài)了鳞滨,所以我們得慎重地來(lái)分析對(duì)待。下面我們具體來(lái)看:
我們一般把性能蟆淀,定義為響應(yīng)時(shí)間的倒數(shù)拯啦,也就是
性能 = 1 / 響應(yīng)時(shí)間
這樣一來(lái),響應(yīng)時(shí)間越短熔任,性能的數(shù)值就越大褒链。同樣一個(gè)程序,在Inter最新的CPU Coffee Lake上疑苔,只需要30s就能運(yùn)行完成甫匹,而在5年前的CPU Sandy Bridge上,需要1min才能完成夯巷,那么我們自然可以算出來(lái)赛惩,Coffee Lake的性能1 / 30哀墓,Sandy Bridge的性能是1 / 60趁餐,兩個(gè)的性能比為2,于是篮绰,我們就說(shuō)后雷,Coffee Lake的性能是Sandy Bridge的2倍。
過(guò)去幾年流行的手機(jī)跑分軟件吠各,就是把多個(gè)預(yù)設(shè)好的程序在手機(jī)上運(yùn)行臀突,然后根據(jù)運(yùn)行需要的時(shí)間,算出一個(gè)分?jǐn)?shù)來(lái)給手機(jī)的性能評(píng)估贾漏。而在業(yè)界候学,各大CPU和服務(wù)器廠商組織了一個(gè)叫做SPEC的第三方機(jī)構(gòu),專門用來(lái)指定各種”跑分“的規(guī)則纵散。
計(jì)算機(jī)的計(jì)時(shí)單位:CPU時(shí)鐘
雖然時(shí)間是一個(gè)很自然的用來(lái)衡量性能的指標(biāo)梳码,但是用時(shí)間來(lái)衡量隐圾,有兩個(gè)問(wèn)題。
第一個(gè)是時(shí)間不”準(zhǔn)“掰茶。如果用你自己隨便寫的一個(gè)程序暇藏,來(lái)統(tǒng)計(jì)程序運(yùn)行時(shí)間,每一次統(tǒng)計(jì)結(jié)果不會(huì)完全一樣濒蒋。有可能這一次花了45ms盐碱,下一次變成了53ms。
為什么會(huì)不準(zhǔn)呢沪伙?這里面有好幾個(gè)原因瓮顽。首先,我們統(tǒng)計(jì)時(shí)間是用類似于”掐秒表“一樣围橡,記錄程序運(yùn)行結(jié)束的時(shí)間減去程序開(kāi)始運(yùn)行的時(shí)間趣倾。這個(gè)時(shí)間也叫Wall Clock Time或者Elapsed Time,就是在運(yùn)行程序期間某饰,掛在墻上的鐘走掉的時(shí)間儒恋。
但是,計(jì)算機(jī)可能同時(shí)運(yùn)行著好多程序黔漂,CPU實(shí)際上不停地在各個(gè)程序之間進(jìn)行切換诫尽。在這些走掉的時(shí)間里面,很可能CPU切換去運(yùn)行別的程序了炬守。而且牧嫉,有些程序運(yùn)行的時(shí)候,可能要從網(wǎng)絡(luò)减途、硬盤去讀取數(shù)據(jù)酣藻,要等網(wǎng)絡(luò)和硬盤把數(shù)據(jù)讀出來(lái),給到內(nèi)存和CPU鳍置。所以說(shuō)辽剧,要想準(zhǔn)確統(tǒng)計(jì)某個(gè)程序運(yùn)行時(shí)間,進(jìn)而去比較兩個(gè)程序的實(shí)際性能税产,我們得把這些時(shí)間給刨除掉怕轿。
那這件事怎么實(shí)現(xiàn)呢?Linux下有個(gè)叫time的命令辟拷,可以幫我們統(tǒng)計(jì)出來(lái)撞羽,同樣的Wall Clock Time下,程序?qū)嶋H在CPU上到底花了多少時(shí)間衫冻。
我們簡(jiǎn)單運(yùn)行一下time命令诀紊。它會(huì)返回三個(gè)值,第一個(gè)是real time隅俘,也就是我們說(shuō)的Wall Clock Time邻奠,也就是運(yùn)行程序整個(gè)過(guò)程中流逝掉的時(shí)間到推;第二個(gè)是user time,也就是CPU在運(yùn)行你的程序惕澎,在用戶態(tài)運(yùn)行指令的時(shí)間莉测;第三個(gè)是sys time,是CPU在運(yùn)行你的程序唧喉,在操作系統(tǒng)內(nèi)核里運(yùn)行指令的時(shí)間捣卤。而程序?qū)嶋H花費(fèi)的CPU執(zhí)行時(shí)間(CPU Time),就是user time + sys time
?```
timeseq1000000|wc-l
1000000?
real? 0m0.101s
user? 0m0.031s
sys ? 0m0.016s
```
在這個(gè)例子里八孝,可以看到董朝,實(shí)際上程序用了0.101s,但是CPU time只有0.031s + 0.014s = 0.047s干跛。運(yùn)行程序的時(shí)間里子姜,只有不到一半是實(shí)際花在這個(gè)程序上的庶骄。
其次假瞬,即使我們已經(jīng)拿到了CPU時(shí)間,我們也不一定可以直接”比較“出兩個(gè)程序的性能差異构回。即使在同一臺(tái)計(jì)算機(jī)上嘉熊,CPU可能滿載運(yùn)行也可能降頻運(yùn)行遥赚,降頻運(yùn)行的時(shí)候自然話的時(shí)間會(huì)多一些。
除了CPU之外阐肤,時(shí)間這個(gè)性能指標(biāo)還會(huì)收到主板凫佛、內(nèi)存這些其他相關(guān)硬件的影響。所以孕惜,我們需要對(duì)”時(shí)間”這個(gè)我們可以感知的指標(biāo)進(jìn)行拆解愧薛,把程序的CPU執(zhí)行時(shí)間變成CPU時(shí)鐘周期數(shù)(CPU Cyles)和時(shí)鐘周期時(shí)間(Clock Cycle)的乘積。
程序的CPU執(zhí)行時(shí)間 = CPU時(shí)鐘周期數(shù) * 時(shí)鐘周期時(shí)間
我們先來(lái)理解一下什么是時(shí)鐘周期時(shí)間衫画。你在買電腦的時(shí)候毫炉,一定關(guān)注過(guò)CPU的主頻。比如我手頭的這臺(tái)電腦就是Inter Core-i7-7700HQ 2.8GHz碧磅,這里的2.8GHz就是電腦的主頻(Frequency/Clock Rate)碘箍。這個(gè)2.8GHz遵馆,我們可以先粗淺地認(rèn)為鲸郊,CPU在1s時(shí)間內(nèi),可以執(zhí)行的簡(jiǎn)單指令的數(shù)量是2.8G條货邓。
如果想要更準(zhǔn)確一點(diǎn)描述秆撮,這個(gè)2.8GHz就代表,我們CPU的一個(gè)“鐘表“能夠識(shí)別出來(lái)的最小時(shí)間間隔换况。就像我們掛在墻上的掛鐘职辨,都是”滴答滴答“一秒一秒地走盗蟆,所以通過(guò)墻上的掛鐘能夠識(shí)別出來(lái)的最小時(shí)間單位就是秒。
而在CPU內(nèi)部舒裤,和我們平時(shí)戴的石英表類似喳资,有一個(gè)叫晶體振蕩器(Oscillator Crystal)的東西,簡(jiǎn)稱晶振腾供。我們把晶振當(dāng)成CPU內(nèi)部的電子表來(lái)使用仆邓。晶振帶來(lái)的每一次”滴答“,就是時(shí)鐘周期時(shí)間伴鳖。
在這個(gè)2.8GHz的CPU上节值,這個(gè)時(shí)鐘周期時(shí)間,就是1 / 2.8G榜聂。我們的CPU搞疗,是按照這個(gè)”時(shí)鐘“提示的時(shí)間來(lái)進(jìn)行自己的操作。主頻越高须肆,意味著這個(gè)表走得越快匿乃,我們的CPU也就”被逼“著走的越快。
如果你自己組裝過(guò)臺(tái)式機(jī)的話豌汇,可能聽(tīng)說(shuō)過(guò)”超頻“這個(gè)概念扳埂,著說(shuō)的其實(shí)就相當(dāng)于把買回來(lái)的CPU內(nèi)部的鐘給調(diào)快了,于是CPU的計(jì)算跟著這個(gè)時(shí)鐘的節(jié)奏瘤礁,也就自然變快了阳懂。當(dāng)然這個(gè)快不是沒(méi)有代價(jià)的,CPU跑得越快柜思,散熱的壓力也就越大岩调。就和人一樣,超過(guò)生理極限赡盘,CPU就會(huì)崩潰号枕。
我們現(xiàn)在回到上面程序CPU執(zhí)行時(shí)間的公式。
程序的CPU執(zhí)行時(shí)間 = CPU時(shí)鐘周期數(shù) * 時(shí)鐘周期時(shí)間
最簡(jiǎn)單的提升性能方案陨享,自然縮短時(shí)鐘周期時(shí)間葱淳,也就是提升主頻。換句話說(shuō)抛姑,就是換一塊好一點(diǎn)的CPU赞厕。不過(guò),這個(gè)是我們軟件工程師控制不了的事情定硝,所以我們把目光挪到了乘法的另一個(gè)因子---CPU時(shí)鐘周期數(shù)上皿桑。如果能夠減少程序需要的CPU時(shí)鐘周期數(shù),一樣能夠提升程序性能。
對(duì)于CPU時(shí)鐘周期數(shù)诲侮,我們可以再做一個(gè)分解镀虐,把它變成”指令數(shù) * 每條指令的平均時(shí)鐘周期數(shù)(Cycles Per Instruction,簡(jiǎn)稱CPI)“沟绪。不同的指令需要的Cycles是不同的刮便,加法和乘法都對(duì)應(yīng)一條CPU指令,但是乘法需要的Cycles就比加法要多绽慈,自然也就慢诺核。在這樣拆分之后,我們的程序CPU執(zhí)行時(shí)間就可以變成這樣三個(gè)部分的乘積久信。
程序的CPU執(zhí)行時(shí)間 = 指令數(shù) * CPI * Clock Cycle Time
因此窖杀,如果我們想要解決性能問(wèn)題,其實(shí)就是要優(yōu)化這三者裙士。
1.時(shí)鐘周期時(shí)間入客,就是計(jì)算機(jī)的主頻,這個(gè)取決于計(jì)算機(jī)硬件腿椎。我們所熟知的摩爾定律就一直在不停地提高我們計(jì)算機(jī)的主頻桌硫。比如說(shuō),最早的80386主頻只有33MHz啃炸,現(xiàn)在手頭的筆記本電腦就是2.8GHz铆隘,在主頻層面,就提升了將近100倍南用。
2.每條指令的平均時(shí)鐘周期數(shù)CPI膀钠,就是一條指令到底需要多少CPU Cycle。在后面講解CPU結(jié)構(gòu)的時(shí)候裹虫,我們會(huì)看到肿嘲,現(xiàn)代的CPU通過(guò)流水線技術(shù)(Pipeline),讓一條指令需要的CPU Cycle盡可能的少筑公。因此雳窟,對(duì)于CPI的優(yōu)化,也是計(jì)算機(jī)組成和體系結(jié)構(gòu)中重要一環(huán)匣屡。
3.指令數(shù)封救,代表執(zhí)行我們程序到底需要多少條指令、用哪些指令捣作。這個(gè)很多時(shí)候就把挑戰(zhàn)給了編譯器誉结。同樣的代碼,編譯成計(jì)算機(jī)指令的時(shí)候虾宇,就有各種不同的表示方式搓彻。
我們可以把自己想象成一個(gè)CPU如绸,坐在那里寫程序嘱朽。計(jì)算機(jī)主頻就好像是你的打字速度旭贬,打字越快,你自然可以多寫一點(diǎn)程序搪泳。CPI相當(dāng)于你在寫程序的時(shí)候稀轨,熟悉各種快捷鍵,越是打相同的內(nèi)容岸军,需要敲擊鍵盤的次數(shù)就越少奋刽。指令數(shù)相當(dāng)于你的程序設(shè)計(jì)得夠合理,同樣的程序要寫的代碼行數(shù)就少艰赞。如果三者皆能實(shí)現(xiàn)佣谐,你自然可以很快地寫出一個(gè)優(yōu)秀的程序,你的”性能“從外面來(lái)看就是好的方妖。
在上一講狭魂,提到了這樣一個(gè)公式:程序的CPU執(zhí)行時(shí)間 = 指令數(shù) * CPI * Clock Cycle Time這么看來(lái),如果要提升計(jì)算機(jī)的性能党觅,我們可以從指令數(shù)雌澄、CPI以及CPU主頻這三個(gè)地方入手。要搞定指令數(shù)或者CPI杯瞻,乍一看都不太容易镐牺。于是,研發(fā)CPU的硬件工程師們魁莉,從80年代開(kāi)始睬涧,就挑上了CPU這個(gè)“軟柿子”。在CPU上多放一點(diǎn)晶體管旗唁,不斷提升CPU的時(shí)鐘頻率宙地,這樣就能讓CPU變得更快,程序的執(zhí)行時(shí)間就會(huì)縮短逆皮。于是宅粥,從1978年Intel發(fā)布的8086CPU開(kāi)始,計(jì)算機(jī)的主頻從5MHz開(kāi)始电谣,不斷提升秽梅。1980年代中期的80386能夠跑到40MHz,1989年的486能夠跑到100MHz剿牺,直到2000年的奔騰4處理器企垦,主頻已經(jīng)到達(dá)了1.4GHz。而消費(fèi)者也在這20年里養(yǎng)成了“看主頻”買電腦的習(xí)慣晒来。當(dāng)時(shí)已經(jīng)基本壟斷了桌面CPU市場(chǎng)的Intel更是夸下了撼睿口,表示奔騰4所使用的CPU結(jié)構(gòu)可以做到10GHz,頗有“大力出奇跡”的意思荧降。功耗:CPU的“人體極限”然而接箫,計(jì)算機(jī)科學(xué)界從來(lái)不相信“大力出奇跡”。奔騰4的CPU主頻從來(lái)沒(méi)有達(dá)到過(guò)10GHz朵诫,最終它的主頻上限定格在3.8GHz辛友。這還不是最糟的,更糟糕的事情是剪返,大家發(fā)現(xiàn)废累,奔騰4的主頻雖然高,但是它的實(shí)際性能卻配不上同樣的主頻脱盲。想要用在筆記本上的奔騰4 2.4GHz處理器邑滨,其性能之和基于奔騰3架構(gòu)的奔騰M 1.6GHz處理器差不多。于是钱反,這一次的“大力出悲劇”掖看,不僅讓Intel的對(duì)手AMD獲得了喘息之機(jī),更是代表著“主頻時(shí)代”的終結(jié)诈铛。后面幾代Intel CPU主頻不但沒(méi)有上升乙各,反而下降了。到如今幢竹,2019年的最高配置Intel i9 CPU耳峦,主頻也之不過(guò)是5GHz而已。相較于1978年到2000年焕毫,這20年里300倍的主頻提升蹲坷,從2000年到現(xiàn)在的這19年,CPU的主頻大概提高了3倍邑飒。
奔騰4的主頻為什么沒(méi)能超過(guò)3.8GHz的障礙呢循签?答案就是功耗問(wèn)題。什么功耗問(wèn)題呢疙咸?我們先看一個(gè)直觀的例子县匠。
一個(gè)3.8GHz的奔騰4處理器,滿載功率是130瓦撒轮。這個(gè)130瓦是什么概念呢乞旦?機(jī)場(chǎng)允許帶上飛機(jī)的充電寶的容量上限是100瓦。如果我們把這個(gè)CPU安在手機(jī)里面题山,不考慮屏幕內(nèi)存之類的耗電兰粉,這個(gè)CPU滿載運(yùn)行45分鐘,充電寶里面就沒(méi)電了顶瞳。而iphone x使用ARM架構(gòu)的CPU玖姑,功率則只有4.5瓦左右愕秫。
我們的CPU,一般都被叫做超大規(guī)模集成電路(Very-Large-Scale Intergration焰络,VLSI)戴甩。這些電路,實(shí)際上都是一個(gè)個(gè)晶體管組合而成的舔琅。CPU在計(jì)算等恐,其實(shí)就是讓晶體管里面的“開(kāi)關(guān)”不斷地去“打開(kāi)”和“關(guān)閉”洲劣,來(lái)組合完成各種運(yùn)算和功能备蚓。
想要計(jì)算得快,一方面囱稽,我們要在CPU里郊尝,同樣的面積里面,多放一些晶體管战惊,也就是增加密度流昏;另一方面,我們要讓晶體管“打開(kāi)”和“關(guān)閉”得更快一點(diǎn)吞获,也就是提升主頻。而這兩者刁绒,都會(huì)增加功耗,帶來(lái)耗電和散熱的問(wèn)題烤黍。
這么說(shuō)知市,可能還是有點(diǎn)抽象跟啤,我還是舉一個(gè)例子唉锌。你可以把一個(gè)計(jì)算機(jī)CPU想象成一個(gè)巨大的工廠隅肥,里面有很多工人糊秆,相當(dāng)于CPU上面的晶體管武福,互相之間協(xié)同工作。
為了工作得快一點(diǎn)痘番,我們要在工廠里多塞一點(diǎn)人捉片。你可能會(huì)問(wèn)平痰,為什么不把工廠造得大一點(diǎn)呢?這時(shí)因?yàn)槲槿遥撕腿酥g如果離得遠(yuǎn)了宗雇,互相之間走過(guò)去需要花費(fèi)的時(shí)間就變長(zhǎng),這也會(huì)導(dǎo)致性能的下降莹规。這就好像如果CPU的面積大赔蒲,晶體管之間的距離變大,電信號(hào)傳輸?shù)臅r(shí)間就會(huì)邊長(zhǎng)良漱,運(yùn)算速度自然就慢了舞虱。
除了多塞一點(diǎn)人,我們還希望每個(gè)人的動(dòng)作都快一點(diǎn)母市,這樣同樣的時(shí)間里就可以多干一點(diǎn)活了矾兜。這就相當(dāng)于提升CPU的主頻,但是動(dòng)作快患久,每個(gè)人就要出汗散熱椅寺。要是太熱了,對(duì)工廠里面的人來(lái)說(shuō)就會(huì)中暑生病蒋失,對(duì)CPU來(lái)說(shuō)就會(huì)崩潰出錯(cuò)返帕。
我們會(huì)在CPU上面抹硅脂、裝電扇篙挽,乃至用上水冷或者其他更好的散熱設(shè)備荆萤,就好像在工廠里面裝風(fēng)扇、空調(diào)嫉髓,發(fā)冷飲一樣观腊。但是同樣的空間下算行,裝上風(fēng)扇空調(diào)能夠帶來(lái)的散熱效果也是有極限的梧油。
因此,在CPU里面州邢,能夠放下的晶體管數(shù)量和晶體管的“開(kāi)關(guān)”頻率也都是有限的儡陨。一個(gè)CPU的功率,可以用這樣一個(gè)公式來(lái)表示:
功耗 ~= 1 / 2 * 負(fù)載電容 * 電壓的平方 * 開(kāi)關(guān)頻率 * 晶體管數(shù)量
那么量淌,為了要提高性能骗村,我們需要不斷地增加晶體管的數(shù)量。同樣的面積下呀枢,我們想要多放一點(diǎn)晶體管胚股,就要把晶體管造得小一點(diǎn)。這個(gè)就是平時(shí)我們所說(shuō)的提升“制程”裙秋。從28nm到7nm琅拌,相當(dāng)于晶體管本身變成了原來(lái)的1 / 4大小缨伊。這個(gè)就相當(dāng)于我們?cè)诠S里,同樣的活进宝,我們要找瘦小一點(diǎn)的工人刻坊,這樣一個(gè)工廠里面就可以多一些人。我們還要提升主頻党晋,讓開(kāi)關(guān)的頻率變快谭胚,也就是要找手腳更快的工人。
但是未玻,功耗增加太多灾而,就會(huì)導(dǎo)致CPU散熱跟不上,這時(shí)深胳,我們就需要降低電壓绰疤。這里有一點(diǎn)非常關(guān)鍵铜犬,在整個(gè)功耗的公式里面舞终,功耗和電壓的平方成正比。這意味著電壓下降到原來(lái)的1 / 5癣猾,整個(gè)的功耗會(huì)變成原來(lái)的1 / 25敛劝。
事實(shí)上,從5MHz主頻的8086到5GHz的Intel i9纷宇,CPU的電壓已經(jīng)從5V左右下降到1V左右夸盟。這也是為什么我們CPU的主頻提升了1000倍,但是功耗只增加了40倍像捶。
并行優(yōu)化上陕,理解阿姆達(dá)爾定律
雖然制程的優(yōu)化和電壓的下降,在過(guò)去的 20 年里拓春,讓我們的 CPU 性能有所提升释簿。但是從上世紀(jì)九十年代到本世紀(jì)初,軟件工程師們所用的“面向摩爾定律編程”的套路越來(lái)越用不下去了硼莽∈埽“寫程序不考慮性能,等明年 CPU 性能提升一倍懂鸵,到時(shí)候性能自然就不成問(wèn)題了”偏螺,這種想法已經(jīng)不可行了。于是匆光,從奔騰 4 開(kāi)始套像,Intel 意識(shí)到通過(guò)提升主頻比較“難”去實(shí)現(xiàn)性能提升,邊開(kāi)始推出 Core Duo 這樣的多核 CPU终息,通過(guò)提升“吞吐率”而不是“響應(yīng)時(shí)間”夺巩,來(lái)達(dá)到目的货葬。提升響應(yīng)時(shí)間,就好比提升你用的交通工具的速度劲够,比如原本你是開(kāi)汽車震桶,現(xiàn)在變成了火車乃至飛機(jī)。本來(lái)開(kāi)車從上海到北京要 20 個(gè)小時(shí)征绎,換成飛機(jī)就只要 2 個(gè)小時(shí)了蹲姐,但是,在此之上人柿,再想要提升速度就不太容易了柴墩。我們的 CPU 在奔騰 4 的年代,就好比已經(jīng)到了飛機(jī)這個(gè)速度極限凫岖。
那你可能要問(wèn)了江咳,接下來(lái)該怎么辦呢?相比于給飛機(jī)提速哥放,工程師們又想到了新的辦法歼指,可以一次同時(shí)開(kāi) 2 架、4 架乃至 8 架飛機(jī)甥雕,這就好像我們現(xiàn)在用的 2 核踩身、4 核,乃至 8 核的 CPU社露。雖然從上海到北京的時(shí)間沒(méi)有變挟阻,但是一次飛 8 架飛機(jī)能夠運(yùn)的東西自然就變多了,也就是所謂的“吞吐率”變大了峭弟。所以附鸽,不管你有沒(méi)有需要,現(xiàn)在 CPU 的性能就是提升了 2 倍乃至 8 倍瞒瘸、16 倍坷备。這也是一個(gè)最常見(jiàn)的提升性能的方式,通過(guò)并行提高性能挨务。這個(gè)思想在很多地方都可以使用击你。舉個(gè)例子,我們做機(jī)器學(xué)習(xí)程序的時(shí)候谎柄,需要計(jì)算向量的點(diǎn)積丁侄,比如向量 W=[W0,W1,W2,…,W15] 和向量 X=[X0,X1,X2,…,X15],W?X=W0?X0+W1?X1+ W2?X2+…+W15?X15朝巫。這些式子由 16 個(gè)乘法和 1 個(gè)連加組成鸿摇。如果你自己一個(gè)人用筆來(lái)算的話,需要一步一步算 16 次乘法和 15 次加法劈猿。如果這個(gè)時(shí)候我們把這個(gè)任務(wù)分配給 4 個(gè)人拙吉,同時(shí)去算 W0~W3, W4~W7, W8~W11, W12~W15 這樣四個(gè)部分的結(jié)果潮孽,再由一個(gè)人進(jìn)行匯總,需要的時(shí)間就會(huì)縮短筷黔。
但是往史,并不是所有問(wèn)題,都可以通過(guò)并行提高性能來(lái)解決佛舱。如果想要使用這種思想椎例,需要滿足這樣幾個(gè)條件。第一请祖,需要進(jìn)行的計(jì)算订歪,本身可以分解成幾個(gè)可以并行的任務(wù)。好比上面的乘法和加法計(jì)算肆捕,幾個(gè)人可以同時(shí)進(jìn)行刷晋,不會(huì)影響最后的結(jié)果。第二慎陵,需要能夠分解好問(wèn)題眼虱,并確保幾個(gè)人的結(jié)果能夠匯總到一起。第三荆姆,在“匯總”這個(gè)階段蒙幻,是沒(méi)有辦法并行進(jìn)行的,還是得順序執(zhí)行胆筒,一步一步來(lái)。這就引出了我們?cè)谶M(jìn)行性能優(yōu)化中诈豌,常常用到的一個(gè)經(jīng)驗(yàn)定律仆救,阿姆達(dá)爾定律(Amdahl’s Law)。這個(gè)定律說(shuō)的就是矫渔,對(duì)于一個(gè)程序進(jìn)行優(yōu)化之后彤蔽,處理器并行運(yùn)算之后效率提升的情況。具體可以用這樣一個(gè)公式來(lái)表示:優(yōu)化后的執(zhí)行時(shí)間 = 受優(yōu)化影響的執(zhí)行時(shí)間 / 加速倍數(shù) + 不受影響的執(zhí)行時(shí)間
在剛剛的向量點(diǎn)積例子里庙洼,4 個(gè)人同時(shí)計(jì)算向量的一小段點(diǎn)積顿痪,就是通過(guò)并行提高了這部分的計(jì)算性能。但是油够,這 4 個(gè)人的計(jì)算結(jié)果蚁袭,最終還是要在一個(gè)人那里進(jìn)行匯總相加。這部分匯總相加的時(shí)間石咬,是不能通過(guò)并行來(lái)優(yōu)化的揩悄,也就是上面的公式里面不受影響的執(zhí)行時(shí)間這一部分。比如上面的各個(gè)向量的一小段的點(diǎn)積鬼悠,需要 100ns删性,加法需要 20ns亏娜,總共需要 120ns。這里通過(guò)并行 4 個(gè) CPU 有了 4 倍的加速度蹬挺。那么最終優(yōu)化后维贺,就有了 100/4+20=45ns。即使我們?cè)黾痈嗟牟⑿卸葋?lái)提供加速倍數(shù)巴帮,比如有 100 個(gè) CPU幸缕,整個(gè)時(shí)間也需要 100/100+20=21ns。
總結(jié)延伸我們可以看到晰韵,無(wú)論是簡(jiǎn)單地通過(guò)提升主頻发乔,還是增加更多的 CPU 核心數(shù)量,通過(guò)并行來(lái)提升性能雪猪,都會(huì)遇到相應(yīng)的瓶頸栏尚。僅僅簡(jiǎn)單地通過(guò)“堆硬件”的方式,在今天已經(jīng)不能很好地滿足我們對(duì)于程序性能的期望了只恨。于是译仗,工程師們需要從其他方面開(kāi)始下功夫了。在“摩爾定律”和“并行計(jì)算”之外官觅,在整個(gè)計(jì)算機(jī)組成層面纵菌,還有這樣幾個(gè)原則性的性能提升方法。1.加速大概率事件休涤。最典型的就是咱圆,過(guò)去幾年流行的深度學(xué)習(xí),整個(gè)計(jì)算過(guò)程中功氨,99% 都是向量和矩陣計(jì)算序苏,于是,工程師們通過(guò)用 GPU 替代 CPU捷凄,大幅度提升了深度學(xué)習(xí)的模型訓(xùn)練過(guò)程忱详。本來(lái)一個(gè) CPU 需要跑幾小時(shí)甚至幾天的程序,GPU 只需要幾分鐘就好了跺涤。Google 更是不滿足于 GPU 的性能匈睁,進(jìn)一步地推出了 TPU。后面的文章桶错,我也會(huì)為你講解 GPU 和 TPU 的基本構(gòu)造和原理航唆。
2.通過(guò)流水線提高性能。現(xiàn)代的工廠里的生產(chǎn)線叫“流水線”牛曹。我們可以把裝配 iPhone 這樣的任務(wù)拆分成一個(gè)個(gè)細(xì)分的任務(wù)佛点,讓每個(gè)人都只需要處理一道工序,最大化整個(gè)工廠的生產(chǎn)效率。類似的超营,我們的 CPU 其實(shí)就是一個(gè)“運(yùn)算工廠”鸳玩。我們把 CPU 指令執(zhí)行的過(guò)程進(jìn)行拆分,細(xì)化運(yùn)行演闭,也是現(xiàn)代 CPU 在主頻沒(méi)有辦法提升那么多的情況下不跟,性能仍然可以得到提升的重要原因之一。我們?cè)诤竺嬉矔?huì)講到米碰,現(xiàn)代 CPU 里是如何通過(guò)流水線來(lái)提升性能的窝革,以及反面的,過(guò)長(zhǎng)的流水線會(huì)帶來(lái)什么新的功耗和效率上的負(fù)面影響吕座。3.通過(guò)預(yù)測(cè)提高性能虐译。通過(guò)預(yù)先猜測(cè)下一步該干什么,而不是等上一步運(yùn)行的結(jié)果吴趴,提前進(jìn)行運(yùn)算漆诽,也是讓程序跑得更快一點(diǎn)的辦法。典型的例子就是在一個(gè)循環(huán)訪問(wèn)數(shù)組的時(shí)候锣枝,憑經(jīng)驗(yàn)厢拭,你也會(huì)猜到下一步我們會(huì)訪問(wèn)數(shù)組的下一項(xiàng)。后面要講的“分支和冒險(xiǎn)”撇叁、“局部性原理”這些 CPU 和存儲(chǔ)系統(tǒng)設(shè)計(jì)方法供鸠,其實(shí)都是在利用我們對(duì)于未來(lái)的“預(yù)測(cè)”,提前進(jìn)行相應(yīng)的操作陨闹,來(lái)提升我們的程序性能楞捂。好了,到這里正林,我們講完了計(jì)算機(jī)組成原理這門課的“前情提要”泡一。一方面,整個(gè)組成乃至體系結(jié)構(gòu)觅廓,都是基于馮·諾依曼架構(gòu)組成的軟硬件一體的解決方案。另一方面涵但,你需要明白的就是杈绸,這里面的方方面面的設(shè)計(jì)和考慮,除了體系結(jié)構(gòu)層面的抽象和通用性之外矮瘟,核心需要考慮的是“性能”問(wèn)題瞳脓。