在大家了解了 M1 芯片表现之后,你肯定想一探究竟其底层核心是什么,本文将从异构计算开始讲起。苹果非常热衷于添加多个专用硬件单元的策略,在本文中,我将其称为协处理器(coprocessor):
- 图形处理单元(GPU),用于图形处理以及其他需要并行处理大量数据的任务(即同时对多个元素执行相同的操作)。
苹果没有在解决方案中添加更多的通用处理器,而是添加了更多的协处理器。你可以称之为加速器。这种趋势并不是新出现的,我从 1985 年开始使用的老式 Amiga 1000 就使用协处理器来加快音频和图形处理的速度。现代 GPU 本质上就是协处理器。Google 的 Tensor 处理单元也是一种用于机器学习的协处理器。
图:Google TPU是专用集成电路(ASIC),我们称之为协处理器。
什么是协处理器?
与 CPU 不同,协处理器不能单独存在。只使用协处理器无法造出计算机。协处理器作为专用处理器,可以很好地完成某些特定的任务。最早的协处理器当属英特尔 8087 浮点单元(FPU)。英特尔的 8086 微处理器可以执行整数运算,但不能执行浮点运算。这两者的区别是什么?
图:英特尔 8087,最早的执行浮点计算的协处理器之一。整数都是这样的数字:43、-5、92、4。对于计算机来说,处理这些数字比较容易。你可能只需要将一些简单的芯片组合在一起,就能处理整数加法。假设你需要执行小数的加法或乘法:4.25、84.7 或 3.1415。这些是浮点数。如果小数点后面的位数是固定的,则我们称之为定点数。金钱通常都保留两位小数,因此都是通过定点数处理的。然而,你可以使用整数来模拟浮点运算,只不过速度会比较慢。与之类似,早期的微处理器只能处理整数的加法,不能处理乘法。但是,它们仍然可以执行乘法,因为你只需要通过多次的加法来模拟乘法。例如 3×4 = 4 + 4 + 4。理解下面的示例代码并不重要,但是可以帮助你理解 CPU 如何通过加、减和分支(代码跳转)来执行乘法。loadi r3, 0 ; Load 0 into register r3
multiply:
add r3, r1 ; r3 ← r3 + r1
dec r2 ; r2 ← r2 - 1
bgt r2, multiply ; goto multiply ifr2 > 0
简而言之,你可以通过重复简单的运算来实现更复杂的数学运算。所有协处理器的工作方式都与之类似。CPU 总有方法完成协处理器的任务。但是,通常这都需要重复多个更简单的操作。我们之所以使用 GPU,是因为对数百万个多边形或像素重复相同的计算,对于 CPU 来说确实很耗时。
如何与协处理器来回传输数据
我们来看一看下面的示意图,以更好地了解协处理器如何与微处理器(CPU)或通用处理器的协同工作。
数字沿彩色线移动。输入/输出可以是协处理器、鼠标、键盘以及其他设备。我们可以将绿色和浅蓝色的公共总线视为管道。数字通过这些管道推送到 CPU 的不同功能单元(图中为灰色盒子)。这些盒子的输入和输出连接到了管道。你可以认为每个盒子的输入和输出都带有阀门。红色控制线可用于打开和关闭这些阀门。因此,负责红线的解码器(Decoder)可以打开两个灰色盒子上的阀门,让数字在它们之间流动。
图:你可以将数据总线视为管道,而红色控制线则负责打开和关闭阀门。但是,在电子设备中,这是通过我们所谓的多路复用器完成的,而不是实际的阀门。如果想执行数字运算,则首先需要将数字放入寄存器中。解码器使用控制线打开灰色盒子“内存”和“寄存器”之间的阀门。具体操作为:
- 解码器打开负载存储单元(LSU)上的阀门,内存地址从绿色地址总线上流出。
- 打开内存盒上的阀门,这样它就可以接收地址了,而地址由绿色管道(地址总线)负责传送。所有其他阀门都关闭,这样输入/输出就无法接收地址。
- 选中地址指定的内存单元。然后解码器会打开通往数据总线的阀门,这样选定内存单元的内容就会流出到蓝色数据总线上。
- 内存单元的数据可以流到任何地方,但是解码器仅打开了寄存器的输入阀门。
鼠标、键盘、显示器、GPU、FPU、神经引擎和其他协处理器都是“输入/输出”盒子。访问方式与访问内存一样。硬盘驱动器、鼠标、键盘、网卡、GPU、DMA(直接内存访问)和协处理器都被映射到自己的内存地址。举个例子,如果处理器尝试从内存地址 84 读取数据:鼠标的 x 坐标,而 85 代表鼠标的 y 坐标。因此,为了获取鼠标坐标,你可以通过汇编代码中执行以下操作:load r1, 84 ; get x-coordinate
loar r2, 85 ; get y-coordinate
对于 DMA 控制器,可能地址 110、111 和 113 有特殊的含义。下面这些伪汇编代码可以使用这些地址与 DMA 控制器进行交互:loadi r1, 1024 ; set register r to source address
loadi r2, 50 ; bytes to copy
loadi r3, 2048 ; destination address
store r1, 110 ; tell DMA controller start address
store r2, 111 ; tell DMA to copy 50 bytes
store r3, 113 ; tell DMA where to copy 50 bytes to
当然,一般软件开发人员不需要知道这些,这些工作都是由设备驱动程序完成的。你使用的程序无法真正看到这些不可见的虚拟内存地址。但是,驱动程序会将这些地址映射到其虚拟内存地址。
本质上,我们拿到的是真实的地址。绿色总线上的地址将从虚拟地址转换为实际物理地址。当我在 DOS 中编写 C/C++的程序时,就不会遇到这种情况。我可以将 C 指针直接指向视频的内存地址,然后直接修改图片。char *video_buffer = 0xB8000; // set pointer to CGA video buffer
video_buffer[3] = 42; // change color of 4th pixel
协处理器的工作方式与此相同。神经引擎、GPU、安全协处理器(Secure Enclave)都拥有可以与之通信的地址。你需要了解这些,同时也需要了解 DMA 控制器可以异步工作。这意味着 CPU 可以为神经引擎或 GPU 安排一整套指令,并将它们写入内存的缓冲区。然后,通过与 IO 地址的对话,将这些指令的位置通知给神经引擎或 GPU 协处理器。你肯定不希望 CPU 处于空闲状态,等待协处理器仔细检查所有指令和数据。你也不想让 DMA 遇到这种情况。这就是为什么一般我们都需要使用某种中断的原因。
中断如何工作?
你插入到 PC 的各种卡,无论是显卡还是网卡,都将分配一些中断线。就像一条直接插入 CPU 的线。这条线被激活后,CPU 就会放下手头所有的工作来处理中断。更具体地说,CPU 会将自己的当前位置及其寄存器的值存储在内存中,以方便回头可以随时返回之前的工作。接下来,CPU 会查看中断表需要做什么。这个表存储了中断被触发时需要运行的程序的地址。作为程序员,你很少看见这些东西。对你来说,你看到的更多的是某些事件注册的回调函数。这些底端的问题一般都是由驱动程序处理的。我之所以唠叨了这么多,就是希望帮助你了解使用协处理器时究竟发生了什么。否则,你就搞不清楚协处理器实际上需要进行哪些通信。我们可以通过中断并行处理很多任务。当 CPU 被计算机鼠标中断时,应用程序可以通过网卡获取图像。鼠标移动时,我们需要新的坐标。CPU 可以读取这些并将其发送到 GPU,然后在新位置上显示鼠标光标。当 GPU 绘制鼠标光标时,CPU 可以趁这段时间处理从网络检索到的图像。就像使用这些中断一样,我们也可以将复杂的机器学习任务发送给 M1 神经引擎,要求它通过网络摄像头设别人脸。同时,计算机的其余部分依然在响应,因为在神经引擎处理图像数据期间,CPU 正在处理其他工作。
图:SiFive 的基于 RISC-V 的主板,能够运行 Linux
RISC-V 的崛起
早在 2010 年,加州大学伯克利分校的并行计算实验室就大量使用了协处理器。他们预见了摩尔定律的终结,意味着我们无法再从通用 CPU 核心压榨出更多性能。我们需要专用的硬件:协处理器。我们来反思一下为什么。我们知道增加时钟频率并不容易。我们一直徘徊在 3–5 GHz,无法突破。进一步增加时钟频率,那么功耗和散热就会出问题。但是,我们可以添加更多的晶体管。只是我们无法加快晶体管的工作速度。因此,我们需要并行处理很多工作。一种方法是添加大量通用核心。正如我之前讨论的那样,我们可以添加很多解码器并执行乱序执行。
晶体管预算:CPU 核心还是协处理器?
我们可以无止境地增加 CPU 核心,最后就会得到 Ampere Altra Max ARM 处理器之类 128 个通用核心的处理器。但这真的是芯片的最佳用法吗?对于云服务器而言,这个方法没问题。我们可以通过 128 个核心处理各种客户端请求。但是,台式机系统可能甚至无法有效地利用普通台式机工作负载上的 8 个以上的核心。因此,即便你拥有 32 个核心,其实大部分也都被浪费了。既然不能增加更多 CPU 核心,那么,我们可以添加更多的协处理器吗?我们来算一笔账:你有一个晶体管预算。早先,也许你有 2 万个晶体管的预算,你发现可以利用这些晶体管制造出具有 1.5 万晶体管的 CPU。这与 80 年代初的真实情况很相似。现在,这个 CPU 可以执行 100 个不同的任务。假设为其中一项任务制作专用的协处理器,将花费 1000 晶体管。如果你为每一个任务创建一个协处理器,那么就需要 10 万个晶体管。这会超过你的预算。
过多的晶体管改变了策略
因此,早期的设计需要专注于通用计算。但是今天,我们的芯片中可以塞入太多的晶体管,但却不知道该用这些晶体管做什么。制作各种新型协处理器的相关研究很多。然而,这些研究经常会造出非常笨拙的加速器,我们需要加以制止。与 CPU 不同,它们无法读取自己需要执行的指令步骤。一般,它们都不知道如何访问内存或组织任何事情。因此,常见解决方案是将一个简单的 CPU 作为一种控制器。因此,整个协处理器都是由一个简单的 CPU 控制的专用加速器电路,CPU 负责配置加速器完成工作。通常这都是高度专业化的工作。例如,神经引擎或张量处理单元等处理的是非常大的寄存器,可以容纳矩阵。
通过量身定制的 RISC-V 控制加速器
这正是 RISC-V 的设计初衷。它仅有约 40–50 条指令的最低限度指令集,可以完成所有常见的 CPU 工作。听起来可能很多,但别忘了,x86 CPU 包含 1500 多个指令。RISC-V 不需要一套大型的固定指令集,它是围绕扩展的概念设计的。每个协处理器都是不同的。因此,它将包含一个 RISC-V 处理器来管理核心指令集的实现,以及根据协处理器需要处理的任务而定制的扩展指令集。苹果 M1 芯片就在推动整个行业朝着协处理器主导的未来发展。而在协处理器的制造中,RISC-V 将成为重要的一环。为什么?制作协处理器的人不能发明自己的指令集吗?不过,我认为苹果已经做到了,或者可能他们使用了 ARM,我不清楚。如果有人知道,请在下方留言。
坚持在协处理器中采用 RISC-V 有什么好处?
制造芯片已成为一件复杂而耗费巨大的工作。我们需要建立验证芯片的工具,运行测试程序,运行诊断程序,以及其他很多的事情都需要付出努力。这是当前使用 ARM 的优势之一。他们拥有庞大的工具生态系统,可以帮助你验证设计,并测试芯片。因此,寻求定制的专有指令集并不是一个好主意。但是,使用 RISC-V 可以为多家公司提供标准工具。就好像突然出现了生态系统,然后由多家公司共同负担。那么,为什么不能使用已有的 ARM 呢?ARM 主要面向通用 CPU。它拥有大型的固定指令集。在客户和 RISC-V 竞争的压力下,ARM 放低了姿态,并于 2019 年开放了扩展指令集。但是,问题仍然存在,因为当初它的设计初衷不在于此。整个 ARM 工具链会假定你已经实现了整个大型 ARM 指令集。这对于 Mac 或 iPhone 的主 CPU 来说没什么问题。但是对于协处理器,你不想要或不需要这么大的指令集。你只需要一个围绕基础固定扩展指令集而构建的工具生态系统。为什么这样会有好处?Nvidia 使用 RISC-V 的方法为我们提供了一些思路。在大型 GPU 上,他们需要某种通用 CPU 作为控制器。但是,为此目的保留的晶体管数量以及允许为此产生的热量都是有限的,并将产生的热量降到最低。请记住,有很多晶体管在争夺芯片这片狭小的空间。由于 RISC-V 的指令集又小又简单,因此它击败了包括 ARM 在内的所有竞争对手。Nvidia 发现,选择 RISC-V 可以制造出比其他任何产品都小的芯片,而且还可以将功耗降至最低。因此,你可以通过这种扩展机制,只添加对完成必须的工作至关重要的指令。而对于 GPU 的控制器,除了加密协处理器上的控制器以外,还需要其他扩展。
ARM 将成为新一代 x86
具有讽刺意味的是,我们可能会看到未来 Mac 和 PC 都由 ARM 处理器来驱动。但是,周边所有的定制硬件,所有协处理器都将由 RISC-V 主导。随着协处理器变得越来越流行,运行 RISC-V 的单片系统(SoC)的数量可能会超过 ARM。
ARM 指挥的 RISC-V 协处理器大军
通用 ARM 处理器将成为 RISC-V 驱动的协处理器的中心,从图形、加密、视频编码、机器学习、信号处理到处理网络程序包,所有任务都可以得到加速。加州大学伯克利分校的教授 David Patterson 和他的团队预见了这一未来,而且这也是经过精心设计后的 RISC-V 完全可以适应这个新世界的原因。我们看到 RISC-V 在各种专门的硬件和微控制器中都得到了广泛的应用和关注,我认为如今 ARM 主导的许多领域都将归入 RISC-V 旗下。
图:树莓派 4 微控制器,当前使用的是 ARM 处理器。试想一下树莓派等设备,如今运行的都是 ARM,但是将来树莓派的 RISC-V 版本可能会提供能够满足各种需求的变体。有些是机器学习微控制器,有些面向图像处理,而有些则用于加密。简单来说,你可以挑选自己的带有微调功能的微控制器。当然,你可以在其上运行 Linux,并执行所有相同的任务,只是性能会有所不同。带有特殊机器学习指令的 RISC-V 微控制器训练神经网络的速度将远远超过带有视频编码指令的 RISC-V 微控制器。英伟达的 Jetson Nano 已经走上这条冒险之路,如下图所示。这款微控制器只有树莓派那么大,拥有机器学习的专用硬件,因此,你可以利用它执行对象检测、语音识别以及其他机器学习任务。
将 RISC-V 作为主 CPU?
许多人可能想问:为什么不用 RISC-V 完全替代 ARM?尽管有些人认为这根本无法实现,因为 RISC-V 拥有一套“精巧又简单”的指令集,无法提供 ARM 和 x86 的高性能。实际上,你可以将 RISC-V 作为主处理器。性能并不是问题。就像使用 ARM 一样,我们只需要有人来制作高性能 RISC-V 芯片。实际上,已经有人制作出了这样的芯片:新的 RISC-V CPU 宣称性能已创纪录。人们常常有一个误解:复杂的指令可以提供更高的性能。RISC 工作站在 90 年代就证明了这是错误的想法,它们在性能基准测试中彻底击败了 x86 计算机。实际上,RISC-V 有很多巧妙的方法来提高性能。简而言之,你完全可以将 RISC-V 处理器作为主 CPU,但这也是一个时机的问题。MacOS 和 Windows 都采用了 ARM。至少在短期内,微软或苹果是否会再次投资硬件以支持 RISC-V 似乎很值得怀疑。
总 结
有人声称 RISC-V CPU 在功耗和性能方面已经超过了 ARM。人们纷纷在讨论,RISC-V 是否确实有可能成为计算机的主 CPU。我必须承认,我不清楚为什么 RISC-V 会超过 ARM。而且他们自己也承认, RISC-V 是一个非常保守的设计,其中并没有使用太多新的指令。但是,采用最小指令集确实有优势。我们可以实现非常小且非常简单的 RISC-V CPU,同时功耗会降低,而时钟频率可以提升。因此,关于 RISC-V 和 ARM 的最终结论还为时尚早。
原文链接:https://erik-engheim.medium.com/apple-m1-foreshadows-risc-v-dd63a62b2562
原文标题:Apple M1 foreshadows Rise of RISC-V
作者:Erik Engheim,现居挪威,热衷于 UX、Julia 编程、科学与写作。