苹果 Apple M1 芯片:Rosetta 2 转译技术

苹果公司于 2020 年末推出了三款搭载有 Apple M1 芯片(又称 Apple silicon)的 Mac 电脑。这种由 Apple 研发的处理器芯片与以往 Mac 搭载的 Intel 处理器存在处理器架构上的差异。Intel 推出的桌面处理器采用 X86 架构,使用 x86_64 指令集,而 Apple M1 芯片基于 ARM 架构,使用 arm64 指令集。指令集的差异使得为 x86_64 指令集编译的程序无法直接在基于 Apple M1 芯片上运行。

本文介绍了 Apple 公司于 macOS 中引入的一项被称为 Rosetta 2 的技术,这项技术能以一种变通的方式将为 Intel 处理器编译的程序运行于 Apple M1 芯片上。

Rosetta 2 是什么

Rosetta 2 是苹果于 macOS 上推出的指令集转译程序,它允许用户在 Apple silicon 上运行包含 x86_64 指令集的程序。由于为 Mac 编写的大多数应用程序通常为 Intel 架构的处理器设计,通过 Rosetta 2 这项技术,能够使用户在开发者未提供面向 Apple silicon 准备的程序时,变通地将这些程序运行于 Mac 中。

Apple 表示,Rosetta 2 并不是替代应用程序原生版本的方案,而只是为开发者准备调整到通用应用程序的过渡方案。

有一款可以运行于 Mac 上的生物学类软件亦名为 Rosetta,请读者不要将此混淆

对于用户来说,Rosetta 几乎是透明的(对用户无感知)。每当用户运行为 Intel 处理器构建的应用程序时,Rosetta 2 都会在后台运行。Rosetta 会自动转译 App 以便与 Apple 芯片搭配使用。当转译过程完成后,操作系统将为用户运行转译后的应用程序。转译程序的过程需要一定的时间,因此用户可能感觉需转译的应用程序启动速度比往常略慢。

通用应用

Apple 于 macOS Big Sur 中引入了名为“通用应用”的概念。这种类型的应用中同时包含为 Intel 处理器以及 Apple 处理器构建的程序。而搭载 Apple M1 芯片的 Mac 电脑则会在同时存在 arm64x86_64 指令集的程序时优先选择 arm64 指令集版本的程序。

图片版权所有,苹果公司,2020 年
本图片相信为处于教育目的而合理使用的屏幕截图
在 Finder “显示简介”中显示的通用应用程序,包含使用 Rosetta 运行的选项

出于避免未知缺陷的考虑,Apple 为通用应用程序提供了强制使用 Rosetta 而使用 x86_64 指令集的相应选项。在应用程序列表中,选择“显示简介”,并查看标有“种类”字样的信息:

  • 应用程序 (Intel) 表示 App 仅支持 Intel 处理器,并且需要 Rosetta 才能在任何搭载 Apple 芯片的 Mac 上运行
  • 应用程序(通用)表示 App 同时支持 Apple 芯片和 Intel 处理器,并且在默认情况下使用 Apple 芯片

若要对于通用应用程序优先使用 x86_64 指令集的版本,则应将“使用 Rosetta 打开”选项勾选,以使这些应用程序能够使用未被 arm64 架构支持的其他拓展功能。

Rosetta 2 转译的性能

自搭载 Apple M1 芯片的 Mac 设备上市以来,许多用户关注在 M1 芯片上运行 Intel 应用程序的速度问题。Apple 公司声称,在大多数情况下,使用 Rosetta 的 App 的性能不会出现任何差异。互联网中的一些实际测试表明通过 Rosetta 2 转译的应用程序的性能约为原生应用的 80% 左右。

哪些程序不能被 Rosetta 转译

Rosetta 能够转译绝大多数为 Intel 处理器构建的应用程序,其中包括含有即时编译(just-in-time,JIT)技术的编译器程序。然而,Rosetta 不能为下列应用程序转译:

  • 内核拓展程序
  • 虚拟 x86_64 平台的虚拟机程序

另外,Rosetta 无法支持 x86_64 指令集中提供的一些较新的指令集特性:包括 AVX、AVX2 与 AVX512 向量指令集。包含这些指令集的程序可能无法在搭载 Apple M1 芯片的设备上运行。

对于 macOS 开发者……

Apple 在开发者文档中提供了 sysctlbyname 函数用于检测这些向量指令集是否可用于用户的设备上。比如,要检测 AVX512 指令集在用户设备上是否可用,则需检查 hw.optional.avx512f 属性值。

另外,应用程序开发者能够使用 sysctlbyname 函数的 sysctl.proc_translated 标识符辨别应用程序是否经转译运行,Apple 开发者网站给出的示例代码如下:

int processIsTranslated() {
   int ret = 0;
   size_t size = sizeof(ret);
   if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) 
   {
      if (errno == ENOENT)
         return 0;
      return -1;
   }
   return ret;
}

拓展阅读