當前位置:
首頁 > 科技 > M1 CPU 那麼多的核,macOS 是怎樣管理的?

M1 CPU 那麼多的核,macOS 是怎樣管理的?

編註:本文 原文 發表於 Howard Oakley 博士的個人博客,文章的翻譯、注釋以及發布均已得到作者同意。為了補充一些細節以及便於普通讀者理解,本文對原文有一定程度的修改。



1984 年 1 月,Apple 開始設計、開發和銷售個人電腦系列產品 Macintosh。在這近 40 年時間裡,Apple 濃墨重彩地書寫了許多科技史上的里程碑,其中就包括了三個非常重要的時間點——1994 年從摩托羅拉 68000 架構遷移至 PowerPC 平台、 2005 年從 PowerPC 平台遷移至英特爾 x86 平台、2020 年從英特爾 x86 平台遷移至 Apple Silicon。

2020 年 11 月 11 日 Apple 在加州 Cupertino 正式發布了 M1 晶元,不僅是 Apple 自己首款基於 ARM 架構的用於個人電腦的自研處理器,而且其強大的性能也讓當時苦「牙膏廠」久已的 Geeker 們也感到異常亢奮。

不過,看得見的風光總是與看不到的努力分不開的。作為專為 Mac 設計、優化的晶元,系統到底是怎麼將程序調度在 M 系列處理器上的。

關於 Howard Oakley 博士

Howard Oakley 博士目前是一名 Mac 軟體的開發者,同時也是網站 Eclectic Light Company 的創始人。他與 Mac 的緣分始於他對 Macintosh SE 和 Macintosh Programmer"s Workshop 的一見鍾情,從此他沉溺於其中、不可自拔直至今日。


不對稱的處理器架構

在以前的 Intel 處理器款的 Mac 中,Intel 處理器所有的核心都是相同的,因此這種處理器是 對稱多處理(Symmetric multiprocessing,縮寫為 SMP)構架。系統要做的事情其實很簡單,保持每一個核心的負載大體相近即可。

在 Intel 處理器款的 Mac 上打開「活動監視器」的 CPU 歷史窗口,我們可以注意到圖表分為了兩列,左半部分奇數核是真實的物理核心,右半部分則是 Intel 超線程技術虛擬出來的核心。可以看到,在高負荷的情況下,系統將負載均勻的分散到了所有的核心上,而負載較輕時系統則將負載主要放在了真實的物理核心上。

橫坐標軸為時間,縱坐標軸則為負載,時間從左到右逐漸靠近當時的情況

但 Apple Silicon 上的 CPU 則完全不同,它的處理器部分都是由兩種不同的 CPU 核心組成,一種是叫做 Firestorm 高性能核心(有時也被縮寫成 P 核),而另一種則叫做 Icestorm 高能效核心(有時也被縮寫成 E 核),這種不對稱的處理器被稱為 非對稱多處理(Asymmetric Multiprocessing,縮寫為AMP、ASMP)器,或是 異構計算(Heterogeneous Computing)處理器。

從 2020 年開始到今天, M1 系列共計發布了四款晶元,分別是:

  • M1 (2020 年)
  • M1 Pro 與 M1 Max (2021 年)
  • M1 Ultra (2022 年)

E 核心有 5 個頻率可以選擇,P 核心有 15 個頻率可以選擇

通過 powermetrics 我們可以知道 E 核心的頻率最高為 2064Mhz,P 核心的情況則分為兩種情況,M1 晶元的 P 核心最高頻率為 3204Mhz,M1 Pro/Max/Ultra 的 P 核心最高頻率可達 3228 MHz。如果系統還是和以前一樣將保持所有的核心負載相近,不僅會浪費 P 核心更多的中間檔位,也會讓跑在 E 核心上的程序明顯更慢。

此外,M1 和 M1 Pro/Max/Ultra 有完全不同的 E 核心和 P 核心組合,每個處理器還可以選擇不同的 CPU 數量,比如最基礎款的 14 inch MacBook Pro 上的 M1 Pro CPU 部分只有 6 個性能核和 2 個能效核,所以開發者如果需要手動適配「保持所有的核心負載相近」這個邏輯從直覺上來說異常繁瑣。

為了簡化核心管理,macOS 會將核心根據功能劃分為 2~4 個相同類型的集群,集群可以理解成組。然而,系統層面上的內核編號和 powermetrics 中顯示的內核編號相同,但和活動監視器中所顯示的內核編號卻並不一樣;因此為了行文統一,文中將採用活動監視器的內核編號規則,但根據系統集群進行編號。在 macOS Monterey 12.3.1 下, M1 系列的三組晶元的功能集群情況如下:

  • M1 分別由一個 E 集群(包含 4 個 E 核心)和一個 P 集群(包含 4 個 P 核心),並命名為 E 和 P0
  • M1 Pro/Max 則由一個 E 集群(包含 2 個 E 核心)和兩個 P 集群(分別包含 4 個 P 核心),並命名為 E、P0 以及 P1
  • M1 Ultra 則由一個 E 集群(包含 4 個 E 核心)和四個 P 集群(分別包含 4 個 P 核心),並命名為 E、P0、P1、P2 以及 P3

從理論上來講,一個集群內的所有核心都會在相同的頻率下運行,並且通常(但不總是)保持每一個集群內「核心的負載」大體相近。極端情況下甚至會發生系統一股腦兒地把所有的任務安排到某集群中的一個核心上。

比如 Logic Pro 導入素材就會出現這種極端情況

線程式控制制是如何進行的

實際應用開發中,macOS 並不提供公開的 API 讓應用程序直接使用具體的核心、核心類型或是集群;相反,應用程序通常由 Grand Central Dispatch 使用 QoS 管理,然後 macOS 會使用這些設置來確定具體線程的管理策略。

在實際情況中,QoS 最低的線程只會派發至 E 核集群,而較高的 QoS 的線程則可能會被派發到 E 或 P 核集群。儘管可以通過命令工具 taskpolicy 或者代碼中的函數 setpriority() 對派發進行動態修改,然而它卻只對較高的 QoS 線程有效。「最低 QoS 線程只在 E 集群上運行」的規則始終不變。

通過 macOS App Store 安裝 Xcode 的線程 QoS 就是最低的,完全不會使用 P 核

macOS 自身的策略是大部分後台任務都以最低的 QoS 運行。這當中包括了 Time Machine 的自動備份、Spotlight 索引更新以及 Archive Utility 的壓縮和解壓。這當中值得一提的是,對於 Archive Utility 很多人可能會有一個直觀的感受:下載了一個 xip 格式的 Xcode 副本,解壓的時候需要耗時 N 久,其實這就是很多代碼被限制在 E 核上運行所致,而且用戶也不能主動將它調往 P 核上運行。


後台線程(Background threads)

因為 M1 和 M1 Pro/Max 晶元上的 E 核集群大小不同,前者有 4 個 E 核,而後者只有 2 個,所以 M1 和 M1 Pro/Max 上的最低 QoS 線程的載入與運行方式是有不同之處的。

在擁有 4 個 E 核的 M1 晶元上運行 QoS 為 9 的線程時,每個 E 核核心頻率為 1000M(1 GHz)左右;而在只擁有 2 個 E 核的 M1 Pro/Max 中運行同樣 QoS 為 9 的線程時,如果只有 1 個線程那麼 E 核的運行頻率也同樣為 1000 MHz,但如果有兩個或者更多,那麼每個 E 核頻率就會增加到 2064 MHz。這樣的設計確保了即使集群大小不同,但 M1 Pro/Max 中 E 集群至少能提供和 M1 相同的後台任務處理性能。

當然這裡依然會有例外,像 backupd 這類擁有最低 QoS 的線程,在運行時如果同時受到來自 I/O 的限流,那麼即使是在 M1 Pro/Max 上也總會以約 1000MHz 的頻率運行。


用戶發起的線程(User threads)

所有 QoS 高於 9 的線程處理都大同小異,它們之間的區別無非就是它們的優先順序不同。高 QoS 的線程有資格運行在任何一種核心或者集群上,不過 M1 和 M1 Pro/Max 上的處理方式又有所不同。

在 M1 上,由於只有 1 個 P 集群和 1 個 E 集群,而物理核心總計有 8 個,因此同一時刻最多只有 8 個線程可以分配到這兩個集群上,每個集群均可以分到 4 個線程。如果同一時刻需要分配到線程數小於等於 4 時,系統會盡量將他們放在 P 集群上運行;除非當前隊列中有更多更高 QoS 級別的線程等待運行,這時才會額外使用 E 集群運行這類任務。在上述情況下, P 核心的頻率的最大值將為 3GHz,E 核心的頻率最大值則為 2GHz,是運行 QoS 為 9 的線程時的兩倍。

但 M1 Pro/Max 卻有 3 個集群,兩個分別擁有 4 個 P 核的集群,以及一個擁有 2 核的 E 集群。如果同一時刻需要分配到線程數小於等於 4 時,系統會主動將線程分為到第一個 P(P0) 集群上,第二個 P 集群將始終保持未載入和不活躍的節能狀態;如果同一時刻需要分配的線程多餘 4 時,多出來的線程(大於等於 5 個小於等於 8 個)將被分配到第二個 P(P1) 集群上;如果此時還有更多的線程(大於等於 1 個小於等於 2 個)等在運行,那麼這些進程將會再分配到 E 集群上。在上述情況下,P 核心的頻率的最大值將為 3228MHz,E 核心的頻率最大值則為 2064MHz。

M1 Ultra 晶元總共有 5 個集群,每個集群有 4 個核心。它們的策略大體與 M1 Pro/Max 相同,只不過在使用 E 集群之前,優先調用的是 4 個 P 集群。

不過,有兩種情況下,代碼似乎只在單個核心上運行:

第一種情況發生在引導過程中,在內核初始化並運行在其他核心之前,代碼只運行在單個 E 核上。另一種情況則發生在,下載完 macOS 更新以後處於「準備」階段時,在 M1 Pro/Max 晶元上,macOS 的 5 個更新線程僅僅被賦予了一個 P 核的活動駐留權利,即 2 個 P 集群中的第一個集群中的第一個(P0,下面標為核心 3 )。

在準備安裝更新的 30 分鐘內,這種不常見的的活動駐留一直都在。

負載模式下的圖形(Patterns under load)

這裡有幾個關於 macOS 策略影響調度的典型例子,這些例子取自活動監視器的 CPU 歷史窗口。

上圖顯示了 M1 晶元的一系列負載的情況,這些負載來自於逐漸增多的 CPU 密集型線程。上面提到過 M1 有兩個集群 E 和 P0,這裡分別用藍框進行劃分。從左開始,第 1~4 個高優先順序的進程的負載全部由 P0 集群承擔,而後續第 5~8 個進程的負載則逐步由 E 集群開始承擔。

這張圖則展示了重負載下 M1 Pro 不斷變化的負載情況,其中一些線程是後台進程,而另一部分則是高優先順序進程,雖然絕大部分的負載都由 E 集群承擔,但 P0 集群也承擔了不少負載,而 P1 集群主要被用來處理一些峰值負載。

最後一張圖則是 M1 Ultra 上的運行情況,作者本人已將對應的核心重新排列到了對應的集群中,其中 E 位於頂部,P0~P3 從第二排開始從左到右、從上到下依次進行排列。而圖中所示的負載則是一個非常典型的情況——系統登錄後的前幾分鐘,可以看到 E 和 P0 承擔了絕大多數時候的負載,而且在負載更重的時的初期,系統會將更多的任務調度到 P1~P3 剩下的 3 個 P 集群上,以更快得完成任務。

目前,活動監視器尚未提供一個關於 M 系列處理器的重要信息——集群頻率。在 CPU 處於 100% 負載時,此時相當於活動駐留,集群在頻率低於 1000MHz 時完成指令的速度不到頻率為 2064MHz 的相同集群的一半快。可惜的是,目前唯一可以獲得頻率信息的手段是命令工具 powermetrics。

下圖是一份 macOS 對 M1 、 M1 Pro 和 Max 晶元中 CPU 核心的管理概要。目前,關於 M1 Ultra 的信息尚在整理中,並在後續進行增補完善。如果你在用 M1 Ultra,熟悉並且願意提供幫助,歡迎與作者 Howard Oakley 博士進行聯繫。

今年 6 月,Apple (可能)會在 WWDC 大會上宣布其 M1 系列的後繼者。屆時,或將能夠看到它們的核心架構以及 macOS 提供的管理策略。

感謝 Walt 提供的關於 Ultra 的信息以及負載下的截圖。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 少數派 的精彩文章:

自己動手更換索尼電視主板,曲線救國實現 Homekit