0 學習路線的知識點概括 學習電腦組成原理,就是學習電腦是如何協調運行的 電腦組成原理的英文叫Computer Organization Organization 意"組織機構"。 該組織機構能夠進行各種計算、控制、讀取輸入,進行輸出,達成各種強大的功能。 把整個電腦組成原理的知識點拆分成了 ...
0 學習路線的知識點概括
學習電腦組成原理,就是學習電腦是如何協調運行的
- 電腦組成原理的英文叫Computer Organization
Organization 意"組織機構"。
該組織機構能夠進行各種計算、控制、讀取輸入,進行輸出,達成各種強大的功能。
把整個電腦組成原理的知識點拆分成了四大部分
- 電腦的基本組成
- 電腦的指令和計算
- 處理器設計
- 存儲器和I/O設備。
0.1 電腦的基本組成
電腦的硬體組成
這些硬體,怎麼對應到經典的馮·諾依曼體繫結構的
除此之外,還需要瞭解電腦的兩個核心指標
- 性能
- 功耗
性能和功耗也是我們在應用和設計五大基本組件中需要重點考慮的因素。
0.2 電腦的指令和計算
需要搞明白,我們每天撰寫的一行行C、Java、PHP程式,是怎麼在電腦裡面跑起來的。
- 瞭解我們的程式是怎麼通過編譯器和彙編器,變成一條條機器指令這樣的編譯過程(編譯過程展開,就是編譯原理)
- 知道我們的操作系統是怎麼鏈接、裝載、執行這些程式的(深入學習,就是操作系統)。而這一條條指令執行的控制過程,就是由電腦五大組件之一的控制器來控制的。
計算部分,要從二進位和編碼開始,理解我們的數據在電腦里的表示,以及我們是怎麼從數字電路層面,實現加法、乘法這些基本的運算功能的。
實現這些運算功能的ALU(Arithmetic Logic Unit/ALU),算術邏輯單元,電腦五大組件之一的運算器。
特別重要的就是浮點數(Floating Point)。
浮點數是我們在日常運用中非常容易用錯的一種數據表示形式。掌握浮點數能讓你對數據的編碼、存儲和計算能夠有一個從表到里的深入理解。尤其在AI火熱的今天,浮點數是機器學習中重度使用的數據表示形式,掌握它更是非常有必要。
0.3 CPU的設計
CPU時鐘可以用來構造寄存器和記憶體的鎖存器和觸發器,因此,CPU時鐘應該是我們學習CPU的前導知識。搞明白我們為什麼需要CPU時鐘(CPU Clock),以及寄存器和記憶體是用什麼樣的硬體組成的之後,我們可以再來看看,整個電腦的數據通路是如何構造出來的。
數據通路,其實就是連接了整個運算器和控制器,並最終組成了CPU。而出於對於性能和功耗的考慮,你要進一步理解和掌握面向流水線設計的CPU、數據和控制冒險,以及分支預測的相關技術。
既然CPU作為控制器要和輸入輸出設備通信,那麼我們就要知道異常和中斷發生的機制。在CPU設計部分的最後,我會講一講指令的並行執行,看看如何直接在CPU層面,通過SIMD來支持並行計算。
0.4 存儲器的原理
通過存儲器的層次結構作為基礎的框架引導,需要掌握從上到下的CPU高速緩存、記憶體、SSD硬碟和機械硬碟的工作原理,它們之間的性能差異,以及實際應用中利用這些設備會遇到的挑戰。存儲器其實很多時候又扮演了輸入輸出設備的角色,所以你需要進一步瞭解,CPU和這些存儲器之間是如何進行通信的,以及我們最重視的性能問題是怎麼一回事;理解什麼是IO_WAIT,如何通過DMA來提升程式性能。
對於存儲器,我們不僅需要它們能夠正常工作,還要確保裡面的數據不能丟失。於是你要掌握我們是如何通過RAID、Erasure Code、ECC以及分散式HDFS,這些不同的技術,來確保數據的完整性和訪問性能。
電腦組成原理的學習辦法
相較於整個電腦科學中的其他科目,電腦組成原理更像是整個電腦學科里的“綱要”。這門課里任何一個知識點深入挖下去,都可以變成電腦科學里的一門核心課程。
- 程式怎樣從高級代碼變成指令在電腦裡面運行,對應著“編譯原理”和“操作系統”這兩門課程
- 計算實現背後則是“數字電路”
- 如果要深入CPU和存儲器系統的優化,必然要深入瞭解“電腦體繫結構”。
為了更快更好地學電腦組成,總結了三個學習方法
學會提問自己來串聯知識點
學完一個知識點之後,你可以從下麵兩個方面,問一下自己。
- 我寫的程式,是怎樣從輸入的代碼,變成運行的程式,並得到最終結果的?
- 整個過程中,計算器層面到底經歷了哪些步驟,有哪些地方是可以優化的?
無論是程式的編譯、鏈接、裝載和執行,以及計算時需要用到的邏輯電路、ALU,乃至CPU自發為你做的流水線、指令級並行和分支預測,還有對應訪問到的硬碟、記憶體,以及載入到高速緩存中的數據,這些都對應著我們學習中的一個個知識點。建議你自己腦子裡過一遍,最好時口頭表述一遍或者寫下來,這樣對你徹底掌握這些知識點都會非常有幫助。
寫一些示常式序來驗證知識點
電腦科學是一門實踐的學科。電腦組成中的大量原理和設計,都對應著“性能”這個詞。因此,通過把對應的知識點,變成一個個性能對比的示例代碼程式記錄下來,是把這些知識點融匯貫通的好方法。因為,相比於強記硬背知識點,一個有著明確性能對比的示常式序,會在你腦海裡留下更深刻的印象。當你想要回顧這些知識點的時候,一個程式也更容易提示你把它從腦海深處裡面找出來。
通過和電腦硬體發展的歷史做對照
電腦的發展並不是一蹴而就的。從第一臺電子電腦ENIAC(Electronic Numerical Integrator And Computer,電子數值積分電腦)的發明到現在,已經有70多年了。現代電腦用的各個技術,都是跟隨實際應用中遇到的挑戰,一個個發明、打磨,最後保留下來的。這當中不僅僅有學術層面的碰撞,更有大量商業層面的交鋒。通過瞭解充滿戲劇性和故事性的電腦硬體發展史,讓你更容易理解電腦組成中各種原理的由來。
比如說,奔騰4和SPARC的失敗,以及ARM的成功,能讓我們記住CPU指令集的繁與簡、權衡性能和功耗的重要性,而現今高速發展的機器學習和邊緣計算,又給電腦硬體設計帶來了新的挑戰。
學習資料推薦
最有效的辦法還是“讀書百遍,其義自見”。對於不夠明白的知識點,多搜索,多看不同來源的資料,多和朋友、同事、老師一起交流,一定能夠幫你掌握好想要學習的知識點。
入門書籍
- 《電腦是怎樣跑起來的》
- 《程式是怎樣跑起來的》(入門微縮版“電腦組成原理”)
- 電腦組成中,硬體層面的基礎實現,比如寄存器、ALU這些電路是怎麼回事Coursera上的北京大學免費公開課《Computer Organization》。
進階書籍
拓展閱讀
- 《程式員的自我修養:鏈接、裝載和庫》
理解電腦硬體和操作系統層面代碼執行的優秀閱讀材料
路線學習小結
學習不是死記硬背,學習材料也不是越多越好。
最有效的辦法,不是短時間衝刺,而是有節奏地堅持,多在留言區和其他朋友一起交流,就更容易能夠“積小步而至千里”,在程式員這個職業上有更長足的發展。
歡迎重學電腦組成原理 ! ! !
- 買電腦時,“原來的電腦性能跟不上啦”
- 寫程式時,“這個程式性能可以優化一下”
這虛無縹緲的“性能”到底指的是什麼呢?
我們能不能給性能下一個明確的定義,然後來進行準確的比較呢?
在電腦組成原理乃至體繫結構中,“性能”都是最重要的一個主題。
學習和研究電腦組成原理,就是在理解電腦是怎麼運作的,以及為什麼要這麼運作。
“為什麼”所要解決的事情,很多時候就是提升“性能”。
1 時間的倒數 - 性能
電腦的性能,其實和體力勞動很像,好比是我們要搬東西。
對於電腦的性能,我們需要有個標準來衡量。這個標準中主要有兩個指標。
1.1 響應時間(Response time)/ 執行時間(Execution time)
讓電腦“跑得更快”。
我們執行一個程式,到底需要花多少時間。花的時間越少,自然性能就越好。
- 實際系統里性能監測工具NewRelic中的響應時間,代表了每個外部的Web請求的執行時間
1.2 吞吐率(Throughput)/ 帶寬(Bandwidth)
讓電腦“搬得更多”。
伺服器使用的網路帶寬,通常就是一個吞吐率性能指標.吞吐率是指我們在一定的時間範圍內,到底能處理多少事情。這裡的“事情”,在電腦里就是處理的數據或者執行的程式指令。
和搬東西對比,如果響應時間短,跑得快,我們可以來回多跑幾趟搬幾趟。
所以縮短程式的響應時間,一般來說都會提升吞吐率。
除了縮短響應時間,我們還有別的方法嗎?當然!
我們還可以多找幾個人一起來搬,這就類似伺服器都是多核的。
人多力量大,同時處理數據,在單位時間內就可以處理更多數據,吞吐率自然也就上去了。
提升吞吐率的辦法有很多。大部分時候,我們只要多加一些機器,多堆一些硬體就好了。
但是響應時間的提升卻沒有那麼容易,因為CPU的性能提升其實在10年前就處於“擠牙膏”的狀態了,所以我們得慎重地來分析對待。
下麵我們具體來看。
我們一般把性能,定義成響應時間的倒數,也就是:
性能 = 1/響應時間
響應時間越短,性能數值越高。
同樣一個程式
- 在Intel最新的CPU Coffee Lake上,只需要30s就能運行完成
- 而在5年前CPU Sandy Bridge上,需要1min才能完成
那麼我們自然可以算出來,Coffee Lake的性能是1/30,Sandy Bridge的性能是1/60,兩個的性能比為2。於是,我們就可以說,Coffee Lake的性能是Sandy Bridge的2倍。
過去幾年流行的手機跑分軟體,就是把多個預設好的程式在手機上運行,然後根據運行需要的時間,算出一個分數來給出手機的性能評估。
而在業界,各大CPU和伺服器廠商組織了一個叫作SPEC(Standard Performance Evaluation Corporation)的第三方機構,專門用來指定各種“跑分”的規則
- 一份SPEC報告通常包含了大量不同測試的評分
SPEC提供的CPU基準測試程式,就好像CPU屆的“高考”,通過數十個不同的計算程式,對於CPU的性能給出一個最終評分。
這些程式豐富多彩,有編譯器、解釋器、視頻壓縮、人工智慧國際象棋等等,涵蓋了方方面面的應用場景。感興趣的話,你可以點擊這裡
2 電腦的計時單位:CPU時鐘
雖然時間是一個很自然的用來衡量性能的指標,但是用時間來衡量時,有兩個問題。
2.1 時間的測不准原理
如果用你自己隨便寫的一個程式,來統計程式運行的時間,每一次統計結果不會完全一樣。
為什麼會不准呢?這裡面有好幾個原因。
2.1.1 統計時間方法
我們統計時間是用類似於“掐秒錶”一樣,記錄 程式運行結束時間減去程式開始運行的時間。
這個時間也叫Wall Clock Time或者Elapsed Time
就是在運行程式期間,掛在牆上的鐘走掉的時間。
但電腦可能同時運行著好多個程式,CPU實際上不停地在各個程式之間進行切換。
在這些走掉的時間里,很可能CPU切換去運行別的程式了。
而且,有些程式在運行的時候,可能要從網路、硬碟去讀取數據,要等網路和硬碟把數據讀出來,給到記憶體和CPU。
要想準確統計某程式的實際運行時間,進而比較程式之間的性能,須把這些額外時間除掉
那這件事怎麼實現呢???
Linux下有一個叫time的命令,可助我們一臂之力,同樣的Wall Clock Time下,程式實際在CPU上到底花了多少時間。
我們簡單運行一下time命令。它會返回三個值
- 第一個 real time
也就是我們說的Wall Clock Time,即運行程式整個過程中流逝掉的時間 - 第二個 user time
CPU在運行你的程式,在用戶態運行指令的時間 - 第三個sys time
CPU運行你的程式,在操作系統內核里運行指令的時間
程式實際花費的CPU執行時間(CPU Time),就是user time加上sys time
一般情況下,如果user+sys比real大,甚至僅user比real大的情況出現,都是因為對應的程式被多個進程或者多個線程並行執行了,也很常見。
在多核或者多cpu的機器上運行,seq和wc命令會分配到兩個cpu上,user和sys是兩個cpu時間相加的,而real只是現實時鐘里走過的時間,極端情況下user+sys可以到達real的兩倍
雖然seq和wc這兩個命令都是單線程運行的,但是這兩個命令在多核cpu運行的情況下,會分別分配到兩個不同的cpu,於是user和sys的時間都是兩個cpu上運行的時間之和,就可能超過real的時間。
可以這樣來快速驗證,運行
time seq 100000000 | wc -l &
讓這個命令多跑一會兒,並且在後臺運行。
然後利用 top 命令看不同進程的cpu占用情況
你會在top的前幾行里看到seq和wc的cpu占用都接近100,實際是各被分配到了一個不同的cpu執行。
2.1.2 不一定可直接比較出性能
即使我們已經拿到了CPU時間,我們也不一定可以直接“比較”出兩個程式的性能差異
即使在同一臺電腦上,CPU可能滿載運行也可能降頻運行,降頻運行的時候自然花的時間會多一些。
除CPU外,時間這個性能指標還會受到主板、記憶體這些其他相關硬體的影響。
所以,我們需要對“時間”這個我們可以感知的指標進行
2.2 CPU時間拆解
程式的CPU執行時間=CPU時鐘周期數×時鐘周期時間
- 時鐘周期時間
你在買電腦的時候,一定關註過CPU的主頻
我手頭的這臺電腦就是 - 2.8 GHz Intel Core i7
這裡的2.8GHz就是電腦的主頻(Frequency/Clock Rate)。
這個2.8GHz,我們可以先簡單地理解為,CPU在1秒時間內,可以執行的簡單指令的數量是2.8G條。
更準確點,這個2.8GHz就代表,我們CPU的一個“鐘錶”能夠識別出來的最小的時間間隔。
就像我們掛在牆上的掛鐘,都是一秒一秒地走,所以通過牆上的掛鐘能夠識別出來的最小時間單位就是秒。
而在CPU內部,有一個叫晶體振蕩器(Oscillator Crystal)的東西,簡稱為晶振。
把晶振當成CPU內部的電子錶來使用。
晶振帶來的每一次“滴答”,就是時鐘周期時間。
在我這個2.8GHz的CPU上,這個時鐘周期時間,就是1/2.8G。
我們的CPU,是按照這個“時鐘”提示的時間來進行自己的操作。
主頻越高,意味著這個表走得越快,我們的CPU也就走得越快。
“超頻”,這說的其實就相當於把買回來的CPU內部的鐘給調快了,於是CPU的計算跟著這個時鐘的節奏,也就自然變快了。當然這個快不是沒有代價的,CPU跑得越快,散熱的壓力也就越大。就和人一樣,超過生理極限,CPU就會崩潰了。
- 回顧之前的CPU執行時間的公式程式的CPU執行時間=CPU時鐘周期數×時鐘周期時間
最簡單的提升性能方案,自然縮短時鐘周期時間,也就是提升主頻。
換句話說,就是換一塊好一點的CPU。
不過,這個是我們這些底層的研發人員控制不了的,所以我們就把目光挪到了乘法的另一個因數——CPU時鐘周期數上。
如果能夠減少程式需要的CPU時鐘周期數量,一樣能夠提升程式性能。
- 對於CPU時鐘周期數,我們可以再做一個分解,把它變成CPU時鐘周期數 = 指令數×每條指令的平均時鐘周期數(Cycles Per Instruction,簡稱CPI)不同的指令需要的Cycles是不同的
加法和乘法都對應著一條CPU指令
但是乘法需要的Cycles就比加法要多,自然也就慢。
在這樣拆分了之後,我們的程式的CPU執行時間就可以變成這樣三個部分的乘積。
程式的CPU執行時間=指令數 × CPI × Clock Cycle Time
因此,要解決性能問題,就是要優化這三者。
- 時鐘周期時間
就是電腦主頻,取決於硬體。摩爾定律就一直在不停提高的主頻。
最早的80386主頻只有33MHz,現在手頭的筆記本電腦就有2.8GHz,在主頻層面,就提升了將近100倍。 - 每條指令的平均時鐘周期數CPI
一條指令到底需要多少CPU Cycle。在後面講解CPU結構的時候,我們會看到,現代的CPU通過流水線技術(Pipeline),讓一條指令需要的CPU Cycle儘可能地少。因此,對於CPI的優化,也是電腦組成和體繫結構中的重要一環。 - 指令數
代表執行我們的程式到底需要多少條指令、用哪些指令。
這個很多時候就把挑戰交給了編譯器。
同樣的代碼,編譯成電腦指令時候,就有各種不同的表示方式。
把自己想象成一個CPU,坐在那裡寫程式。
電腦主頻就好像是你的打字速度,打字越快,你自然可以多寫一點程式。
CPI相當於你在寫程式的時候,熟悉各種快捷鍵,越是打同樣的內容,需要敲擊鍵盤的次數就越少。
指令數相當於你的程式設計得夠合理,同樣的程式要寫的代碼行數就少。
如果三者皆能實現,你自然可以很快地寫出一個優秀的程式,“性能”從外面來看就是好的。
3 總結
學完本文,對“性能”這個名詞,你應該有了更清晰的認識。
主要對於“響應時間”這個性能指標進行抽絲剝繭,拆解成了電腦時鐘周期、CPI以及指令數這三個獨立的指標的乘積,並且為指明瞭優化電腦性能的三條康莊大道。
也就是,提升電腦主頻,優化CPU設計使得在單個時鐘周期內能夠執行更多指令,以及通過編譯器來減少需要的指令數。
後面會講解,具體怎麼在電路硬體、CPU設計,乃至指令設計層面,提升電腦的性能。
參考
- 豆瓣讀書 - 電腦專題
- 深入淺出電腦組成原理
- What do 'real', 'user' and 'sys' mean in the output of time(1)?