在上一篇中,我們談到過(guò)
程序的CPU執(zhí)行時(shí)間 = 指令數(shù)×CPI×Clock Cycle Time
要提升計(jì)算機(jī)的性能,可以從上面這三方面著手。
通過(guò)指令數(shù)/CPI,好像都太難了。
因此工程師們,就在CPU上多放晶體管,不斷提升CPU的時(shí)鐘頻率,讓CPU更快,程序的執(zhí)行時(shí)間就會(huì)縮短。
* 從1978年Intel發(fā)布的8086 CPU開(kāi)始,計(jì)算機(jī)的主頻從5MHz開(kāi)始,不斷攀升
* 1980年代中期的80386能夠跑到40MHz
* 1989年的486能夠跑到100MHz
* 直到2000年的奔騰4處理器,主頻已經(jīng)到達(dá)了1.4GHz
1 功耗:CPU的“人體極限”
奔騰4的CPU主頻從來(lái)沒(méi)有達(dá)到過(guò)10GHz,最終它的主頻上限定格在3.8GHz
<https://zh.wikipedia.org/wiki/%25E5%25A5%2594%25E8%2585%25BE4>
而且奔騰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 <https://zh.wikipedia.org/wiki/Intel_Core_i9>
,主頻也不過(guò)是5GHz
相較于1978年到2000年,這20年里300倍的主頻提升,從2000年到現(xiàn)在的這19年,CPU的主頻大概提高了3倍
* CPU的主頻變化,奔騰4時(shí)進(jìn)入瓶頸期
奔騰4的主頻為什么沒(méi)能超3.8GHz?
就因?yàn)楣?
一個(gè)3.8GHz的奔騰4處理器,滿載功率是130瓦
130瓦是什么概念呢?機(jī)場(chǎng)允許帶上飛機(jī)的充電寶的容量上限是100瓦時(shí)
如果我們把這個(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 Integration,VLSI
由一個(gè)個(gè)晶體管組成
CPU的計(jì)算過(guò)程,其實(shí)就是讓晶體管里面的“開(kāi)關(guān)”不斷“打開(kāi)”/“關(guān)閉”,組合完成各種運(yùn)算和功能。
要想算得快
* 增加密度
在CPU同樣的面積,多放晶體管
* 提升主頻
讓晶體管“打開(kāi)”/“關(guān)閉”得快點(diǎn)
這兩者,都會(huì)增加功耗,帶來(lái)耗電和散熱的問(wèn)題!!!
可以把CPU想象成一個(gè)工廠,有很多工人
就如CPU上面的晶體管,互相之間協(xié)同工作。
為了工作快點(diǎn)完成,在工廠里多塞一點(diǎn)人
你可能會(huì)問(wèn),為什么不把工廠造得大點(diǎn)?
這是因?yàn)椋撕腿酥g如果離得遠(yuǎn)了,互相之間走過(guò)去需要花的時(shí)間就會(huì)變長(zhǎng),這也會(huì)導(dǎo)致性能下降!
這就如如果CPU的面積大,晶體管之間的距離變大,電信號(hào)傳輸?shù)臅r(shí)間就會(huì)變長(zhǎng),運(yùn)算速度自然就慢了。
除了多塞一點(diǎn)人,還希望每個(gè)人動(dòng)作快點(diǎn),同樣時(shí)間就可多干活了
這就相當(dāng)于提升CPU主頻,但是動(dòng)作快,每個(gè)人就要出汗散熱
要是太熱了,對(duì)工廠里面的人來(lái)說(shuō)會(huì)休克,對(duì)CPU來(lái)說(shuō)就會(huì)崩潰出錯(cuò)。
我們會(huì)在CPU上面抹硅脂、裝風(fēng)扇,乃至用上水冷或者其他更好的散熱設(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)的頻率變快,也就是要找手腳更快的工人
但功耗增加過(guò)多,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倍,但是功耗只增長(zhǎng)了40倍
2 并行優(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ī)
但是,在此之上,再想要提升速度就不太容易了
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 = [W_0, W_1, W_2, …, W_{15}]$
和向量
$X = [X_0, X_1, X_2, …, X_{15}]$ $W·X = W_0 * X_0 + W_1 * X_1 +$ $W_2 * X_2 +
… + W_{15} * X_{15}$
這些式子由16個(gè)乘法和1個(gè)連加組成。如果你自己一個(gè)人用筆來(lái)算的話,需要一步一步算16次乘法和15次加法。
如果這個(gè)時(shí)候我們把這個(gè)人物分配給4個(gè)人,同時(shí)去算\(W_0~W\_3\), \(W\_4~W\_7\), \(W\_8~W_{11}\),
\(W_{12}~W_{15}\)這樣四個(gè)部分的結(jié)果,再由一個(gè)人進(jìn)行匯總,需要的時(shí)間就會(huì)縮短。
但并不是所有問(wèn)題,都可以通過(guò)并行提高性能來(lái)解決
要使用這種思想,需要滿足以下條件:
* 需要進(jìn)行的計(jì)算,本身可以分解成幾個(gè)可以并行的任務(wù)
好比上面的乘法和加法計(jì)算,幾個(gè)人可以同時(shí)進(jìn)行,不會(huì)影響最后的結(jié)果。
* 需要能夠分解好問(wèn)題,并確保幾個(gè)人的結(jié)果能夠匯總到一起
* 在“匯總”這個(gè)階段,是沒(méi)有辦法并行進(jìn)行的,還是得順序執(zhí)行,一步一步來(lái)。
這就引出了性能優(yōu)化中一個(gè)經(jīng)驗(yàn)定律
* 阿姆達(dá)爾定律(Amdahl’s Law)
對(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。
3 總結(jié)
無(wú)論是簡(jiǎn)單地通過(guò)提升主頻,還是增加更多的CPU核心數(shù)量,通過(guò)并行提升性能,都會(huì)遇到相應(yīng)的瓶頸
僅靠簡(jiǎn)單地通過(guò)“堆硬件”的方式,在今天已經(jīng)不能很好地滿足我們對(duì)于程序性能的期望了。
于是,工程師們需要從其他方面開(kāi)始下功夫了。
在“摩爾定律”和“并行計(jì)算”之外,在整個(gè)計(jì)算機(jī)組成層面,還有這樣幾個(gè)原則性的性能提升方法。
3.1 加速大概率事件
深度學(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
通常我們使用 O 表示一個(gè)算法的好壞,我們優(yōu)化一個(gè)算法也是基于 big-O
但是 big-O 其實(shí)是一個(gè)近似值,就好比一個(gè)算法時(shí)間復(fù)雜度是 O(n^2) + O(n)
這里的 O(n^2) 是占大比重的,特別是當(dāng) n 很大的時(shí)候,通常我們會(huì)忽略掉 O(n),著手優(yōu)化 O(n^2) 的部分
3.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)有辦法提升那么多的情況下,性能仍然可以得到提升的重要原因之一
3.3 通過(guò)預(yù)測(cè)提高性能
預(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)提升我們的程序性能。
深度優(yōu)先搜索算法里面的 “剪枝策略”,防止沒(méi)有必要的分支搜索,這會(huì)大幅度提升算法效率
* 整個(gè)組成乃至體系結(jié)構(gòu),都是基于馮·諾依曼架構(gòu)組成的軟硬件一體的解決方案
* 這里面的方方面面的設(shè)計(jì)和考慮,除了體系結(jié)構(gòu)層面的抽象和通用性之外,核心需要考慮的是“性能”問(wèn)題
參考
深入淺出計(jì)算機(jī)組成原理
X 交流學(xué)習(xí)
Java交流群 <https://jq.qq.com/?_wv=1027&k=5UB4P1T>
博客 <https://blog.csdn.net/qq_33589510>
Github <https://github.com/Wasabi1234>
熱門工具 換一換
