背景
SOT 是一个与 Python 版本强相关的模块,基本上每个 Python 版本都需要专门适配一次,而每次适配都是一次自底向上从零开始的过程。而跟随这个过程可以帮助新人更快地理解 SOT 整个架构~
在过去,我们最开始是基于 Python 3.8 开发的,之后适配了 Python 3.9 并利用流水线进行了监控(PaddlePaddle/PaddleSOT#105 ),不久又适配了 Python 3.10(PaddlePaddle/PaddleSOT#112 ),由于 Python 3.11 内部发生了大量的改动,因此成立了专项对 Python 3.11 进行支持(PaddlePaddle/PaddleSOT#360 ),如今我们要对 3.12 进行适配了~
适配新版本的最好切入点是了解新版本的改动,比如 Python 3.11,它对整个字节码体系做了大幅的调整,但是调整了什么呢?我们可以在 Release Notes 里找到,但是为什么改动呢?其实我们能从 faster-cpython project 了解到 Python 近几年的加速计划,基本上可以说近几个版本的改动都是为了加速。但是这样改动的目的又是什么,具体实现是什么?这些我们就需要从源码入手来寻找答案了。在 Python 3.11 适配期间,我(@SigureMo )整理了 Python 3.11 核心加速原理——指令特化 并进行了分享,这是 Python 3.11 最大的目标,也是最核心改动的原因,了解这些之后,整个版本适配就没什么悬念了(虽然 3.11 坑确实很多就是了)。
从 Python 3.9-3.11 的适配经验而言,目前看 Python 3.11 > 3.12 > 3.10 > 3.9,这其实也能从 Python 3.12 Release Notes 、faster-cpython project 3.13 plan 以及源码找到一些线索,Python 3.12 完成的最大的一件事是使用 DSL 完成了 ceval 的重写,以便实现 Tier 2 优化器,也就是重构,并没有实现 Tier 2 optimizer。Python 3.11 最大的难点就是 Tier 1 实现后整体结构的变动,而 Tier 2 预计会在 3.13 发布,因此 3.12 的适配难度应该低于 3.11。(但也可预见未来 Python 3.13 适配应该难于 3.11)
另一方面,了解 SOT 架构也是对新版本适配有帮助的,PEP 523 是 SOT JIT 编译的基础,我们该模块源码放在 paddle/fluid/pybind/eval_frame.c ,每次适配新版本的开始都是这个最底层的模块。
更上一层地,是模拟执行核心模块 python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py 和字节码生成模块 python/paddle/jit/sot/opcode_translator/executor/pycode_generator.py 。在模拟执行模块中,我们需要对每条字节码进行模拟执行,并修改模拟执行器的状态,在字节码生成模块中,我们需要根据模拟执行的结果来生成新的字节码,这些都是和版本强相关的模块(主要是字节码的设计)。
此外大多是版本无关的代码,一般不需要进行适配。
Eval Frame 适配
字节码适配
字节码适配任务即对新版本新增、修改的字节码进行适配,根据 Python 3.12 字节码变更 和 Python 各版本字节码差异表格 ,变动和新增字节码如下:
行为变动
新增
Note
并不是每个新增 / 变动的字节码都需要适配,这里只是列出全部,有些字节码是一些复杂特性才会出现的(比如异常、异步、match 语法)此种情况不需要适配,Python 3.12 为了实现 PEP 695 也有一些新的字节码,这些字节码我们也是现阶段不需要支持的,对 PEP 695 实现感兴趣可以参考 Jelle 的博客
字节码的适配,即字节码模拟执行逻辑的适配,也就是修改 OpcodeExecutor,字节码的模拟执行逻辑可参考以下内容:
建议每个实现都看看源码,文档中有很多细节是不会暴露给用户的,但我们模拟执行是需要的
其它模块适配
TODO...
单测汇总见: #61174
背景
SOT 是一个与 Python 版本强相关的模块,基本上每个 Python 版本都需要专门适配一次,而每次适配都是一次自底向上从零开始的过程。而跟随这个过程可以帮助新人更快地理解 SOT 整个架构~
在过去,我们最开始是基于 Python 3.8 开发的,之后适配了 Python 3.9 并利用流水线进行了监控(PaddlePaddle/PaddleSOT#105),不久又适配了 Python 3.10(PaddlePaddle/PaddleSOT#112),由于 Python 3.11 内部发生了大量的改动,因此成立了专项对 Python 3.11 进行支持(PaddlePaddle/PaddleSOT#360),如今我们要对 3.12 进行适配了~
适配新版本的最好切入点是了解新版本的改动,比如 Python 3.11,它对整个字节码体系做了大幅的调整,但是调整了什么呢?我们可以在 Release Notes 里找到,但是为什么改动呢?其实我们能从 faster-cpython project 了解到 Python 近几年的加速计划,基本上可以说近几个版本的改动都是为了加速。但是这样改动的目的又是什么,具体实现是什么?这些我们就需要从源码入手来寻找答案了。在 Python 3.11 适配期间,我(@SigureMo)整理了 Python 3.11 核心加速原理——指令特化 并进行了分享,这是 Python 3.11 最大的目标,也是最核心改动的原因,了解这些之后,整个版本适配就没什么悬念了(虽然 3.11 坑确实很多就是了)。
从 Python 3.9-3.11 的适配经验而言,目前看 Python 3.11 > 3.12 > 3.10 > 3.9,这其实也能从 Python 3.12 Release Notes、faster-cpython project 3.13 plan 以及源码找到一些线索,Python 3.12 完成的最大的一件事是使用 DSL 完成了 ceval 的重写,以便实现 Tier 2 优化器,也就是重构,并没有实现 Tier 2 optimizer。Python 3.11 最大的难点就是 Tier 1 实现后整体结构的变动,而 Tier 2 预计会在 3.13 发布,因此 3.12 的适配难度应该低于 3.11。(但也可预见未来 Python 3.13 适配应该难于 3.11)
另一方面,了解 SOT 架构也是对新版本适配有帮助的,PEP 523 是 SOT JIT 编译的基础,我们该模块源码放在
paddle/fluid/pybind/eval_frame.c,每次适配新版本的开始都是这个最底层的模块。更上一层地,是模拟执行核心模块
python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py和字节码生成模块python/paddle/jit/sot/opcode_translator/executor/pycode_generator.py。在模拟执行模块中,我们需要对每条字节码进行模拟执行,并修改模拟执行器的状态,在字节码生成模块中,我们需要根据模拟执行的结果来生成新的字节码,这些都是和版本强相关的模块(主要是字节码的设计)。此外大多是版本无关的代码,一般不需要进行适配。
Eval Frame 适配
framein eval custom code was not released intstate#61703字节码适配
字节码适配任务即对新版本新增、修改的字节码进行适配,根据 Python 3.12 字节码变更 和 Python 各版本字节码差异表格,变动和新增字节码如下:
行为变动
新增
Note
并不是每个新增 / 变动的字节码都需要适配,这里只是列出全部,有些字节码是一些复杂特性才会出现的(比如异常、异步、match 语法)此种情况不需要适配,Python 3.12 为了实现 PEP 695 也有一些新的字节码,这些字节码我们也是现阶段不需要支持的,对 PEP 695 实现感兴趣可以参考 Jelle 的博客
字节码的适配,即字节码模拟执行逻辑的适配,也就是修改
OpcodeExecutor,字节码的模拟执行逻辑可参考以下内容:ceval.cbytecode.c以及根据其生成的generated_cases.c.h建议每个实现都看看源码,文档中有很多细节是不会暴露给用户的,但我们模拟执行是需要的
其它模块适配
TODO...
单测汇总见: #61174