为什么苹果 M1 芯片会那么快?请看这份最详细易懂的技术指南(下)

神译局 · 2020-12-14
凭借着CPU逐渐显现的优势,苹果未来会蚕食PC市场更多的份额和利润。

神译局是36氪旗下编译团队,关注科技、商业、职场、生活等领域,重点介绍国外的新技术、新观点、新风向。

编者按:苹果今年最大的亮点也许不是手机,而是一块小小的芯片。M1发布会虽然已经过去了一阵子,但围绕着它的讨论依然不见平息。不过,对它的讨论很多都不在点子上,在技术方面解释得既不够深入也不够易懂。在这方面,Erik Engheim在Medium上发表的这篇文章也许是最详细最易懂的技术指南了。阅读本文,你将了解以下几点:1)为什么M1会这么快?2)苹果是不是用了什么独门绝招才做到这一点?3)英特尔和AMD能不能效仿?原文标题是:Why Is Apple’s M1 Chip So Fast?篇幅关系,我们分两部分刊出,此为第二部分。

划重点:

CPU提高性能的两种策略:要么跑快点,要么跑多点,但跑快点这条路已经走到尽头

跑多点也有两种策略:增加内核,或者乱序执行(OoO),苹果走的是后面这条路

AMD和Intel的乱序执行要比M1逊色

因为体系架构问题,英特尔和AMD没机会赶上苹果的CPU了

任何CPU想要快速运行都要面临的根本挑战

所以说,异构计算是部分原因,而不是唯一的原因。M1上面所谓的快速通用CPU内核Firestorm确实很快。跟过去与英特尔和AMD的内核相比较弱的ARM CPU内核相比,这是一个重大差异。

在对标中,Firestorm击败了大多数的英特尔内核,几乎击败了最快的AMD Ryzen内核。按照传统观点的话,这是不可能的。

在讨论是什么导致Firestorm跑得这么快之前,我们先要了解让CPU跑得快的核心思想是什么。

原则上,你可以结合以下两种策略来实现:

  1. 串行更快地执行更多的指令。

  2. 并行执行大量指令。

上世纪80年代的时候,做到这一点很容易。只需要增加时钟频率,指令就能加快完成。时钟周期是CPU工作的最小时间单位,是计算机执行某项操作的时候。不过这想操作可以是很微小的操作。所以,一条指令可能由多个较小的任务组成,因此可能需要多个时钟周期才能完成。

但是,现在再想提高时钟频率已经几乎不可能了大家嘴里反复絮叨的“摩尔定律的终结”真的来了。

所以,现在其实就剩下并行执行尽可能多的指令这条路了。

多核还是乱序处理器?

这条路也有两种走法。一种是增加更多的CPU内核。从软件开发者的角度来看,这就好比增加线程。每个CPU内核就像一个硬件的线程。如果你还不知道什么是线程,可以把它看作是执行任务的过程。一个CPU有两个内核的话,就可以同时执行两项单独的任务:两个线程。这些任务可以描述为两个独立的程序存储在内存当中,或者实际上也可以是同一程序执行两次。每个线程都需要做一些记录,比方说本线程目前在一系列程序指令当中的位置。每个线程都可以存储临时结果,而且应该是独立存放的。

原则上,只有一个内核的处理器也能跑多个线程。不过,在这种情况下,它只是把一个线程暂停并保存当前进程,再切换到另一线程运行。稍后再切换回来。这种做法并不能带来太多的性能增强,只是在线程可能经常要停下来等待用户输入,或者网络连接速度慢要等数据的时候使用。这些可以称之为为软件线程。硬件线程意味着拥有真正的额外物理硬件,比方说额外的内核,可以加快处理速度。

问题在于,开发者得会写代码来利用这种优势。其中的部分任务(比方说服务器软件)是很容易写的。你可以想象分别处理每一位连接用户。这些任务互相之间独立性太强了,以至于拥有大量内核是服务器(尤其是基于云的服务)的绝佳选择。

有128个内核的Ampere Altra Max ARM CPU专为云计算而设计,硬件线程多是其好处之一。

这就是为什么你会看到类似Ampere之类的ARM CPU制造商会制造像Altra Max这样的CPU的原因,这款处理器有着疯狂的128核!这种芯片是专门为云计算准备的。你不需要疯狂的单核性能,因为在云端,关键是在尽可能节能的情况下让尽可能多的线程来处理尽可能多的并发用户。

相比之下,苹果则处在另一端。苹果制造的是单用户设备。多线程并不是优势。他们的设备主要用来玩游戏,视频编辑,做开发等。他们希望台式机有漂亮的响应性好的图形和动画。

桌面软件一般不会用很多的内核。比方说,8核也许能让计算机游戏受益,但是像128核之类的东西完全就是浪费。相反,你需要更少但更强大的内核。

乱序执行的机制

有趣的来了,乱序执行。乱序执行可以并行执行更多指令但又不用做成多线程的方式。开发者不必专门写软件就能利用这种能力。从开发者的角度来看,似乎每个内核都跑得更快了。

要想了解其工作原理,你需要先了解一些有关内存的知识。请求访问内存特定位置的数据是很慢的。但是,获取1字节数据的时延跟获取128字节的数据的时延却没有分别。数据要通过我们所谓的数据总线来发送。你可以把数据总线看作是内存与数据通过的CPU不同部分之间的一条通道或管道,数据就是通过这条管道来传输的。实际上,当然那只是一些导电的铜线。如果数据总线足够宽的话,就可以同时存取多个字节。

所以,CPU一次会执行一大块的指令。但是是按照次序一条接一条地执行的。现代的微处理器则会做所谓的乱序操作(OoO )。

这意味着他们能够对指令缓冲区进行快速分析,弄清楚哪些指令依赖于哪个指令。不妨看看下面这个简单的例子:

01: mul r1, r2, r3    // r1 ← r2 × r3

02: add r4, r1, 5     // r4 ← r1 + 5

03: add r6, r2, 1     // r6 ← r2 + 1

乘法往往一般都很慢。可以这么说,乘法需要多个时钟周期来执行。第二条指令只能等,因为它的计算要取决于知道了放进r1寄存器的结果才行。

但是,第3行的第3条指令就不需要依赖于之前的指令的计算。所以,乱序处理器可以并行计算这条指令。

不过在现实当中我们谈论的是数百条指令。CPU能够找出这些指令之间的所有依赖关系。

它会通过查看每条指令的输入来对其进行分析。指令的输入是否取决于一或多条其他指令的输出?所谓的输入和输出,是指包含有之前计算结果的寄存器。

比方说,add r4,r1、5这条指令要依赖mul r1,r2,r3所输出的r1。我们可以把这些关系链接在一起,形成CPU可以处理的详细图谱。其中节点是指令,而边则是连接它们的寄存器。

CPU可以对这样的节点图谱进行分析,然后确定可以并行执行哪些指令,以及哪些指令中继续执行之前需要在什么地方等待多个相关计算的结果。

很多指令会早早就执行完毕,但我们没法对结果进行官宣。我们不能保证结果;否则的话,我们会以错误的顺序提供结果。在外界看来,它得看起来就像是按照发出的指令顺序执行的。

就像堆栈一样,CPU会从顶部弹出已完成的指令,直到找到未完成的指令。

这个解释还不够完善,但应该能提供一些线索了。基本上就是,你既可以实现程序员必须知道的那种并行性,也可以实现那种CPU假装是一切都是单线程执行的样子。不过,你知道,在幕后,它正在执行乱序的黑魔法。

正是出众的乱序执行能力使得M1的Firestorm内核可以狠狠地踢前作的屁股,扬名立万。实际上,它比英特尔或AMD的任何产品都要强大。可能比主流市场上的任何产品都要强大。

为什么AMD和Intel的乱序执行要比M1逊色?

在对乱序执行(OoO )的解释当中,我跳过了一些重要的细节,这里需要谈一下。否则的话,就没法理解为什么苹果能够在这场游戏当中领先,为什么英特尔和AMD可能没法赶上。

我所说的“scratchpad”实际上就是所谓的“重排序缓冲器(ROB)”,里面并不包含常规的机器代码指令。不是那种CPU从内存获取要执行的东西。这些是CPU指令集体系结构(ISA)里面的指令。就是那种我们称之为x86、ARM、PowerPC等的指令。

但是,在内部,CPU会用程序员看不到的完全不同的指令集。我们称之为微指令(micro-ops或μops )。ROB里面都是这些微指令。

对于CPU施展魔法来让东西并行运行来说,这个地方可以做的事情要实际得多。原因是微指令的范围很广(包含有很多的位),并且可以包含各种元信息。你没法把那种信息添加到ARM或x86的指令里面,而很多的元信息只有在当前执行的上下文之中才有意义。

我们可以这么看,就把它看作是你在写程序的时候。你有一个公共API,这个API需要保持稳定并且所有人都能用。ARM、x86、PowerPC、MIPS就是这样的指令集。而微指令基本上是用来实现公共API的专用API。

此外,对于CPU来说,微指令往往更易用。为什么?因为每一个微指令都只完成一项简单的有限任务。常规的ISA指令可能更复杂,导致会发生很多事情发生,最终会变成成多个微指令。

对于CISC CPU来说,往往别无选择只能用微指令,否则大型复杂的CISC指令会导致流水线和OoO几乎没法实现。

但RISC CPU就有得选。比方说,小一点的ARM CPU根本不用微指令。但这也意味着做不了类似OoO之类的事情。

但是这又有什么关系呢?为什么这个细节对于理解为什么苹果能够压倒AMD和英特尔非常重要呢?

那是因为CPU能跑多快要取决于往ROB装填微指令的速度以及数量。填充得越快,能选择出可以并行执行的指令的机会就越大,而并行执行则意味着性能的提高。

机器代码指令被所谓的指令解码器分解成微指令。如果能够有更多的解码器,我们就可以并行分解更多的指令,填充ROB的速度就可以更快。

在这一点上,苹果的M1跟其他的CPU有很大的差别。英特尔和AMD最大微处理器内核有四个解码器,也就意味着可以并行解码四条指令分解出微指令。

但是苹果却有着疯狂的8个解码器。不仅如此,它的ROB大概比别人大3倍。基本上相当于可容纳三倍规模的指令。其他主流芯片制造商的CPU没有一个有这么多解码器的。

为什么英特尔和AMD没法多加点指令解码器?

这就是RISC复仇的机会。而M1 Firestorm内核采用的是ARM RISC架构,这一事实开始变得重要起来。

你看,对于x86来说,一条指令的长度在1到15个字节之间。而在RISC芯片上,指令的长度是固定的。这种情况下固定长度为什么很重要呢?

因为如果每一条指令的长度都一样的话,把一连串字节分解成指令,并行输入给8个不同的解码器这件事就变得微不足道了。

但是,如果是x86 CPU的话,解码器都不知道下一条指令从哪里开始。它得分析每一条指令才能知道指令的长度。

英特尔和AMD采取的是暴力破解法,也就是在每个可能的起点对指令进行解码。这意味着会有很多猜错的时候,要把错误丢弃掉。这会造成解码器阶段十分复杂,绕来绕去,以至于很难再添加更多的解码器。但是对于苹果来说,相比之下增加更多的解码器根本不算事儿

实际上,添加更多解码器会导致很多的其他问题,以至于对AMD来说,4个解码器基本上就是上限了。

其结果是,在相同的时钟频率下,M1 Firestorm内核能处理的指令数量实际上是AMD和Intel CPU的两倍。

有人则认为,因为CISC指令可转化为更多的微指令,所以密度更大,这样一来,解码一条x86指令就类似于解码两条ARM指令。

只是在现实世界里面,情况并非如此。高度优化的x86代码很少会用复杂的CISC指令。才能够某种程度来说,它已经有点RISC风格了。

但这对英特尔或AMD毫无帮助,因为就算15字节长的指令很少见,造出来的解码器也得处理。而这会导致复杂性,从而阻碍AMD和Intel添加更多的解码器。

可是AMD的Zen3内核还是更快啊,不是吗?

据我所知,最新的AMD CPU内核,也就是所谓的Zen3内核在性能基准测试是要比Firestorm内核快一些。但问题是,这仅仅是因为Zen3内核的时钟频率为5 GHz。而Firestorm内核的时钟频率为3.2 GHz。虽然时钟频率提高了近60%,但Zen3也只是勉强比Firestorm快一点。

那苹果为什么不相应提高时钟频率呢?因为更高的时钟频率会导致芯片发热。但那却是苹果的主要卖点之一。跟英特尔和AMD的产品不同,他们的计算机几乎不需要制冷。

从本质上讲,可以说Firestorm内核确实优于Zen3内核。Zen3只能靠加大电流并变得更热来让自己保持领先。而苹果只是选择不这么做而已。

如果苹果想要提高性能的话,他们只只需要多加些内核就可以了。这样一来,他们既可以降低功耗,又能提供更高性能。

未来

似乎AMD和Intel在两个方面都陷入了困境:

  • 他们没有一个可以轻松从事异构计算和SoC设计的商业模式。

  • 他们传统的x86 CISC指令集反过来又给他们造成困扰,导致难以提高OoO性能。

当然,这并不意味着游戏结束了。他们是可以提高时钟频率,强化散热能力,增加更多内核,扩充CPU缓存等。但这些方面他们也都处于劣势。英特尔的情况最糟,一方面内核似乎已经被Firestorm击败,而且能跟SoC解决方案集成的GPU也很弱。

引入更多内核的问题在于,对于典型的桌面工作负荷来说,内核太多会导致收益递减。当然,大量内核非常适合服务器。

但是在这个领域,像Amazon和Ampere之类的公司正在用128核的怪兽CPU发动攻击。这就像是东线和西线同时开战。

不过对于AMD和Intel来说,幸运的是,苹果并没有直接卖自己的芯片。所以,PC用户只能接受他们提供的任何产品。PC用户可能会投奔曹营,但这会是一个缓慢的过程。用户不会马上离开自己自己投入了大量资金的平台。

但是,那些还没有在任何平台上面烧太多钱的年轻专业人,他们未来可能会慢慢地转向苹果阵营,扩大了后者在高端市场的份额,并因此进一步扩大其在PC市场所占的利润份额

延伸阅读:

苹果 M1 芯片,乔布斯的最后杀招

小小的 M1 芯片,也许决定了苹果的命运和未来

硬核技术文:如何自己动手做一个 CPU?

译者:boxi

+1
22

好文章,需要你的鼓励

参与评论
登录后才能参与讨论哦...
后参与讨论
提交评论0/1000

请回复有价值的信息,无意义的评论将很快被删除,账号将被禁止发言。

文章提及的项目

下一篇

网络占卜再精准也代替不了现实的温暖拥抱……

2020-12-14

36氪APP让一部分人先看到未来
36氪
鲸准
氪空间

为你推送和解读最前沿、最有料的科技创投资讯

一级市场金融信息和系统服务提供商

聚集全球最优秀的创业者,项目融资率接近97%,领跑行业