RFC-0151:针对 CPU 目标的编译器调整标志

RFC-0151:针对 CPU 定位的编译器优化标志
状态已接受
区域
  • 工具链
说明

对用于控制 CPU 定位的编译器标记提出的更改,以及这些更改对平台和 SDK build 的影响。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-01-04
审核日期(年-月-日)2022-02-02

摘要

对用于控制 CPU 定位的编译器标记提出的更改,以及这些更改对平台和 SDK build 的影响。

设计初衷

Fuchsia 的 build 会生成许多工件,这些工件包含适用于不同架构的可执行机器代码。例如:预构建的共享库(发布供 SDK 使用),或平台和产品系统映像中包含的可执行 C/C++ 或 Rust 二进制文件。在编译器中生成机器码时,请务必指明以下内容:

目标架构:要使用哪种指令集架构?例如 x86-64 或 AArch64 ISA。此外,编译器可以定位到 ISA 的修订版。修订版可能会提供额外的指令或现有指令的变体,例如新的浮点指令或 SIMD 指令,或更广泛的原子内存操作,这些指令可以显著提升性能。了解目标架构至关重要,因为这样才能生成保证在目标设备上运行的代码。“提升”目标架构可解锁新功能,但代价是牺牲与旧版硬件的向后兼容性。

ARM ISA 的演变

上图:ARM ISA 的演变过程(来源

目标微架构:ISA 如何实现?这通常以指令是顺序执行还是乱序执行、解码带宽、缓存加载延迟时间等方面来表达。通过指定目标微架构,编译器可以生成在目标硬件上运行速度更快的机器码,而不会限制硬件兼容性。

Intel Core 2 微架构

上图:Intel Core 2 微架构框图(来源

编译器允许用户以我们稍后将要介绍的方式指定这些目标。Fuchsia 的构建系统能够全局或按二进制文件配置编译器。Fuchsia build 中现有的 CPU 定位实现存在一些缺点,本 RFC 旨在解决这些缺点:

  1. 为 arm64 选择基准配置时,目标是特定 CPU (Cortex-A53),而不是所用的 ISA 和功能。这会导致平台基准定义不清晰。

  2. 由于缺少先前的文献和政策或最佳实践,因此尚不清楚如何为此基准设置替换项。因此,Fuchsia 会构建所有 build,但会回退到基准 build,包括以明确不在基准范围内的硬件为目标平台的 build 配置。

自 2016 年该 build 问世以来,这些缺点就一直存在,在此之前,Fuchsia 的演变前身也存在这些缺点。当前系统将在第一部设备(恰好使用与当前平台 arm64 基准相同的微架构)上提供 Fuchsia。

近期的发展表明,我们需要进行全面改革。具体而言,除了以 Cortex-A53 为目标平台的 Astro 和 Sherlock 开发板配置之外,Fuchsia 现在还支持 Nelson 开发板配置 (Cortex-A55) 和 Atlas 开发板配置 (Intel Amber Lake)。不过,这些 build 目前未配置为利用基准与实际目标之间的差异。

此外,越来越多的人希望优化平台硬件基准的定义,或者提高基准。更明确地定义基准配置和特定开发板配置有助于加快相关工作。另请参见:

为了应对当前和未来的挑战,此 RFC 建议对 build 中的 CPU 定位进行即时更改,以及在可预见的未来治理定位的机制和政策。

利益相关方

教员cpu@google.com

Reviewers:

  • aaronwood@google.com - 系统汇编
  • digit@google.com - 构建
  • mcgrathr@google.com - 内核
  • mvanotti@google.com - 安全
  • maniscalco@google.com - 内核
  • phosek@google.com - 工具链
  • travisg@google.com - 内核

咨询了

由于拟议的更改会影响平台的大部分内容,因此我们鼓励所有相关方自行指定咨询人员。我尤其欢迎图形、媒体和 SDK 等团队提供反馈。

社交

此提案的要点最初是在 Fuchsia 的内核演变工作组中以 60 分钟的演示和公开讨论的形式进行审核的。

背景

编译时调整标志

Fuchsia 使用 clang 编译 C/C++,并且 Fuchsia 代码的某些子集也会使用 gcc 持续构建和测试。这两种工具都提供以下标志:

-march:设置目标架构,例如 x86-64-v2(根据 RFC-0073 的当前 x64 基准)或 ARMv8-A。还可以选择指定其他架构功能,例如 +avx2,以指示大于 x64 基准的 Intel Haswell 扩展。

-mtune:设置目标微架构,例如 cortex-a53haswell。如果未使用 -mtune-mcpu,则此值会设为 generic,以在一系列目标 CPU 上实现平衡。

-mcpu:设置目标 CPU。接受与 -mtune 类似的值。对于 ARM CPU,这相当于将目标架构 (-march) 和目标微架构 (-mtune) 设置为与目标 CPU 匹配。在 x86 上,这被视为已废弃,并且给定值会重定向到 -mtune

Rust 编译器提供 codegen 选项,如下所示:

target-cpu:与 -mcpu 类似,例如接受 cortex-a53

target-features:类似于 -march 地图项,例如 +avx2

当前状态

目前,所有 x64 build 均使用 -march=x86-64-v2 进行编译,所有 ARM build 均使用 -mcpu=cortex-a53 进行编译。

有一个机制可通过名为 board_configs 的 GN 参数替换此配置,该参数可被 .gni 文件中的板级配置替换。某些开发板(尤其是 Astro 和 Sherlock)会手动指定上述 Cortex-A53 配置,但这目前没有任何作用,因为如果未定义替换项,则相同的配置也会用作后备。大多数开发板配置都不会设置 board_configs

调整目标和权衡

本部分简要介绍了设置 CPU 定位选项时要考虑的不同目标,以及它们之间的一些权衡。

硬件兼容性:以较低版本的 ISA 为目标平台可实现与旧版硬件的兼容性。虽然兼容性更高,但您将无法使用可能具有性能或安全优势的新 ISA 功能。

性能:新指令可以提升性能:更快或更广泛的原子操作、加速的数学运算(FPU、SIMD 改进)、适用于常见算法(例如 CRC 和 AES)的内置加速器。针对给定 CPU 优化机器码可以生成在目标 CPU 上运行速度更快的代码,但通常会降低不在目标参数范围内的其他 CPU 上的性能。

与二进制文件大小的相互作用:在某些情况下,我们发现调整会增加二进制文件大小,例如,针对有序处理器的优化指令调度会增加寄存器压力。

二进制文件大小:某些 codegen 功能需要特定 CPU 功能才能解锁。例如,SIMD 支持自动向量化,这与展开循环有类似的效果,即生成的代码速度更快,但也更大。针对有序 CPU 调整的指令调度通常会生成较大的代码,因为它会增加更多调度约束条件,并可能会增加寄存器压力和寄存器溢出。

其他 codegen 功能可以缩减二进制文件的大小。例如,将 CRC 和 AES 等算法替换为专用指令,可以生成速度更快且更小的代码。

问题排查更轻松,即二进制代码多样性:针对不同的 CPU 进行调整意味着,随着时间的推移,会生成同一逻辑工件的更多二进制变体。例如,内核映像或预构建共享库的多个“变种”,每个变种都针对不同的目标进行了优化。这可能会使重现问题变得更加复杂,或者使 Fuchsia 面临在某些二进制变体中出现但在其他变体中不出现的问题。

公平竞争环境:除了基准 build 之外,Fuchsia 可能还会提供针对特定 CPU 进行过优化的 SDK 预构建文件(系统映像、可重新分发的共享库)。这样做会使某些硬件选项获得比其他选项更少的权限。我们有理由假设,创建针对某些 CPU 进行优化的 SDK 变种,将会在未来带来提供更多经过优化的 SDK 发布渠道的期望。

简单:上述所有因素都会增加理解 Fuchsia、在 Fuchsia 上进行开发以及维护 Fuchsia 的复杂性。上述权衡适用于在面向特定硬件的 build 和分发渠道(例如面向特定用户硬件的 OTA 渠道的 build 和发布流水线)上设置 CPU 定位选项,以在可行的情况下引入二进制多样性。在撰写本文时,系统或软件包提交机制根本无法向不同的目标硬件提供多个二进制文件,将正确的二进制文件与正确的设备进行匹配。

提案

您可以在此更改中查看系统立即建议的修改。 下文提供了更多说明。

新的 arm64 基准硬件目标

arm64 的当前基准定义为以 Cortex-A53 为目标平台,如下所示:

-mcpu=cortex-a53

这在技术上等同于以一组精确的 Cortex-A53 功能来表达 -march,并为 Cortex-A53 调整 codegen。

-march=<armv8a + Cortex-A53 features>
-mtune=cortex-a53

相反,基准将表达平台实际执行的 ARMv8-A ISA 功能,因此被假定为基准,然后为通用 armv8a CPU 调整代码生成器。

-march=armv8-a+simd+crc+crypto
-mtune=generic

-march 的影响实际上是无效的,因为移除 Cortex-A53 支持但未在代码中使用的 -march 功能是无效的。

-mtune 的影响微乎其微,甚至没有影响,因为通用调整目标会针对典型的有序 ARMv8-A CPU(例如 Cortex-A53)进行优化。

对现有 x64 基准硬件目标的更改

x64 的当前基准如下:

-march=x86-64-v2

此主题之前已在前面提到的 RFC-0073:将 x86-64 平台要求提升到 x86-64-v2 中有所介绍。

这将更改为以下标志集:

-march=x86-64-v2
-mtune=generic

这并不是行为变更,因为如前所述,如果未指定 -mtune-mcpu-mtune 会默认为 generic。不过,添加 -mtune=generic 会使此行为变得显式,并且与 arm64 基准的定义保持一致。

特定于开发板的配置

在特定于板级的 .gni 文件(例如 //boards/ 中找到的文件)中指定的 board_configs 板级参数将继续用于使用特定于板级的配置替换基准配置。

具体而言,使用 Cortex-A53 的板级配置(例如 astro.gnisherlock.gni)将继续以 Cortex-A53 为目标平台,并保留当前的 -mcpu=cortex-a53 配置。

本质上,此 RFC 会将以 Cortex-A53 为目标平台的现有 arm64 配置从平台基准中提取出来,并将其提取到搭载此类 CPU 的 Astro 和 Sherlock 开发板的特定于开发板的配置中。然后,此 RFC 使用可泛化到许多硬件选项的 ARM ISA 术语(而非单个 ARM CPU)重新定义了平台基准。

此外,在 SDK 的未来版本中,我们可能会添加对针对不同架构变体(例如 ARM Cortex-A73 或 Intel AVX 扩展)的优化的支持。这需要进一步讨论,超出了我们的服务范围。

内核配置

board_configs 参数将不再适用于内核映像。原因如下:

  1. 目前,在 codegen 时需要知道的新指令或其他 CPU 功能对内核没有好处。

  2. 基于微架构对内核代码进行调整不会带来任何好处,无法抵消增加二进制代码多样性和复杂性的成本。

内核可以继续提供有关支持的硬件功能的信息,例如通过 zx_system_get_features 系统调用。

此外,内核仍可利用一些较新的硬件功能,例如 64kB 内存页,而无需生成不同的代码,只需在运行时查询这些功能是否存在即可。如果引入了需要特定于开发板的配置的此类新功能,则可以轻松引入用于定义关联标志的新参数 kernel_board_configs

向后兼容性

此 RFC 中提出的立即更改不会提高 Fuchsia 的最低硬件要求,因此不会影响向后兼容性。未来如果要提高最低要求,可以参考本 RFC 提倡的政策。

安全注意事项

Fuchsia 使用或打算使用多项可提高安全性或支持使用清理程序(从而提高安全性)的 CPU 功能。这些通常不受此处讨论的编译器标志控制,因此无需担心。

值得注意的是:

测试

正确性:对 CPU 定位的更改绝不应影响正确性。这通过持续的提交前和提交后测试进行验证。现有系统足以确保这一点。

效果:更改 CPU 定位设置通常会影响效果。 与之前一样,Fuchsia 的 Perfcompare 系统将用于验证任何此类更改。

二进制文件大小:更改 CPU 定位通常会以细微的方式影响二进制文件大小。具体而言,Fuchsia 目前最密切地跟踪 Astro 图片的大小,因为这是我们最受约束的目标。立即更改不会使此大小发生回归。未来,这些商品定义的所有者可以查看影响特定商品图片的更改,并仔细考虑相关权衡。

缺点、替代方案和未知情况

CPU 定位会带来许多工程和业务权衡,因为有时目标会相互冲突。这些问题已在上文中加以说明。未来会改变这些权衡的更改,以及未来的调整机会和注意事项均不在本 RFC 的讨论范围之内。