去年年底发布的基于 Apple Silicon 的 Mac 掀起了一阵新闻报道热潮,机器的性能也让人大吃一惊。本文详细介绍了将 Firefox 移植到这些 CPU 上以原生运行的经验背景。
我们将从 Mac 转型的一些背景信息开始,概述 Firefox 内部需要了解的新架构,然后介绍通用二进制的概念。
然后我们将解释 DRM/EME 如何在新平台上工作,谈论我们对 macOS Big Sur 的体验,并讨论我们必须处理的各种更新问题。最后我们将介绍发布版本,并概述正在进行中的各种其他改进。
Apple Silicon 即将到来
关于苹果将 Mac 产品线切换到 ARM CPU 的猜测在行业内已经持续了几年。早在 2013 年,苹果公司就将他们放在 iPhone 上的定制 ARM 芯片称为“桌面级”设计。
虽然这一说法最初遭到了一些质疑,但在 2018 年年底,计算机硬件杂志 AnandTech 公布了在 iPhone XS 上运行行业标准 SPEC 基准测试的结果,显示出即使是反映现实世界桌面用例的工作负载也达到了桌面芯片的性能,而且在功耗效率方面也显著提高。这给了我们一些预警,表明苹果可能准备在不久的将来开始向 ARM 架构过渡。
从 Mozilla 平台团队的角度来看,macOS 上架构变化的重点领域之一是 Firefox 对 macOS API 的使用。Firefox 和 Gecko 的根源可以追溯到 Netscape 代码库,该代码库早在 1994 年就支持了 Mac。
尽管不断更新,Firefox 仍然使用大量 macOS API,这些 API 随着 Mac 的发展而演变(Carbon、Cocoa、HITheme、Quartz,等等)。
苹果通常会保留它们——毕竟代码还在那里并且可以工作——甚至在某些行为发生变化的地方添加了兼容性 shim。但他们并不愿意永远保留兼容性,事实上在之前的 macOS Catalina 中已经删除了 32 位支持,这影响了依赖它的应用程序,其中包括许多游戏。
因此,我们担心并非所有 API 都将在新架构上得到支持,我们必须立即重写一部分小部件、工具包或主题代码。
根据上述基准测试的性能和苹果的发布历史,平台团队在 3 月份估计“macOS 10.16”可能会在 2020 年 9 月或 10 月左右发布,并且存在重大风险,即为了添加 ARM 支持而进行 API 更改,我们在计划中考虑了这一点。
发布公告
2020 年 6 月 22 日,苹果公司确认将开始将其 Mac 硬件转移到他们自己的 ARM 芯片上——被称为 Apple Silicon。他们还确认这些机器将搭载 Intel x64 模拟器(Rosetta 2)并支持 iOS 应用。
后者导致 Mozilla 平台团队内部猜测新 Mac 是否会有触摸屏。虽然我们当时——而且现在仍然——做好了支持它的准备,但至少最终的第一个基于 Apple Silicon 的 Mac 没有配备触摸屏。
随着过渡公告的发布,苹果还宣布了开发者过渡套件 (DTK) 的可用性,实际上包含 iPad Pro 的芯片,放在 Mac Mini 的外壳里。苹果没有分享的是最终机器何时上市。
根据 DTK 可用时间和苹果暗示的“年底前”发布,我们猜测这很可能是在圣诞节假期前。
回顾过去,我们注意到苹果始终能够在发布公告后几乎立即提供硬件,因此我们认为任何下一个计划的公告都应视为发布日期。
当另一个公告计划在 11 月 10 日发布——比我们最初的估计提前一个月——我们将其视为发货日期。事实证明,苹果确实在一周后的 11 月 17 日发布了第一批硬件。
第一步
在支持新硬件所需的所有工作中,将 Firefox 移植到 64 位 ARM 架构实际上并不是我们必须做的事情:我们多年来一直在 Android 和 Linux 上支持 64 位 ARM。
我们在 2019 年底之前一直没有发布 64 位 Android 版本,因为在那之前,我们的 JavaScript JIT 还没有针对 64 位 ARM 进行完全优化,导致的 64 位版本会比 32 位版本更慢。 在手机上,对浏览器使用超过 4GB 内存的需求并不大!2019 年,我们发布了第一个针对 64 位 ARM 的 Windows 版本的 Firefox,这让我们积累了一些经验,这正是我们现在面临的挑战。
虽然基于 ARM 硬件的 Windows 目前还没有在我们用户中流行起来,但人们预计苹果的过渡将完全不同。不仅有充分的理由相信硬件性能将如第一节所述具有突破性。苹果明确表示他们将切换整个产品线,而不是发布一台“试探性”设备。最重要的是,他们在 Mac 上拥有成功的架构过渡的成功记录。
因此,由于代码库中已经包含了对 64 位 ARM 的支持,第一步工作是浏览所有 Firefox 代码、依赖项和各种第三方构建系统,以查看它们是否正确处理了 Mac 可能带有 ARM 芯片的这个新想法。
其次,我们需要调整和修复 Firefox 代码库中处理低级调用约定,特别是 JavaScript 和 C++(以及现在的 Rust)代码部分之间的接口的各个部分。
Rust 尤其令人担忧。Firefox 依赖于 Rust 代码,我们需要一个有效的 Rust 编译器来构建浏览器。虽然Rust 对 Apple Silicon 的支持正在进行中,但直到 8 月中旬才出现可用的编译器版本,这限制了 Firefox 可能取得的进展。
编译器能够运行后,需要对我们依赖的所有 Rust 库进行类似的处理。需要更新编译器以及某些库对特定编译器版本的依赖,尤其是处理 SIMD 支持的部分,最终会让我们在以后遇到麻烦,因为它难以将 Apple Silicon 支持推送到更早版本的 Firefox,而不会潜在影响其他平台。
通用二进制
一个重要的决定是要么为基于 Intel 和 ARM 的 Mac 生成单独的版本,要么生成通用二进制,该二进制文件将两个版本捆绑在一起并在运行时选择正确的版本。生成通用二进制文件稍微复杂一些,但我们拥有可以适应的现有工具,这些工具可以追溯到苹果同时支持 32 位和 64 位二进制文件的时代。
这极大地简化了用户的工作——不会出现下载错误版本的风险——并且还意味着我们的下载页面和一些基础设施(如本地化)可以保持不变。
主要缺点是安装程序的大小显著增加,不仅对于 ARM 用户,而且对于 Intel 用户也是如此。由于这只会影响初始安装,并且用户通常会通过更新来接收新版本,而新版本的大小要小得多,因此我们认为这是一个可以接受的缺点,并继续走这条路线。
Netflix 和 DRM
虽然我们可以自己将 Firefox 的开源部分移植到 64 位 ARM,但 Netflix 和其他一些视频流媒体服务(如 Hulu、Disney+ 或 Amazon Prime)要求其视频使用闭源的专有 DRM 软件进行解码。
如果用户访问此类网站,Firefox 将自动下载并安装这种专有的 EME/CDM 模块。这给我们带来了一个问题,因为我们依赖于这些第三方供应商发布这些解码器的 ARM64 版本。
我们没有设法获得对这些更新发布日期的承诺,即使我们获得了承诺,也无法保证这些更新会在 Apple Silicon 硬件的未知发布日期之前发布。 由于我们有大量用户使用浏览器在线观看视频,这对原生 Apple Silicon 版本来说是一个潜在的障碍。
最终,我们采用了为 Windows on ARM 版本的 Firefox 使用的技术。DRM 视频解码器已经在单独的进程中执行,因此我们可以将专有代码与用户的系统隔离开来。
如果我们强制此解码过程在模拟下运行,我们就可以使用现有的 Intel x64 解码模块,并让它们与以原生方式运行的主浏览器通信。
要使它工作,有一些问题:因为加载 Google Widevine DRM 模块的进程本身依赖于一些运行时库,所以我们也需要 Intel x64 版本的这些库。
幸运的是,由于通用二进制文件包含两个版本的 Firefox,我们能够直接从应用程序包中提取它们。
其次,Apple 实际上并没有在 Apple Silicon 机器上预装 Rosetta 2 模拟器,而是当用户尝试运行 Intel 应用程序时才会触发安装。
因此,虽然在实践中用户系统很可能安装了 Rosetta,但我们不能依赖于这种情况总是发生。以编程方式触发 Rosetta 安装可以实现,但 我们的一些同事发现它不可靠,因此我们在第一次发布时放弃了这种做法,退回到 将遇到相关错误的用户引导到支持文章。
macOS Big Sur
macOS Big Sur 测试版独立于 Apple Silicon 硬件发布,让我们可以提前了解兼容性情况。令我们欣慰的是,我们依赖的 API 没有被弃用,任何向后兼容性问题或缺失的 shim 都局限于一些小的视觉问题,我们 通常能够快速修复。 其他具有类似旧代码库的开源项目就没有那么幸运了。
版本号从 10.x 升级到 11.0 - 比较可以预测的是 - 产生了错误, 无论是在我们的代码中还是在 依赖于 UA 嗅探的外部网站中,尽管 Apple 试图通过在使用旧 SDK 构建的应用程序中返回旧版本号来减轻这个问题。
更新问题
将更新后的 Firefox 应用程序包推送到用户 - 现在是一个支持两种类型 Apple 硬件的通用二进制文件,而不是之前只支持 Intel x64 - 暴露了一些进一步的复杂情况。
在更新过程中,更新磁盘上的文件后,Firefox 会重新启动更新后的版本。任何在 Intel x64 模拟下运行并启动另一个进程的 Apple Silicon 应用程序也会导致该进程在模拟下启动。
因此,当在模拟下运行的旧 Firefox 83 启动具有原生支持的新 Firefox 84 时,它不会启动新的原生二进制文件,而是最终强制它也在模拟下运行,至少在应用程序完全重启之前是这样。
虽然我们 开发了一个解决方法,但我们认为在发布日期之前它没有经过充分的测试,而且它的优势很小,因此我们最终只是 添加了一个发行说明来处理这种情况。
更令人担忧的是,用户报告一些防病毒软件将我们所有的通用二进制文件标记为恶意软件,并在更新到达的那一刻破坏了 Firefox 安装。
该软件使用了机器学习技术,并可能观察到我们组合的通用二进制文件与之前见过的任何其他合法软件都不太一样。
尝试通过常规支持渠道联系供应商没有成功,因此我们最终搜索了 LinkedIn 并设法找到了一名在核心防病毒检测方面工作的工程师。
他们立即理解了问题的严重性,并迅速采取行动修复了问题,从而避免了这款产品用户遭受重大灾难。值得注意的是,如果没有最后时刻的努力,我们将无法在无限期内发布原生 Apple Silicon 版本。
这不是第一次 浏览器制造商对防病毒软件供应商的 目标不一致感到厌烦,当防病毒软件和浏览器 无法协同工作时。
发布调用
将 Firefox 发布计划与 Apple 的预计发布日期进行比较,这意味着我们的 Firefox 83 - 预计于 11 月 17 日发布 - 与发布硬件的可用时间一致。
虽然在第一批生产机器交付给客户后,在稳定版中宣布原生支持会很好,但这意味着它将完全没有在真实硬件上进行测试。
我们决定保持谨慎,将最初的支持限于 Firefox 84 测试版,该测试版与 Firefox 83 同日发布,这使我们和我们的用户都有时间评估该产品在实际 Apple Silicon 硬件上的稳定性。
尽管我们有点失望,因为我们是在第一个 在 Nightly 中宣布原生支持的团队之一,最终我们还是稍微延迟了稳定版的发布,但其他浏览器供应商在发布支持版本方面遇到的困难支持了我们的决定。具有原生 Apple Silicon 支持的 Firefox 在 2020 年 12 月 15 日 Firefox 84 发布时,随着 84 测试版的发布进入了更广泛的世界。
虽然大多数关于 Apple Silicon 的基准测试表明 Rosetta 模拟器对性能的影响通常很低,并且 预计应用程序的运行速度可以达到原生性能的 70%-80%,但在测试原生 Firefox 构建时,我们看到了更大的性能提升,包括一些关键基准测试的性能翻倍,以及惊人的 2.5 倍的启动速度。
对启动速度加快的一个合理的解释可能是,Firefox 的许多部分本身是用 Web 自己的语言 - JavaScript、CSS 和 HTML - 编写的,因此它使用 JavaScript JIT 来实现其自身的大部分功能。
在启动时,JIT 必须将 JavaScript 转换为机器代码,虽然这通常在模拟下运行时是一个非常快的操作,但 Rosetta 必须将这种 JIT 生成的机器代码转换为另一种架构的机器代码。
Apple 引入了翻译缓存,这很可能完全消除了大多数应用程序的这种开销,但它不适用于 JIT 输出的代码。使用原生构建,可以完全避免第二次翻译,我们又拥有了一个快速的浏览器。
未来支持
随着初始版本的发布,我们可以在 Apple Silicon 版本中进行一些进一步的改进,其中一些改进将在 Firefox 85 中提供。
首先,我们不得不禁用 WebRender,因为它在 Apple Silicon 的第一个 Big Sur 版本中触发了图形驱动程序错误。现在这些错误已经得到解决,我们已经验证了 WebRender 在最终硬件上的运行情况, 我们重新启用了它,它将在 85 版本中发布。
其次,Firefox 目前使用 64 位 ARM 上的 WebAssembly 基线编译器。有一个 更快的优化编译器,名为 Cranelift ,可以在 Firefox Nightly 上进行测试,在几周内,我们预计将完成我们自己的优化编译器 Ion 的 64 位 ARM 移植, 它很可能成为新的默认编译器。
Apple Silicon 芯片是首批采用异构设计的台式机芯片之一,它们拥有不同的性能和效率核心。我们正在 修改我们的大部分核心线程和线程池架构,以 更好地处理这种差异,提高效率,并最终 能够将不太重要的任务调度到效率核心。
最后,我们正在清理和更新我们对旧版 macOS 绘图 API 的使用,在某些情况下, 完全删除我们自定义的绘图代码。这将有助于解决一些 深色模式支持中的突出问题,因为 旧版 macOS API 根本不支持它,并且 必须通过更新的 API 获取颜色值。它还将消除我们的一些弃用担忧!
我们希望您喜欢这篇关于 Firefox 团队如何经历 Apple Silicon 转型过程的内部视角,我们期待在未来的一年中将 Firefox 在 macOS 上的体验推向更高的水平。
感谢 Mike Hommey 和 Haik Aftandilian 对这篇文章做出的重大贡献。他们还完成了这里描述的大部分工程工作。Andrew Overholt、Sylvestre Ledru 和 Selena Deckelmann 提供了进一步的编辑建议。
9 条评论