在传统的多核心处理器中(比如之前Mac型号使用的英特尔CPU),所有的核心都是相同的。将线程分配给核心时,只需要平衡它们的负载即可,这种方式叫做对称式多处理(symmetric multiprocessing,SMP)。
在活动监视器的“CPU历史”窗口中,核心负载(即CPU%)是根据时间显示的,最早的值显示在最左侧。左半边奇数序号的核心是真实的核心,显示了一个8核心英特尔至强W在大负载下的情况。右侧的偶数序号的核心是超线程模拟的虚拟核心,也负责处理大负载。
但苹果芯片的CPU不一样,因为它包含两种不同的核心类型,一种用于高性能(称为性能核心、P核心或Firestorm核心),另一种用于低功耗(称为效率核心、E核心或Icestorm核心)。为了提高效率,线程需要根据核心类型进行分配。这个分配工作可以由应用程序和进程自己控制,比如Asahi Linux;也可以由操作系统负责,比如macOS。在本文中,我们就来看一看macOS是如何管理苹果M1芯片上的核心分配的。这种管理方式叫做非对称式多处理(AMP,不过有人喜欢叫它异质计算)。
1、架构
M1系列芯片的CPU核心有两种:
-
E核心,其内部处理单元大约为P核心的一半,最大时钟频率为2064MHz。
-
P核心,拥有更高的最大频率,原始M1为3204MHz,M1 Pro/Max/Ultra为3228MHz。
M1系列芯片的CPU核心配置方式有三种:
-
原始M1包含4个E和4个P核心,用于MacBook Air、13寸MacBook Pro、iMac和Mac mini
-
M1 Pro和Max有2个E和8个P核心,用于14寸和16寸MacBook Pro和Mac Studio Max。
-
M1 Ultra有4个E和16个P核心,用于Mac Studio Ultra。
一些14寸MacBook Pro笔记本使用了缩水版的M1 Pro芯片,其P核心数量从8个降为6个。
为了简化核心管理,macOS按照功能将核心分成簇,每个簇包含2~4个同类型的核心。可惜,系统级别的核心编号(如powermetrics等工具显示的核心编号)和活动监视器中看到的核心编号是不一样的。为了与后者一致,此处我们采用了活动监视器中看到的核心编号,但簇的编号还是与系统的方式一致。在macOS Monterey 12.3.1中,三个芯片的功能簇如下:
-
原始的M1中,每种类型的核心只有一个簇,分别为E0和P0,每个簇包含同一类型的4个核心;
-
M1 Pro和Max有一个簇(E0)包含两个E核心,两个簇(P0和P1)分别包含4个P核心;
-
M1 Ultra有一个簇(E0)包含4个E核心,四个簇(P0、P1、P2、P3)分别包含4个P核心。
每个簇中的所有核心都运行在同一时钟频率下,而且通常(但并非所有情况下)会保持簇内的负载平衡。偶尔,负载分配会不均匀,某些极端情况下,一些线程可能会被分配到簇内的单一核心上。
2、线程控制
与Asashi Linux不同,macOS并不支持直接访问核心、核心类型或簇,至少公开的API并没有提供这些功能。通常,它们需要通过服务质量(QoS)设置中的Grand Central Dispatch来管理,macOS使用该功能来决定线程管理的策略。
最低QoS的线程只会在E簇上运行,而更高QoS的核心可以分配到E或P核心商。后者的行为可以通过taskpolicy命令行工具或setpriority()函数动态修改。这些工具可以限制高QoS线程只能在E和核心上运行,也可以在E或P核心上运行。但是,它们并不能改变最低QoS线程的规则,这些线程只能在E核心上运行。
macOS本身采用的策略是绝大部分后台任务都以最低QoS运行。这些任务包括自动的时间机器备份、Spotlight索引维护等。归档工具(Archive Utility)的压缩和解压缩任务也在其中,例如,如果下载了xip格式的Xcode,解压缩就会花费很长时间,因为代码只能在E核心上运行,而且没办法改变。
3、后台线程
最低QoS线程在原始M1和M1 Pro/Max芯片上的加载和运行方式不同,因为两者的E簇大小不一样。
原始的M1芯片有4个E核心,因此QoS 9的线程运行时,时钟频率会设置为大约1000MHz(1GHz)。而只有两个E核心的M1 Pro/Max采用了不同的做法:如果只有一个线程,则以1000MHz左右的频率在簇上运行,但如果有两个或更多线程,则频率提高到2064MHz。这样可以保证M1 Pro/Max的E簇能在簇大小不同的情况下,用差不多的功耗,提供至少相当于原始M1的后台任务性能。
一个常见的例外是,某些拥有最低QoS的线程的进程(如backupd)还会受到I/O的制约,这样的线程在M1 Pro/Max上会以1000MHz的频率运行。
4、用户线程
所有QoS高于9的线程的处理方式都差不多,但队列的优先级不同会导致不同的结果。
由于高QoS的线程可以在任意类型的簇上运行,因此M1和M1 Pro/Max的管理方式不一样。原始的M1只有一个P簇,因此每次最多可以将8个线程分配到两个簇上,每个簇运行4个线程。当线程数小于等于4个时,就会尽量全部分配到P簇上运行,只有当队列中存在更多高QoS线程时才用到E簇。P核心的执行频率大约为3GHz,而E核心为2GHz,大约是运行QoS 9线程时的频率的两倍。
M1 Pro和Max芯片一共有三个簇,其中两个簇每个包含4个P核心,另一个簇包含两个E核心。队列里的前4个线程会分配到第一个P簇(P0);如果存在线程5~8,就会分配到第二个P簇(P1),否则第二个P簇空闲,以降低功耗。如果队列中还有更多线程,就会分配到E核心上。每种核心类型的最大频率分别为:P0、P1为3228MHz,E0为2064MHz。
M1 Ultra芯片一共有五个簇,每个簇有四个核心。其策略和M1 Pro/Max芯片一样,但会在所有四个P簇都被使用的情况下才会使用E0。
但是有两种情况,代码看起来像是仅在一个核心上运行:在引导过程中,操作系统内核初始化并运行其他核心之前,代码只会在一个活跃的E核心上运行。另一种情况是在安装macOS更新之前、“准备”下载更新的时候。在M1 Pro/Max芯片上,五个线程分配到相当于一个核心的资源,因此可以看到CPU使用率为100%,但被限制到一个P核心上,即第二个P簇(P0)中的第一个核心(下图中的Core 3)。
这种不寻常的活跃核心分配情况在安装更新之前的准备阶段一直持续30分钟左右。
5、高负荷的情况
下图来自活动监视器的CPU历史窗口,反映了更一般情况下macOS的策略效果。
上图是原始M1芯片,逐渐增加大量占用CPU的线程数目时的情况。它的两个簇E0和P0由蓝色的框标识。从左往右看,当只有高QoS的线程1~4时,负载完全被分配到P0簇上,然后线程5~8会占用E0簇。
上图是M1 Pro芯片在高负载下的情况,负载来自多个线程且不断变化,一些线程是后台QoS,一些是高QoS。大部分负载都分配到了E0簇的两个核心中,P0也在大部分时间内处于满状态,而在高峰时期会用到P1。
上图是M1 Ultra的情况,我按照簇重新排列了核心,顶端是E0,下面的两列分别为P0~P3。图中的负载是在登录之后几分钟内的典型负载,E0和P0上有大量负载,而前期负载较高时会分配到P1~P3上。
需要注意的一点是,活动监视器中并没有提供有关M1核心的簇频率的信息。在小于1000MHz频率下占用100%CPU的簇(相当于活跃状态)的核心上执行指令时,其速度只有以2064MHz频率下占用100%CPU的簇的一半。不幸的是,这个信息只能通过命令行工具powermetrics获得。
下图给出了macOS对于原始的M1、M1 Pro和Max芯片的CPU核心的管理方式。
苹果将在六月初的WWDC上公布M1系列的后续产品,我们很期待看到macOS管理M1芯片所用的核心架构和策略。
原文链接:https://eclecticlight.co/2022/04/25/how-macos-manages-m1-cpu-cores/
声明:本文为 CSDN 翻译,未经授权,禁止转载。