程式設計師學習 CPU 有什麼用?

語言: CN / TW / HK

theme: jzman

本文已收錄到  GitHub · AndroidFamily,有 Android 進階知識體系,歡迎 Star。技術和職場問題,請關注公眾號 [彭旭銳] 私信我提問。

前言

大家好,我是小彭。

在上一篇文章裡,我們聊到了計算機的馮·諾依曼架構,以及計算機的五大部件:控制器、運算器、儲存器、輸入裝置和輸出裝置。在現在計算機體系中,CPU 是整個計算機的核心,主要包含控制器和運算器兩大部件。

在後續文章中,我們將從 CPU 的基本認識開始,逐步將 CPU 與執行系統、儲存系統 和 I/O 系統串聯起來,請關注。


學習路線圖:


1. 認識 CPU 中央處理器

1.1 什麼是 CPU?

中央處理單元(Central Processing Unit,CPU)也叫中央處理器或主處理器,是整個計算機的核心,也是整臺計算機中造價最昂貴的部件之一。

從硬體的角度: CPU 由超大規模的電晶體組成;

從功能的角度: CPU 內部由時鐘、暫存器、控制器和運算器 4 大部分組成。

  • 1、時鐘(Clock): 負責發出時鐘訊號,也可以位於 CPU 外部;
  • 2、暫存器(Register): 負責暫存指令或資料,位於儲存器系統金字塔的頂端。使用暫存器能夠彌補 CPU 和記憶體的速度差,減少 CPU 的訪存次數,提高 CPU 的吞吐量;
  • 3、控制器(Control Unit): 負責控制程式指令執行,包括從主記憶體讀取指令和資料傳送到暫存器,再將運算器計算後的結果寫回主記憶體;
  • 4、運算器(Arithmetic Logic Unit,ALU): 負責執行控制器取出的指令,包括算術運算和邏輯運算。

馮·諾依曼架構

—— 圖片引用自 Wikipedia

1.2 為什麼要學習 CPU?

對於大部分程式設計師,日常所處理的工作都是在跟 Java 和 C++ 等高階語言打交道,並不會直接地與 CPU 打交道。那麼,為什麼我們還要花這麼多時間去學習 CPU 呢?我認為有以下原因:

  • 原因 1 - 掌握 CPU 原理能夠開發更高效能的程式: 理解 CPU 的工作原理有助於設計出更高效能的演算法或程式碼,例如通過避免偽共享、提高快取命中率等方式提高程式執行效率,就需要對 CPU 的快取機制有一定的理解;

  • 原因 2 - 擴充套件方案積累: CPU 是整個計算機系統中最複雜的模組,也是當代電腦科學的制高點。積累 CPU 內部的解決方案,能夠為將來的遇到類似問題提供思路,達到觸類旁通的作用。例如 CPU 快取淘汰策略與應用記憶體的快取淘汰策略有相似之處;

  • 原因 3 - CPU 是知識體系最底層的知識: 當我們在思考或解決某一個問題時,就需要利用到更深層次的知識積累來解釋,而 CPU 就是位於知識體系中最底層知識。例在記憶體系統的可見性、執行系統的 IO_WAIT 和執行緒池設計等問題中,都需要對 CPU 的執行機制有一定理解。

CPU

—— 圖片引用自 圖片來源

1.3 通用處理器和專用處理器

在早期的計算機系統中,只有 1 個通用處理器,使用 1 個處理器就能夠完成所有計算任務。後來人們發現可以把一些計算任務分離出來,單獨設計專門的晶片微架構,在執行效率上會遠遠高於通用處理器,最典型的專用處理器就是 GPU 圖形處理器。

這種用來專門處理某種計算任務的處理器就是專用處理器,那為什麼專用處理器在處理某些特定問題時更快呢,我認為有 3 點解釋:

  • 1、最優架構: 專用處理器只處理少量型別的工作,可以為特定工作設計最優晶片架構,而通用處理器只能設計全域性最優架構,但不一定是執行特定工作的最優機構;
  • 2、硬體加速: 可以把多條指令的計算工作直接用硬體實現,相比於 CPU 一條條地執行指令,能夠節省大量指令週期;
  • 3、成本更低: 專用處理器執行的計算流程是固定的,不需要 CPU 的流水線控制、亂序執行等功能,實現相同計算效能的造價更低。

現代計算機架構都是 1 個通用處理器加上多個專用處理器,這種將不同型別的計算任務採用不同的計算單元完成的設計,也叫 異構計算(Heterogeneous Computing)。

多處理器架構


2. 指令集架構 ISA

2.1 什麼是指令集架構?

CPU 所能理解的機器語言就是 指令(Instruction Code), 一個 CPU 所能理解的所有指令就是 指令集(Instruction Set)。

為了保證晶片間的相容性,晶片廠商並不為每款新晶片設計一個新的指令集,而是將指令集推廣為標準規範,這個規範就是 指令集架構(Instruction Set Architecture,ISA)

相對於指令集架構,CPU 在實現具體指令集功能的硬體電路設計就是 微架構(Micro Architecture)。如果用軟體的思考方式,ISA 就是 CPU 的功能介面,定義了 CPU 的標準規範,而微架構就是 CPU 的功能實現,定義了 CPU 的具體電路設計,一種指令集可以相容不同的微架構。

2.2 兩種主流的指令集架構

因為 CPU 位於整個計算機系統最底層且最核心的部件,如果 CPU 的相容性都出問題了,那麼以前開發的應用軟體甚至作業系統將無法在新的 CPU 上執行,這對晶片廠商的生態破壞是致命的。因此,指令集架構是相對穩定的,晶片廠商在 ISA 中新增或刪除指令時會非常謹慎。

目前,能夠有效佔領市場份額的只有 2 個 ISA ,它們也分別代表了複雜與精簡 2 個發展方向:

  • x86 架構: Intel 公司在 1970 年代推出的複雜指令集架構;
  • ARM 架構: ARM 公司在 1980 年代推出的精簡指令集架構,我們熟悉的 Apple M1 晶片、華為麒麟晶片和高通驍龍晶片都是 ARM 架構(其實,ARM 公司並不生產晶片,而是以技術授權的模式執行)。

2.3 複雜指令集和精簡指令集

在 CPU 指令集的發展過程中,形成了 2 種指令集型別:

  • 複雜指令集(Complex Instruction Set Computer,CISC): 強調單個指令可以同時執行多個基本操作,用少量指令就可以完成大量工作,執行效率更高;
  • 精簡指令集(Reduced Instruction Set Computer,RISC): 強調單個指令只能執行一個或少數基礎操作,指令之間沒有重複或冗餘的功能,完成相同工作需要使用更多指令。

在早期的計算機系統中,指令集普遍很簡單,也沒有複雜和精簡之分。隨著應用軟體的功能越來越豐富,應用層也在反向推動晶片架構師推出更強大的指令集,以簡化程式編寫和提高效能。例如,一些面向音視訊的指令可以在一條指令內同時完成多個數據進行編解碼。

這在當時的確是不錯的選擇。 原因是 CPU 和主存的速度差實在太大了,用更少的指令實現程式功能(指令密度更高)可以減少訪存次數。 憑藉這一點,複雜指令集對精簡指令集的優勢是幾乎全面性的:

  • 優勢 1: 可以減少程式佔用的記憶體和磁碟空間大小;
  • 優勢 2: 可以減少從記憶體或磁盤獲取指令所需要的頻寬,能夠提高匯流排系統的傳輸效率;
  • 優勢 3: CPU L1 Cache 可以容納更多指令,可以提高快取命中率。且現代計算機中多個執行緒會共享 L1 Cache,指令越少對快取命中率越有利;
  • 優勢 4: CPU L2 Cache 可以容納更多資料,對操作大量資料的程式也有利於提高快取命中率。

然而,這些優勢都是有代價的:

  • 缺點 1 - 處理器設計複雜化: 指令越複雜,用於解析指令的處理器電路設計肯定會越複雜,執行效能功耗也越大;
  • 缺點 2 - 指令功能重疊: 很多新增的指令之間產生了功能重疊,不符合指令集的正交性原則,而且新增的很多複雜指令使用率很低,但處理器卻付出了不成正比的設計成本;
  • 缺點 3 - 指令長度不統一: 指令長度不統一,雖然有利於使用哈夫曼編碼進一步提高指令密度(頻率高的指令用短長度,頻率高的指令用大長度),但是指令長度不同,執行時間也有長有短,不利於實現流水線式結構。

因此,到 1980 年代,精簡指令集 RISC 逐漸浮出水面。目前,大多數低端和移動系統都採用 RISC 架構,例如 Android 系統、Mac 系統和微軟 Surface 系列。

相比於複雜指令集,精簡指令集更加強調 “正交性” ,單個指令只能執行一個或少數基礎操作,指令之間沒有重複或冗餘的功能。而且精簡指令集的每條 指令長度相同 ,非常便於實現流水線式結構。

網上很多資料有一個誤區: ~~精簡指令集簡化了指令集的大小。~~ 這是不對的,準確的說法是簡化了指令集的複雜度。

總結一下: 複雜指令集憑藉更高的指令密度,在效能方面整體優於精簡指令集(記憶體 / 磁碟佔用、CPU Cache 命中率、TLB 未命中率),而精簡指令集犧牲了指令密度換取更簡單的處理器架構,以效能換取功耗的平衡。

| 指令集型別 | CISC | RISC | | --- | --- | --- | | 指令數量 | 指令數量龐大 | 指令數量相對較少 | | 指令長度 | 長度不同 | 長度相同 | | 指令功能 | 有重疊 | 正交 | | 舉例 | x86 | ARM、MIPS |


3. CPU 的效能指標

3.1 執行系統引數

  • 1、主頻(Frequency/Clock Rate): 在 CPU 內部有一個 晶體振盪器(Oscillator Crystal) ,晶振會以一定的頻率向控制器發出訊號,這個訊號頻率就是 CPU 的主頻。主頻是 CPU 最主要的引數,主頻越快,計算機單位時間內能夠完成的指令越快。 CPU 的主頻並不是固定的,CPU 在執行時可以選擇低頻、滿頻甚至超頻執行, 但是工作頻率越高,意味著功耗也越高;

  • 2、時鐘週期(Clock Cycle): 主頻的另一面,即晶振發出訊號的時間間隔, 時鐘週期=1/主頻;

  • 3、外頻: 外頻是主機板為 CPU 提供的時鐘頻率,早期計算機中 CPU 主頻和外頻是相同的,但隨著 CPU 主頻越來越高,而其他裝置的速度還跟不上,所以現在主頻和外頻是不相等的;

  • 4、程式執行時間:

    • 4.1 流逝時間(Wall Clock Time / Elapsed Time): 程式開始執行到程式結束所流逝的時間;

    • 4.2 CPU 時間(CPU Time): CPU 實際執行程式的時間,僅包含程式獲得 CPU 時間片的時間(使用者時間 + 系統時間)。由於 CPU 會並行執行多個任務,所以程式執行時間會小於流逝時間;

    • 4.3 使用者時間(User Time): 使用者態下,CPU 切換到程式上執行的時間;

    • 4.4 系統時間(Sys Time): 核心態下,CPU 切換到程式上執行的時間;

3.2 儲存系統引數

  • 字長(Word): CPU 單位時間內同時處理資料的基本單位,多少位 CPU 就是指 CPU 的字長是多少位,比如 32 位 CPU 的字長就是 32 位,64 位 CPU 的字長就是 64 位;

  • 地址匯流排寬度(Address Bus Width): 地址匯流排傳輸的是地址訊號,地址匯流排寬度也決定了一個 CPU 的定址能力,即最多可以訪問多少資料空間。舉個例子,32 位地址匯流排可以定址 4GB 的資料空間;

  • 資料匯流排寬度(Data Bus Width): 資料匯流排傳輸的是資料訊號,資料匯流排寬度也決定了一個 CPU 的資訊傳輸能力。

區分其它幾種容量單位:

  • 位元組(Byte): 位元組是計算機資料儲存的基本單位,即使儲存 1 個位也需要按 1 個位元組儲存;

  • 塊(Block): 塊是 CPU Cache 管理資料的基本單位,也叫 CPU 快取行;

  • 段(Segmentation)/ 頁(Page): 段 / 頁是作業系統管理虛擬記憶體的基本單位。

  • 相關文章:計算機的儲存器金字塔長什麼樣?


4. 影響 CPU 效能的因素

CPU 作為計算機的核心部件,未來一定是朝著更強大的效能出發。在看待 CPU 的視角上,我們也要具備一定的全域性觀:

  • 1、提升 CPU 效能不止是 CPU 的任務: 計算機系統是多個部件組成的複雜系統,脫離整體談區域性沒有意義;
  • 2、平衡效能與功耗: 一般來說,CPU 的計算效能越高,功耗也越大。我們需要綜合考慮效能和功耗的關係,脫離功耗談效能沒有意義。

4.1 提升 CPU 主頻

提升主頻對 CPU 效能的影響是最直接的,過去幾十年 CPU 的主要發展方向也是在怎麼提升 CPU 主頻的問題上。

不過,最近幾年 CPU 主頻的速度似乎遇到瓶頸了。因為想要主頻越快,要麼讓 CPU 滿頻或超頻執行,要麼升級晶片製程,在單位體積裡塞進去更多電晶體。這兩種方式都會提升 CPU 功耗,帶來續航和散熱問題。如果不解決這兩個問題,就無法突破主頻瓶頸。

主頻的瓶頸

—— 圖片引用自 Wikipedia

4.2 多核並行執行

既然單核 CPU 的效能遇到瓶頸,那麼在 CPU 晶片裡同時塞進去 2 核、4 核甚至更多,那麼整個 CPU 晶片的效能不就直接翻倍提升嗎?

理想很美好,現實是效能並不總是隨著核心數線性增加。在核心數較小時,增加並行度得到的加速效果近似於線性提升,但增加到一定程度後會趨於一個極限, 說明增加並行度的提升效果也是有瓶頸的。

為什麼呢?因為不管程式並行度有多高,最終都會有一個結果彙總的任務,而彙總任務無法並行執行,只能序列執行。例如,我們用 Java 的 Fork/Join 框架將一個大任務分解為多個子任務並行執行,最終還是需要序列地合併子任務的結果。

這個結論也有一個經驗定律 —— 阿姆達爾定律(Amdahl’s Law) ,它解釋了處理器平行計算後效率提升情況。我們把序列的部分稱為序列分量 $W_s$ ,把並行的部分稱為並行分量 $W_p$ ,正是序列分量限制了效能提升的極限,序列分量越大,極限越低。

  • 並行後的執行時間是 $\frac{W_p}{p} + W_s$
  • 並行後的加速倍數是 $\frac{W_s+W_p}{W_s+\frac{W_p}{p}}$ ,當並行度 p 趨向於 無窮大時,提升極限就是 $\frac{W_s+W_p}{W_s}$

並行度、並行分量對提升效果的影響

—— 圖片引用自 Wiki 百科

提示: 以綠色的曲線為例,程式可以的並行分量是 95%,序列分量是 5%,最終得出的提升極限就會 20 倍。

4.3 指令重排序

增加核心數是提升並行度最直接的方法,但並不是唯一的方法。

現代 CPU 為了提高並行度,會在遵守單執行緒資料依賴性原則的前提下,對程式指令做一定的重排序。事實上不止是 CPU,從原始碼到指令執行一共有 3 種級別重排序:

  • 1、編譯器重排序: 例如將迴圈內重複呼叫的操作提前到迴圈外執行;
  • 2、處理器系統重排序: 例如指令並行技術將多條指令重疊執行,或者使用分支預測技術提前執行分支的指令,並把計算結果放到重排列緩衝區(Reorder Buffer)的硬體快取中,當程式真的進入分支後直接使用快取中的結算結果;
  • 3、儲存器系統重排序: 例如寫緩衝區和失效佇列機制,即是可見性問題,從記憶體的角度也是指令重排問題。

指令重排序型別

4.4 SoC 晶片 —— 片內片外雙匯流排結構

隨著晶片積體電路工藝的進步,在馮·諾依曼架構中的五大部件(運算器、控制器、儲存器、輸入和輸出裝置介面)也可以整合在一個晶片上,形成一個近似於完整計算機的系統,這種晶片也叫 片上系統(System on Chip,Soc)。 SoC 晶片將原本分佈在主機板上的各個部件聚合到同一個晶片上,不同部件之間的匯流排資訊傳輸效率更高。


5. 總結

今天,我們簡單了討論了 CPU 的基本概念,很多問題只是淺嘗輒止。在後續的文章裡,我們將從執行系統、儲存系統和 I/O 系統三個角度與 CPU 串聯起來。請關注。


本文為稀土掘金技術社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!

參考資料