Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 774 – 移除 JIT 构建对 LLVM 的要求

作者:
Savannah Ostrowski <savannah at python.org>
讨论至:
Discourse 帖子
状态:
推迟
类型:
标准跟踪
创建日期:
2025年1月27日
Python 版本:
3.14
发布历史:
2025年1月27日
决议:
2025年3月14日

目录

摘要

自 Python 3.13 以来,CPython 已经能够通过 Linux 和 Mac 上的 --enable-experimental-jit 标志以及 Windows 上的 --experimental-jit 标志配置和构建实验性的即时 (JIT) 编译器。要启用 JIT 构建 CPython,用户需要在其机器上安装 LLVM(最初使用 LLVM 16,但最近使用 LLVM 19)。LLVM 负责生成对于我们的复制-修补 JIT 至关重要的模板(请参阅 PEP 744)。这些模板是预定义的、特定于架构的模板,用于在运行时生成机器代码。

本 PEP 提议通过将生成的模板托管在 CPython 仓库中,移除启用 JIT 的构建对 LLVM 的构建时依赖。这种方法使我们能够在构建时利用已签入的受支持平台的模板,从而简化贡献者体验并解决 2024 年 9 月 Python 核心开发者冲刺中提出的问题。话虽如此,这里有一个明显的权衡需要考虑,因为改进的开发者体验确实会以增加仓库大小为代价。

重要的是,本 PEP 并非提案接受或拒绝 JIT 本身,而是确定 JIT 构建的 LLVM 构建时依赖在未来是否可接受。如果本 PEP 被拒绝,我们将维持现状,保留 LLVM 构建时要求。虽然此依赖项迄今为止有效地服务于 JIT 开发过程,但它引入了设置复杂性和其他挑战,本 PEP 旨在缓解这些问题。

动机

在 2024 年 9 月举行的 Python 核心开发者冲刺中,讨论了 JIT 的后续步骤——相关讨论也发生在 GitHub 上。作为讨论的一部分,也明确希望移除 JIT 构建对 LLVM 的要求,为在 3.14 中默认发布 JIT 做准备。冲刺中的共识是,为 Tier 1 平台的非调试构建提供预生成模板就足够了,并且将这些文件签入 CPython 仓库足以满足有限数量的平台(尽管已经探索了更多选项;请参阅 被拒绝的想法)。

目前,使用 JIT 构建 CPython 需要 LLVM 作为构建时依赖。尽管不暴露给最终用户,但这种依赖是次优的。要求 LLVM 增加了开发人员和希望启用 JIT 构建 CPython 的用户的设置负担。根据操作系统,操作系统随附的 LLVM 版本可能与 JIT 构建所需的版本不同,这给故障排除和解决带来了额外的复杂性。由于目前只有少数核心开发人员贡献和维护 JIT,我们还希望确保尽可能减少在 JIT 相关代码上工作的摩擦。

通过提议的方法,可以预先生成支持架构的预编译模板,存储在中央位置,并在构建过程中自动使用。这种方法确保了可重现的构建,使 JIT 成为 CPython 未来更稳定和可持续的一部分。

基本原理

本 PEP 提议将 JIT 模板直接签入 CPython 仓库,作为消除我们对 LLVM 构建时依赖的最佳途径。

这种方法

  • 为希望使用 JIT 构建 CPython 的用户提供最佳的端到端体验
  • 降低了希望为 JIT 做出贡献的用户的入门门槛
  • 确保构建在不同平台之间保持可重现和一致,而不依赖外部基础设施或下载机制
  • 消除网络条件或托管文件与 CPython 仓库状态之间潜在差异引入的可变性,并且
  • 使模板遵守我们对所有其他 JIT 相关代码的相同审查流程

然而,这种方法确实会导致整体仓库大小略有增加。比较过去 90 天提交的仓库增长,实际提交与添加模板后的相同提交之间的差异为每个模板文件 0.03 MB。在整体仓库大小的背景下,这是一个小幅增长,同期增长了 2.55 MB。对于六个模板文件,这相当于上限为 0.18 MB。目前所有六个平台的模板文件总大小为 7.2 MB。[1]

未来,随着寄存器分配的改变,这些模板可能会变得更大,每个模板文件中的每条指令将引入 5-6 个变体(大 5-6 倍)。然而,如果我们最终选择这条路线,我们可以对模板文件进行额外的修改,以帮助抵消这种大小的增加(例如,删除注释,最小化模板)。

规范

本规范概述了提议的更改,以移除对 LLVM 的构建时依赖,以及如果本 PEP 被接受,贡献者的体验。

仓库变更

CPython 仓库现在将在 Tools/jit 中的一个名为 stencils/ 的新子目录中托管预编译的 JIT 模板。目前,JIT 已针对六个平台进行测试和构建,因此首先我们将签入六个模板文件。将来,如果需要或相关支持其他平台,我们可能会签入额外的模板文件。

cpython/
    Tools/
        jit/
            stencils/
                aarch64-apple-darwin.h
                aarch64-unknown-linux-gnu.h
                i686-pc-windows-msvc.h
                x86_64-apple-darwin.h
                x86_64-pc-windows-msvc.h
                x86_64-pc-linux-gnu.h

工作流程

工作流程变更可以分为两部分,即使用 JIT 启用构建 CPython 和处理 JIT 的实现。

使用 JIT 构建 CPython

预编译的 JIT 模板文件将存储在 Tools/jit/stencils 目录中,每个文件名都对应于上面概述的目标三元组。在构建时,我们决定是使用已签入的模板还是为用户的平台生成新模板。具体来说,对于安装了 LLVM 的贡献者,Tools/jit/stencils 中的 build.py 脚本将允许他们为其平台重新生成模板。没有 LLVM 的用户可以直接依赖仓库中的预编译模板文件。

JIT 实现(或接触 JIT 文件)工作

在持续集成 (CI) 中,当 JIT 相关文件发生更改时,模板文件将自动验证和更新。当打开一个涉及这些文件的拉取请求时,jit.yml 工作流程(用于构建和测试我们的构建)将照常运行。

然而,作为其中的一部分,我们将引入一个新步骤,该步骤将仓库中当前的模板与 CI 中生成的模板进行比较。如果某个平台的模板文件存在差异,则会生成一个用于更新模板的补丁文件,并且该步骤将失败。每个补丁都上传到 GitHub Actions。CI 在所有平台运行完成后,为了方便起见,这些补丁被聚合到一个补丁文件中。您可以下载此聚合补丁,在本地应用它,然后将更新后的模板重新提交到您的分支。然后,随后的 CI 运行将通过。

参考实现

参考实现 的关键部分包括

忽略模板本身和任何必要的 JIT README 更改,支持可重现模板生成和托管的源代码更改是最小的(大约 150 行更改)。

被拒绝的想法

作为本 PEP 研究和探索的一部分,考虑了几种替代方法。然而,下面的想法要么涉及基础设施成本、维护负担,要么导致更差的整体开发者体验。

使用 Git 子模块

Git 子模块对于托管模板来说是一种糟糕的开发者体验,因为它们会产生另一种不必要的摩擦。例如,对 JIT 的任何更新都需要重新生成模板并将其提交到单独的仓库。这引入了一个复杂的过程:您必须更新子模块仓库中的模板,提交这些更改,然后更新主 CPython 仓库中的子模块引用。这种脱节增加了不必要的复杂性和开销,使贡献者和维护者的过程变得脆弱且容易出错。

使用 Git 子树

当使用子树时,嵌入式仓库成为主仓库的一部分,类似于本 PEP 中提议的内容。然而,子树需要额外的工具和维护步骤,这增加了工作流程不必要的复杂性。

托管在单独的仓库中

虽然将 JIT 模板拆分为单独的仓库可以避免与托管模板相关的存储开销,但它增加了构建过程的复杂性。需要额外的工具来获取模板,并且可能会在工作流程中创建额外且不必要的故障点。这种分离也使得难以确保模板与 CPython 源代码树之间的一致性,因为更新必须在仓库之间进行协调。

托管在云存储中

将模板托管在 S3 存储桶或 GitHub 原始存储等云存储中会引入外部依赖,使离线开发工作流程复杂化。此外,根据提供商的不同,这种类型的托管会产生额外的成本,这是我们希望避免的。

使用 Git LFS

Git 大文件存储 (LFS) 为贡献者增加了工具依赖,使开发工作流程复杂化,特别是对于可能尚未熟悉 Git LFS 的用户。Git LFS 与离线工作流程配合不佳,因为由 LFS 管理的文件在检出特定提交时需要互联网连接才能获取,这甚至对基本的 Git 工作流程也造成了干扰。Git LFS 确实有一些免费配额,但超出该配额会有额外费用,这也是我们不希望看到的。

保持现状,LLVM 作为构建时依赖项

将 LLVM 保留为构建时依赖会维持现有采用和贡献的障碍。最终,此选项未能解决可访问性和简单性的核心挑战,并且未能消除在秋季 Python 核心开发者冲刺中被认为不可取的依赖(也是本 PEP 的推动力),使其成为一个糟糕的长期解决方案。

脚注


来源:https://github.com/python/peps/blob/main/peps/pep-0774.rst

最后修改:2025-05-26 16:58:47 GMT