選自Debugger
作者:Erik Engheim
機器之心編譯
參與:小舟、澤南
除了輕度辦公以外,Arm 架構的蘋果電腦還可以打遊戲、看視頻、跑深度學習,效率都還不錯。
最近,很多人的 M1 晶片版蘋果 MacBook 和 Mac Mini 到貨了。在不少測試中,我們看到了令人期待的結果:M1 晶片跑分比肩高端 X86 處理器,對標的 CPU 是 Ryzen 4900HS 和英特爾 Core i9,還能跟英偉達的 GPU GTX 1050Ti 打得有來有回。5 納米的晶片,真就如此神奇?
自蘋果發布搭載自研 M1 晶片的 Mac 產品後,人們對 M1 晶片充滿了好奇,各種測評層出不窮。最近,開發者 Erik Engheim 撰寫長文,分析 M1 晶片速度快背後的技術原因,以及英特爾和 AMD 等晶片廠商的劣勢。
關於蘋果的 M1 晶片,這篇文章將圍繞以下問題展開討論:
M1 晶片速度快背後的技術原因。蘋果是不是採用了什麼特殊的技術來實現這一點?如果 Intel 和 AMD 也想這麼做,難度有多大?
鑑於蘋果的官方宣傳中存在大量專業術語,我們先從最基礎的講起。
什麼是 CPU?
在提到英特爾和 AMD 的晶片時,我們通常談論的是中央處理器(CPU),或者叫微處理器。它們從內存中提取指令,然後按順序執行每條指令。
一個基本的 RISC CPU(不是 M1)。指令沿著藍色箭頭從內存移動到指令寄存器。解碼器用來解讀指令的內容,同時通過紅色的控制線來連通 CPU 的各個部分。ALU 對寄存器中的數字進行加減運算。
CPU 本質上是一個設備,包含許多被稱為寄存器的內存單元和被稱為算術邏輯單元(ALU)的計算單元。ALU 執行加法、減法和其他基礎數學運算。然而,這些只與 CPU 寄存器相連。如果想把兩個數字加起來,你必須把這兩個數字從內存中取出,放到 CPU 的兩個寄存器中。
下面是 RISC CPU(M1 中的 CPU 類型)執行的幾個典型指令示例:
此處的 r1 和 r2 是寄存器。當前的 RISC CPU 無法對不在寄存器中的數字執行示例中的運算,比如不能將在兩個不同位置的內存中的數字相加,而是要將兩個數字各放到一個單獨的寄存器裡。
在上面的示例中,我們必須先將內存位置為 150 的數字放到寄存器 r1 中,然後將位置為 200 的數字放到 r2 中,只有這樣,這兩個數字才能依據 add r1, r2 指令進行加法運算。
這種老式機械計算器有兩個寄存器:累加器和輸入寄存器。現代 CPU 通常有十幾個寄存器,而且它們是電子的,不是機械的。
寄存器的概念由來已久。例如,在上圖的機械計算器上,寄存器用來存放加起來的數字。
M1 不是 CPU 這麼簡單
M1 晶片不是 CPU,而是把多個晶片集成到了一起,CPU 只是其中的一部分。
可以說,M1 是把整個計算機放在了一塊晶片上。M1 包含 CPU、GPU、內存、輸入 / 輸出控制器,以及完整計算機所需的其他很多東西,這就是我們經常會在手機上看到的 SoC(片上系統)概念。
M1 是一個片上系統。也就是說,將構成一臺計算機的所有部件都放在一塊矽晶片上。
如今,如果你從英特爾或 AMD 購買一塊晶片,你拿到的實際上是一個微處理器包,而過去的計算機主板上是多個單獨的晶片。
計算機主板示例,上面包含內存、CPU、顯卡、IO 控制器、網卡等部件。
然而,現在我們可以在一塊矽片上集成大量電晶體,因此 AMD、英特爾等公司開始將多個微處理器放在一塊晶片上。我們將這些晶片稱為 CPU 核心。一個核心基本上是一個完全獨立的晶片,它可以從內存中讀取指令並執行計算。
具備多個 CPU 核心的微晶片。
很長一段時間以來,添加更多通用 CPU 核心成為提高晶片性能的主要方法,但有家廠商沒這麼做。
蘋果的異構計算策略沒那麼神秘
在提升性能的道路上,蘋果並沒有選擇增加更多通用 CPU 核心,而是採取了另一種策略:添加更多專用晶片來完成一些專門的任務。這樣做的好處是:與通用 CPU 核心相比,專用晶片可以使用更少的電流執行任務,而且速度還更快。
這並不是什麼全新的技術。多年來,圖形處理單元(GPU)等專用晶片已經存在於英偉達和 AMD 的顯卡中,執行與圖形相關的操作,速度比通用 CPU 快得多。
蘋果只是在這個方向上走得更加徹底。除了通用核心和內存之外,M1 包含了一系列專用晶片:
CPU(中央處理器):SoC 的「大腦」,運行作業系統和 app 的大部分代碼。GPU(圖形處理器):處理圖形相關的任務,如可視化 app 的用戶界面和 2D/3D 遊戲。IPU(圖像處理單元):用於加快圖像處理應用所承擔的常見任務。DSP(數位訊號處理器):具備比 CPU 更強的數學密集型功能,包括解壓音樂文件。NPU(神經網絡處理器):用於高端智慧型手機,加速語音識別等機器學習任務。視頻編碼器 / 解碼器:以高能效的方式處理視頻文件和格式的轉換。Secure Enclave:負責加密、身份驗證,維護安全性。統一內存(unified memory):允許 CPU、GPU 和其他核心快速交換信息。
這就是使用 M1 Mac 進行圖像和視頻編輯時速度有所提升的一部分原因。許多此類任務可以直接在專用硬體上運行,這樣一來,相對廉價的 M1 Mac Mini 就能夠輕鬆對大型視頻文件進行編碼。
你或許疑惑,統一內存與共享內存有什麼區別。將視頻內存與主存共享的做法導致了低性能,因為 CPU 和 GPU 必須輪流訪問內存,共享意味著爭用數據總線。
統一內存的情況就不同了。在統一內存中,CPU 和 GPU 可以同時訪問內存,並且 CPU 和 GPU 還可以相互告知一些內存的位置。以前 CPU 必須將數據從其主存區域複製到 GPU 使用的區域,而使用統一內存模式,無需複製,通過告知內存位置即可令 GPU 使用該內存。
也就是說,M1 上各種專有協處理器都可以使用同一內存池彼此快速地交換信息,從而顯著提升性能。
英特爾和 AMD 為什麼不效仿這一策略?
其他 ARM 晶片製造商也越來越多地投入專用硬體。AMD 開始在某些晶片上安裝功能更強大的 GPU,並通過加速處理器(APU)逐步向某種形式的 SoC 邁進。(APU 將 CPU 核心和 GPU 核心放置在同一晶片上。)
AMD Ryzen 加速處理器在同一塊晶片上結合 CPU 和 GPU,但不包含其他協處理器、IO 控制器或統一內存。
英特爾和 AMD 不這麼做是有重要原因的。SoC 本質上是晶片上的整個計算機,這使得它非常適合實際的計算機製造商,例如惠普、戴爾。計算機製造商可以簡單地獲取 ARM 智慧財產權許可,併購買其他晶片的 IP,來添加他們認為自己的 SoC 應該具備的任意專用硬體。然後,他們將已完成的設計交給半導體代工廠,比如 GlobalFoundries 和臺積電(TSMC),臺積電現在是 AMD 和蘋果的晶片代工廠。
那麼問題來了。英特爾和 AMD 的商業模型都是基於銷售通用 CPU(只需將其插入大型 PC 主板)。計算機製造商只需從不同的供應商那裡購買主板、內存、CPU 和顯卡,然後將它們集成即可。但這種方式已經漸漸淡出。
在 SoC 時代,計算機製造商無需組裝來自不同供應商的物理組件,而是組裝來自不同供應商的 IP(智慧財產權)。他們從不同供應商那裡購買顯卡、CPU、數據機、IO 控制器等的設計,並將其用於設計 SoC,然後尋找代工廠完成製造過程。
但是英特爾、AMD、英偉達都不會將其智慧財產權給戴爾或惠普,讓他們為自己的計算機製造 SoC。
當然,英特爾和 AMD 可能只是開始銷售完整的 SoC,但是其中包含什麼呢?PC 製造商可能對此有不同的想法。英特爾、AMD、微軟和 PC 製造商之間可能就 SoC 要包含哪些專用晶片產生衝突,因為這些晶片需要軟體支持。
而對於蘋果來說,這很簡單。蘋果控制整個產品,比如為機器學習開發者提供如 Core ML 庫等。至於 Core ML 是在蘋果的 CPU 上運行還是 Neural Engine,這是開發者無需關心的實現細節了。
CPU 快速運行的根本挑戰
異構計算只是一部分原因。M1 的快速通用 CPU 核心 Firestorm 確實速度非常快,與之前的 ARM CPU 核心相比,二者的速度差距非常大。與 AMD 和英特爾核心相比,ARM 也非常弱。相比之下,Firestorm 擊敗了大多數英特爾核心,也幾乎擊敗了最快的 AMD Ryzen 核心。
在探討 Firestorm 的速度成因之前,我們先來了解讓 CPU 快速運行的核心意義。
原則上可以通過以下兩種策略來完成 CPU 加速的任務:
以更快的速度順序執行更多指令;並行執行大量指令。
在上世紀 80 年代,這很容易做到。只要增加時鐘頻率,就能更快執行指令。每個時鐘周期表示計算機執行某項任務的時間,但是這項任務可能非常微小。一條指令由多個較小的任務構成,因此可能需要多個時鐘周期。
但是現在已經幾乎不可能增加時鐘頻率了,所以第二個策略「並行執行大量指令」是目前研發的重心。
多核還是亂序處理器?
這個問題有兩種解決方法。一種是引入更多 CPU 核心。從軟體開發者的角度講,這類似於添加線程,每個 CPU 核心就像一個硬體線程。雙核 CPU 可以同時執行兩個單獨的任務,即兩個線程。這些任務可以被描述為兩個存儲在內存中的單獨程序,或者同一個程序被執行了兩次。每個線程需要記錄,例如該線程當前在程序指令序列中的位置。每個線程都可以存儲臨時結果(應分開存儲)。
原則上,處理器可以在只有一個核心的情況下運行多個線程。這時,處理器只能是暫停一個線程並存儲當前進程,然後再切換到另一個線程,之後再切換回來。這並不能帶來太多的性能提升,僅在線程經常懸停來等待用戶輸入或者慢速網絡中的數據等時才使用。這些可以稱為軟體線程。硬體線程意味著可以使用實際的附加物理硬體(如附加核心)來加快處理速度。
問題在於開發者必須編寫代碼才能利用這一點,一些任務(例如伺服器軟體)很容易編寫,你可以想像分別處理每個連接的用戶。這些任務彼此獨立,因此擁有大量核心是伺服器(尤其是基於雲的服務)的絕佳選擇。
具有 128 個核心的 Ampere Altra Max ARM CPU 專為雲計算而設計,大量硬體線程是一項優勢。
這就是你會看到 128 核心 Ampere Altra Max ARM CPU 的原因了。該晶片專為雲計算製造,不需要瘋狂的單核性能,因為在雲上需要每瓦具有儘可能多的線程來處理儘可能多的並發用戶。
而蘋果則不同,蘋果生產單用戶設備,大量線程並不是優勢。蘋果的設備多用於遊戲、視頻編輯、開發等。蘋果希望臺式機具有精美的響應圖形和動畫。
桌面軟體通常不需要利用很多核心,例如,電腦遊戲通常需要 8 個核心,在這種情況下 128 個核心就完全是浪費了。因此,用戶需要的是更少但更強大的核心。
亂序執行是一種並行執行更多指令但不以多線程執行的方式。開發者無需專門編碼其軟體即可利用它。從開發者的角度來講,每個核心的運行速度都更快了。
要了解其工作原理,首先我們需要了解一些內存知識。在一個特定的內存位置上請求數據的速度很慢。但是與獲得 128 個字節相比,延遲獲得 1 個字節的影響不大。數據通過數據總線發送,你可以將其視為內存與數據經過的 CPU 不同部分之間的一條通道或管道。實際上它只是一些可以導電的銅線。如果數據總線足夠寬,你就可以同時獲取多個字節。
因此 CPU 一次執行一整個指令塊,但是這些指令被編寫為一條接著一條執行。現代微處理器會進行「亂序執行」。這意味著它們能夠快速分析指令緩衝區,查看指令之間的依賴關係。示例如下:
01:mulr1,r2,r3//r1←r2×r302:addr4,r1,5//r4←r1+503:addr6,r2,1//r6←r2+1
乘法是一個緩慢的運算過程,需要多個時鐘周期來執行。第二條指令僅需等待,因為其計算取決於先知道放入 r1 寄存器的結果。但是,第三條指令並不取決於先前指令的計算結果,因此亂序處理器可以並行計算此指令。
但現實情況往往有數百條指令,CPU 能夠找出這些指令之間的所有依賴關係。
它通過查看每個指令的輸入來分析指令的輸入是否取決於一或多個其他指令的輸出,輸入和輸出指包含之前計算結果的寄存器。
例如上例中,add r4, r1, 5 指令依賴於來自 r1 的輸入,而 r1 通過 mul r1, r2, r3 指令得到。
我們可以將這些關係連結在一起,形成 CPU 可以處理的詳細圖。圖的節點表示指令,邊表示連接它們的寄存器。CPU 可以分析這類節點圖,並確定可以並行執行的指令,以及在繼續執行之前需要在哪一步等待多個相關計算結果。
許多指令可以很早完成,但是其結果無法正式化。我們無法提交這些結果,否則順序將出現錯誤。指令往往是需要按照順序執行的。像堆棧一樣,CPU 將從頂部一直彈出已完成的指令,直到命中未完成的指令。
亂序執行功能讓 M1 上的 Firestorm 核心發揮了重要作用,實際上它比英特爾或 AMD 的產品更加強大。
為什麼英特爾和 AMD 的亂序執行不如 M1?
「重排序緩衝區」(Re-Order Buffer,ROB)不包含常規的機器碼指令,即 CPU 從內存中獲取的待執行指令。這些是 CPU 指令集架構(ISA)中的指令,也就是我們稱為 x86、ARM、PowerPC 等的指令。
但是,CPU 內部會使用程式設計師無法看到的完全不同的指令集,即微操作(micro-op 或 μop),ROB 內全是微操作。
微操作非常寬(包含很多位),能夠包含各種元信息。而 ARM 或 x86 指令則無法添加此類信息,因為會發生:
程序的二進位文件完全膨脹。暴露 CPU 的工作原理細節,比如是否具備亂序執行單元、寄存器重命名等詳細信息。很多元信息僅在當前執行情況下才有意義。
你可以將其視為,在編寫程序時有一個公共 API,需要保持穩定並供所有人使用,那就是 ARM、x86、PowerPC、MIPS 等指令集。而微操作基本上是用於實現公共 API 的私人 API。
通常,微操作對於 CPU 而言更易於使用,因為每條微指令都能完成一項簡單的有限任務。常規的 ISA 指令可能更複雜,會導致大量事情發生,進而實際上轉化為多個微操作。
CISC CPU 通常只使用微操作,否則大型複雜的 CISC 指令會讓 pipeline 和亂序執行幾乎無法實現。
RISC CPU 有一個選擇,所以較小的 ARM CPU 不使用微操作,但這也意味著它們無法執行亂序執行等。
對於理解英特爾和 AMD 的亂序執行不如 M1,這很關鍵。
快速運行的能力取決於你可以用微操作填充 ROB 的速度及數量。填充的速度越快,這種能力就越大,你就有更多機會選擇可並行執行的指令,性能就會進一步提升。
機器碼指令被指令解碼器分割成多個微操作。如果有更多的解碼器,我們就可以並行分割更多的指令,從而更快地填充 ROB。
這就是存在巨大差異的地方。最糟糕的英特爾和 AMD 微處理器核心具有 4 個解碼器,這意味著它可以並行解碼 4 條指令,並輸出微操作。
但是蘋果有 8 個解碼器。不僅如此,ROB 還大了約 2 倍,基本上可以容納 3 倍的指令。沒有其他主流晶片製造商的 CPU 擁有如此多的解碼器。
為什麼英特爾和 AMD 不能添加更多的指令解碼器?
這就牽扯到 RISC 了。M1 Firestorm 核心使用的是 ARM RISC 架構。
對於 x86,一條指令的長度可能是 1–15 字節不等。而在 RISC 晶片上,指令大小是固定的。如果每個指令具有相同的長度,將字節流分割成指令並饋入 8 個不同的並行解碼器將易如反掌。但是在 x86 CPU 上,解碼器不知道下一條指令從哪裡開始,它必須實際分析每條指令,判斷它的長度。
英特爾和 AMD 採用暴力方式處理這一問題,它們嘗試在每個可能的起點上解碼指令。這意味著必須處理大量錯誤的猜測和錯誤。這讓解碼器階段變得非常複雜,也很難再添加更多的解碼器。相比而言,蘋果輕輕鬆鬆就可以添加更多解碼器。
實際上,添加更多東西會導致許多其他問題,以至於 AMD 本身的 4 個解碼器基本上已經是其上限了。
而正是這一點讓 M1 Firestorm 核心在相同的時鐘頻率下處理的指令數量是 AMD 和英特爾 CPU 的兩倍。
有人可能會反駁說,CISC 指令會變成更多的微操作,它們的密度更大,因此解碼一條 x86 指令類似於解碼兩條 ARM 指令。
然而實際上,高度優化的 x86 代碼很少使用複雜的 CISC 指令。在某些方面,它具有 RISC 風格。
但這對 Intel 或 AMD 沒有幫助,因為即使 15 個字節長的指令很少見,也必須製造解碼器來處理它們。而這會導致複雜性,從而阻止 AMD 和 Intel 添加更多解碼器。
AMD 的 Zen3 核心不還是更快嗎?
據了解,最新 AMD CPU 核心(即 Zen3)要比 Firestorm 核心快一點。但這只是因為 Zen3 核心的時鐘頻率為 5 GHz,Firestorm 核心的時鐘頻率為 3.2 GHz。儘管時鐘頻率高了近 60%,但 Zen3 也只是勉強超越 Firestorm。
那蘋果為什麼不增加時鐘頻率呢?因為更高的時鐘頻率會使晶片變熱。這也是蘋果的主要賣點之一。與 Intel 和 AMD 的產品不同,他們的計算機幾乎不需要冷卻。
從本質上講,我們可以說 Firestorm 核心確實優於 Zen3 核心。Zen3 只能通過更大的電流和變得更熱來維持領先。而蘋果選擇不這樣做。
如果蘋果想要更高的性能,他們只會增加更多的核心。這樣就可以在降低功耗的同時,還能提供更高的性能。
未來將會如何
看來 AMD 和英特爾在兩個方面都陷入了困境:
它們沒有允許其輕鬆追求異構計算和 SoC 設計的商業模型。傳統的 x86 CISC 指令集讓它們難以提高亂序執行性能。
但這不意味著遊戲結束。它們當然可以增加時鐘頻率,使用更多的散熱,添加更多核心,增強 CPU 緩存等。但它們目前都處於劣勢。英特爾的情況最糟糕,因為其核心已經被 Firestorm 擊敗,並且它的 GPU 薄弱,無法集成到 SoC 方案中。
引入更多核心的問題在於,對於典型的桌面工作負載,使用過多核心會導致收益遞減。當然,很多核心非常適合伺服器。但 Amazon 和 Ampere 等公司已經使用 128 核的巨型 CPU 了。
幸運的是,Apple 並未出售其晶片。因此,PC 用戶只能接受 AMD 和英特爾提供的產品。PC 用戶可能會跳船,但這是一個緩慢的過程。人們通常不會立即離開已經有大量投入的平臺。
但是,年輕的專業人士沒有在任何平臺上投入太多資金,他們將來可能會越來越多地轉向蘋果,從而擴大蘋果在高端市場的份額和在 PC 市場總利潤中的份額。
參考內容:
https://erik-engheim.medium.com/why-is-apples-m1-chip-so-fast-3262b158cba2