为什么苹果的M1芯片这么快?
新型M1 Mac的真实世界体验已经开始流行。它们的运行速度很快。真快。但为什么?魔术是什么?
上YouTube,我看到一位Mac用户去年购买了iMac。它已用完40 GB的RAM,花了他大约4,000美元。他难以置信地看着自己的超贵iMac被新的M1 Mac Mini拆毁了,他为此花了700美元。
在一次又一次的实际测试中,M1 Macs不仅超越了顶级的Intel Macs,而且还在销毁它们。人们难以置信地开始问这到底是怎么可能的?
如果你是一个O ˚F那些人,你来对地方了。在这里,我计划将其分解为易于消化的部分,就像苹果公司对M1所做的一样。具体来说,我认为很多人有以下问题:
- 此M1芯片如此之快的技术原因是什么?
- 苹果公司是否做出了一些真正具有异国情调的技术选择以实现这一目标?
- 像英特尔和AMD这样的竞争对手采用相同的技术技巧有多容易?
当然,您可以尝试使用Google,但如果您尝试了解苹果公司所做的工作,除了肤浅的解释,您将很快陷入技术高度专业的术语中,例如使用非常宽的指令解码器,巨大的重排序缓冲区(ROB)等的M1。除非您是CPU硬件的极客,否则很多都是“傻瓜”。但是,如果您愿意,我强烈推荐Andrei Frumusanu在AnandTech上的文章,该文章深入介绍了细节。多亏了他的辛勤工作和研究,我们才知道有关M1的许多重要技术细节。
为了充分利用这个故事,我建议阅读我之前的文章:“ RISC和CISC在2020年意味着什么?” 在这里,我解释什么是微处理器(CPU)以及各种重要概念,例如:
- 指令集架构(ISA)
- 流水线
- 加载/存储架构
- 微码与微操作
但是,如果您不耐烦,我将简要介绍您需要了解的材料,以帮助我理解M1芯片。
什么是微处理器(CPU)?
通常,当谈到英特尔和AMD的芯片时,我们谈论的是中央处理器(CPU)或微处理器。正如您可以在我的RISC vs. CISC故事中了解的更多内容一样,这些信息从内存中提取指令。然后,通常按顺序执行每个指令。
一个最基本的CPU是一种设备,它具有许多称为寄存器的命名存储单元和许多称为算术逻辑单元(ALU)的计算单元。ALU执行加法,减法和其他基本数学运算之类的操作。但是,这些仅连接到CPU寄存器。如果要相加两个数字,则必须从内存中获取这两个数字并放入CPU的两个寄存器中。
这是M1上的RISC CPU执行的一些典型指令示例。
加载r1,150
加载r2,200
加r1,r2
存储r1,310
这里r1
和r2
是我谈到的寄存器。现代RISC CPU无法对不在寄存器中的数字进行这样的操作。例如,它不能在两个不同位置的RAM中添加两个数字。相反,它必须将这两个数字放入一个单独的寄存器中。这就是我们在此简单示例中所做的。我们在RAM的存储器位置150处提取数字,并将其放入r1
CPU的寄存器中。接下来,我们将地址200的内容放入register r2
。只有这样,数字才能与add r1, r2
指令相加。
寄存器的概念是古老的。例如,在这个旧的机械计算器上,寄存器就是保存您要添加的数字的函数。术语收银机的起源。寄存器是您注册输入数字的地方。
M1不是CPU!
但是要了解M1,这是一件非常重要的事情:
M1不是CPU,它是将多个芯片放入一个大的硅封装中的整个系统。CPU只是这些芯片之一。
基本上,M1是将整个计算机集成到一个芯片上。M1包含一个CPU,图形处理单元(GPU),内存,输入和输出控制器,以及构成一台整体计算机的许多其他功能。这就是我们所说的片上系统(SoC)。
今天,如果您购买芯片(无论是从Intel还是AMD获得的),实际上可以在一个封装中获得相当于多个微处理器的数量。过去,计算机的主板上会在物理上分离多个芯片。
但是,由于今天我们能够在硅芯片上放置如此多的晶体管,因此英特尔和AMD等公司开始将多个微处理器集成到一个芯片上。今天,我们将这些芯片称为CPU内核。一个核心基本上是一个完全独立的芯片,可以从内存中读取指令并执行计算。
长期以来,就提高性能而言,这一直是游戏的名称:只需添加更多的通用CPU内核即可。但是,部队受到了干扰。CPU市场中有一个参与者偏离了这一趋势。
苹果并不是那么秘密的异构计算策略
苹果没有添加更多的通用CPU内核,而是采取了另一种策略:他们开始添加越来越多的专用芯片来完成一些专门的任务。这样做的好处是,专用芯片趋于使用比通用CPU内核少得多的电流来显着更快地执行其任务。
这不是完全新的知识。多年来,已经在Nvidia和AMD图形卡中放置了诸如图形处理单元(GPU)之类的专用芯片,它们执行与图形相关的操作要比通用CPU快得多。
苹果所做的只是简单地朝这个方向做出更大的转变。M1不仅具有通用内核和存储器,还包含各种专用芯片:
- 中央处理器(CPU)-SoC的“大脑”。运行操作系统和应用程序的大多数代码。
- 图形处理单元(GPU)-处理与图形相关的任务,例如可视化应用程序的用户界面和2D / 3D游戏。
- 图像处理单元(ISP)-可用于加速图像处理应用程序完成的常见任务。
- 数字信号处理器(DSP)-处理比CPU更复杂的数学功能。包括解压缩音乐文件。
- 神经处理单元(NPU)-在高端智能手机中用于加速机器学习(AI)任务。这些包括语音识别和相机处理。
- 视频编码器/解码器—处理视频文件和格式的节能转换。
- Secure Enclave-加密,身份验证和安全性。
- 统一内存-允许CPU,GPU和其他内核快速交换信息。
这就是为什么许多使用M1 Mac进行图像和视频编辑的人看到这样的速度提高的原因的一部分。他们执行的许多任务可以直接在专用硬件上运行。这样一来,廉价的M1 Mac Mini就能对大型视频文件进行编码而又不费吹灰之力,而昂贵的iMac却让其所有粉丝全力以赴,但仍无法跟上潮流。
阅读有关异构计算的更多信息:Apple M1预示了RISC-V的兴起。
苹果的统一内存架构有何特别之处?
苹果公司的“统一内存架构”(UMA)有点棘手(我第一次在这里写下来时就错了)。
为了解释原因,我们需要往后退几步。
长期以来,廉价的计算机系统已将CPU和GPU集成到同一芯片(相同的硅芯片)中。这些都是众所周知的缓慢。过去所说的“集成图形”与所说的“慢图形”基本相同。
这些由于某些原因而变慢的原因:
该内存的单独区域已预留给CPU和GPU。如果CPU想要让GPU使用大量数据,它就不会说“这里有我的一些内存”。不,CPU必须在GPU控制的存储区域上显式复制整个数据块。
CPU和GPU不希望它们的内存以相同的方式提供。让我们做一个愚蠢的食物类比:CPU希望服务员非常快速地提供他们的数据盘,但是它们却很酷,而且只有很小的一部分。想象一下一家豪华的法国餐厅,那里的侍者穿着溜冰鞋,可以为您提供快速服务。
相反,GPU很酷,服务员处理数据的速度很慢。但是GPU需要大量的食物。他们吞噬大量数据,因为它们是庞大的并行计算机,可以并行读取大量数据。想象一下一个美国垃圾食品店,那里的食物需要一些时间才能到达,因为他们正在将整车食物推到您的座位区。
面对如此不同的需求,将CPU和GPU放在同一物理芯片上并不是一个好主意。如果提供少量法国菜,GPU将坐在那里挨饿。结果是在SoC上放置功能强大的GPU毫无意义。弱小的GPU可以轻易地消耗掉服务的一小部分数据。
第二个问题是大型GPU会产生大量热量,因此您无法将它们与CPU集成在一起,而不会出现自行消除产生的热量的问题。因此,独立显卡往往看起来像下面的显卡:具有大型冷却风扇的大型野兽。它们具有专用的专用存储器,旨在为贪婪的卡提供大量数据。
这就是为什么这些卡具有高性能的原因。但是它们有一个致命的弱点:每当它们必须从CPU使用的内存中获取数据时,这种情况就会发生在计算机主板上的一组称为PCIe总线的铜走线上。尝试通过超薄吸管装满水。它可能很快进入您的嘴,但是吞吐量完全不足。
苹果的统一内存体系结构试图解决所有这些问题,而又没有老式共享内存的缺点。他们通过以下方式实现这一目标:
- 没有专门为CPU或GPU保留的特殊区域。内存分配给两个处理器。它们都可以使用相同的内存。无需复制。
- 苹果使用的内存既可以存储大量数据,又可以快速存储数据。用计算机的话来说,这就是所谓的低延迟和高吞吐量。因此,不需要连接到不同类型的存储器。
- 苹果降低了GPU的功耗,因此可以集成功能相对强大的GPU,而不会导致SoC过热。而且ARM芯片产生的热量更少,从而使GPU具有比与AMD或Intel CPU在相同硅芯片上的GPU更高的热量预算。
有人会说统一内存并不是全新的。的确,过去有不同的系统拥有它。但是,内存需求的差异可能不会那么大。其次,Nvidia所谓的统一内存并不是一回事。在Nvidea世界中,统一内存仅表示存在软件和硬件,它们负责自动在单独的CPU和GPU内存之间来回复制数据。因此,从程序员的角度来看,Apple和Nvidia统一内存可能看起来相同,但从物理意义上来说并不相同。
当然,在此策略中需要权衡取舍。要获得这种高带宽内存(大份量),需要进行完全集成,这意味着您没有机会从客户那里升级他们的内存。但是,Apple试图通过使与SSD磁盘的通信如此之快以使它们本质上像老式内存一样工作来最大程度地减少此问题。
如果SoC如此智能,为什么英特尔和AMD不复制这种策略?
如果苹果公司正在做的事情如此聪明,为什么不是每个人都这样做呢?在某种程度上,它们是。其他ARM芯片制造商越来越多地投入专用硬件。
AMD还开始在其某些芯片上安装功能更强大的GPU,并逐步采用加速处理单元(APU)向某种形式的SoC迈进,这些处理器基本上是CPU内核和GPU内核位于同一硅芯片上。
然而,有重要的原因使他们无法做到这一点。SoC本质上是芯片上的整个计算机。这使其更适合实际的计算机制造商,例如HP和Dell。让我用一个愚蠢的汽车类比澄清一下:如果您的业务模型是制造和销售汽车发动机,那么开始制造和销售整车将是一个不寻常的飞跃。
相比之下,对于ARM而言,这不是问题。戴尔或惠普等计算机制造商可以简单地授予ARM知识产权许可,并购买其他芯片的IP,以添加他们认为自己的SoC应该具有的任何专用硬件。接下来,他们将完成的设计运送到GlobalFoundries或TSMC等半导体代工厂,后者今天为AMD和Apple生产芯片。
在这里,我们遇到了Intel和AMD业务模型的大问题。他们的商业模式基于销售通用CPU,人们只需将其插入大型PC主板即可。因此,计算机制造商只需从不同的供应商那里购买主板,内存,CPU和图形卡,然后将它们集成到一个解决方案中即可。
但是我们正在迅速远离那个世界。在新的SoC世界中,您无需组装来自不同供应商的物理组件。而是从不同的供应商那里组装IP(知识产权)。您从不同的供应商那里购买了图形卡,CPU,调制解调器,IO控制器以及其他产品的设计,并将其用于内部设计SoC。然后,您将得到一个铸造厂来制造它。
现在您遇到了一个大问题,因为英特尔,AMD或Nvidia都不会将其知识产权许可给戴尔或惠普,让他们为自己的机器制造SoC。
当然,英特尔和AMD可能只是开始销售完整的成品SoC。但是这些包含什么?PC制造商可能对它们包含的内容有不同的想法。您可能会在英特尔,AMD,微软和PC制造商之间发生冲突,因为应包含哪种专用芯片,因为这些芯片需要软件支持。
对于苹果公司来说,这很简单。他们控制整个小部件。例如,它们为您提供了Core ML库,供开发人员编写机器学习内容。Core ML是在Apple的CPU上运行还是在Neural Engine上运行,是开发人员无需关心的实现细节。
使任何CPU快速运行的根本挑战
因此,异构计算是原因的一部分,而不是唯一的原因。M1上称为Firestorm的快速通用CPU内核确实非常快。与过去的ARM CPU内核相比,这是一个重大偏差,与AMD和Intel内核相比,ARM CPU内核往往非常脆弱。
相比之下,Firestorm击败了大多数Intel内核,几乎击败了最快的AMD Ryzen内核。传统观点认为这不会发生。
在讨论使Firestorm快速运行的原因之前,先要了解使快速CPU成为核心思想的真正意义。
原则上,您可以结合以下两种策略来完成任务:
- 依次执行更多指令。
- 并行执行大量指令。
上世纪80年代,这很容易。只要增加时钟频率,指令就会更快地完成。每个时钟周期都是计算机执行某项操作的时间。但是,这东西可以说是相当的小。因此,一条指令可能由多个较小的任务组成,因此可能需要多个时钟周期才能完成。
但是,如今几乎不可能提高时钟频率。这就是人们十多年来一直在努力的整个“摩尔定律的终结”。
因此,实际上是关于并行执行尽可能多的指令。
多核还是乱序处理器?
有两种方法。
- 添加更多的CPU内核。每个核心独立且并行地工作。
- 使每个CPU内核并行执行多个指令。
对于软件开发人员来说,添加内核就像添加线程。每个CPU内核都像一个硬件线程。
如果您不知道线程是什么,则可以将其视为执行任务的过程。一个CPU具有两个内核,可以同时执行两个单独的任务:两个线程。可以将任务描述为两个单独的程序存储在内存中,或者实际上可以是同一程序执行两次。每个线程需要一些簿记,诸如其中以程序指令序列的线程当前是。每个线程可以存储临时结果,应将其分开保存。
原则上,一个处理器只能有一个内核并运行多个线程。在这种情况下,它只是暂停一个线程并存储当前进程,然后再切换到另一线程。稍后它将切换回去。除非线程不得不经常停止执行以下操作,否则不会带来很多性能提升:
- 等待用户输入
- 网络连接速度慢等导致的数据
让我们称这些软件线程。硬件线程意味着您可以使用实际的物理CPU内核来加快处理速度。
线程的问题是软件开发人员必须编写所谓的多线程代码。这通常很困难。过去,这是最难编写的代码。但是,使服务器软件成为多线程往往很容易。这仅仅是在单独的线程上处理每个用户请求的问题。因此,在这种情况下,具有很多核心是一个明显的优势。特别是对于云服务。
这就是为什么您会看到诸如Ampere之类的ARM CPU制造商制造诸如具有疯狂的128核的Altra Max之类的CPU的原因。该芯片是专门为云计算的。您不需要疯狂的单核性能,因为在云中,每瓦特具有尽可能多的线程来处理尽可能多的并发用户。
阅读有关具有许多内核的ARM CPU的更多信息:Apple的服务器是否下一步?
相比之下,苹果则处于另一端。它们构成单用户设备。大量线程不是优势。他们的设备用于游戏,视频编辑,开发等。他们希望台式机具有精美的响应图形和动画。
桌面软件通常不会利用很多内核。例如,计算机游戏可能会受益于8个内核,但是像128个内核之类的东西将完全浪费。取而代之的是,您需要更少但更强大的内核。
乱序执行的工作方式
为了使内核更强大,我们需要它并行执行更多指令。乱序执行(OoOE)是一种并行执行更多指令但不将该功能公开为多个线程的方式。
有关替代解决方案,请阅读:超长指令字微处理器
开发人员不必专门编码其软件即可利用OoOE。从开发人员的角度来看,看起来每个内核的运行速度都更快。请注意,它不是硬件线程的直接替代方法。您要同时使用这两种方法,具体取决于要解决的特定问题。
要了解OoOE的工作原理,您需要了解有关内存的一些知识。在一个特定的内存位置中请求数据很慢。但是CPU能够同时获取多个字节。因此,在内存中获取1个特定字节所花的时间不会少于在该字节之后获取100个字节以上的时间。
这是一个类比:考虑仓库中的拣货员。可能是上图中的红色小机器人。移动到多个位置遍布各地需要花费时间。但是从彼此相邻的插槽中拾取物品很快。计算机内存非常相似。您可以快速获取相邻的存储单元的内容。
数据通过我们所谓的数据总线发送。您可以将其视为内存与数据被推送通过的CPU不同部分之间的一条通道或管道。实际上,当然只是一些导电的铜线。如果数据总线足够宽,则可以同时获取多个字节。
因此,CPU一次获取整条指令来执行。但是它们被编写为一个接一个地执行。现代微处理器可以执行我们所谓的无序执行(OoOE)。
这意味着他们能够快速分析指令缓冲区,并查看哪些指令取决于哪个指令。看下面的简单例子:
01:mul r1,r2,r3 // r1←r2×r3
02:加r4,r1,5 // r4←r1 + 5
03:加r6,r2,1 // r6←r2 + 1
乘法往往是一个缓慢的过程。可以这么说,它需要多个时钟周期才能执行。第二条指令仅需等待,因为其计算取决于知道放入r1
寄存器的结果。
但是,该行的第三条指令03
不依赖于先前指令的计算。因此,乱序处理器可以开始并行计算此指令。
但实际上,我们正在谈论数百条指令。CPU能够找出这些指令之间的所有依赖关系。
它通过查看每个指令的输入来分析指令。输入是否取决于一个或多个其他指令的输出?所谓输入和输出,是指包含先前计算结果的寄存器。
例如,add r4, r1, 5
指令取决于r1
产生的输入mul r1, r2, r3
。我们可以将这些关系链接在一起,成为CPU可以处理的详细图形。节点是指令,边是连接它们的寄存器。
CPU可以分析这样的节点图,并确定它可以并行执行哪些指令,以及在继续执行之前需要在哪里等待多个相关计算的结果。
许多指令将尽早完成,但我们无法将其结果正式化。我们不能承诺他们;否则,我们将以错误的顺序提供结果。对于世界其他地区,它看起来必须仿佛按照发出指令的顺序来执行。
就像堆栈一样,CPU将从顶部一直弹出完成的指令,直到命中未完成的指令。
基本上,您有两种形式的并行性:一种是开发人员在编写代码时必须显式处理的,另一种是完全透明的。当然,后者依赖于CPU上的许多晶体管,这些晶体管专门用于无序执行魔术。对于晶体管很少的小型CPU,这不是可行的解决方案。
正是出众的乱序执行能力使M1踢屁股上的Firestorm核心和举足轻重。实际上,它比Intel或AMD的任何产品都要强大得多,它们可能永远无法追赶。要了解原因,我们需要深入了解一些技术细节。