Paddle 3.0 编译器全链路深度解析:SOT 图捕获、PIR 中间表示与 CINN Kernel 生成
Paddle 3.0 编译器全链路深度解析SOT 图捕获、PIR 中间表示与 CINN Kernel 生成【免费下载链接】PaddlePArallel Distributed Deep LEarning: Machine Learning Framework from Industrial Practice 『飞桨』核心框架深度学习机器学习高性能单机、分布式训练和跨平台部署项目地址: https://gitcode.com/GitHub_Trending/pa/PaddlePaddle 3.0 以「动态图编写、编译器加速」为核心理念通过SOT → PIR → CINN三阶段编译流水线将用户用动态图eager mode书写的 Python 代码最终编译为高性能 GPU KernelSOT 在 Python 字节码层面完成计算子图捕获PIR 提供 MLIR 风格的 SSA 中间表示并承载全部图优化CINN 将融合后的算子子图降为 CUDA Kernel 并交由 PIR 执行器调度。本文以仓库内 SKILL.md 及其 6 篇 references 设计文档为骨架结合源码逐层剖析这条全链路帮助读者掌握从 Python 代码到cuLaunchKernel的完整编译路径并具备定位 SOT 捕获失败、shape 推导错误、融合策略问题等实战问题的能力。全链路概览从动态图到 GPU Kernel 的四阶段流水线用户 Python 代码动态图 eager mode │ ▼ Stage 0: SOT 图捕获 PEP 523 eval_frame 拦截 → OpcodeExecutor 字节码模拟 → FunctionGraph / StatementIR → paddle.jit.to_static(full_graphTrue) 编译子图 → pir::Program │ ▼ Stage 1: PIR Pass 优化 pir::ProgramSSA 形式的 pd_op.* 算子图 │ ├── ShapeOptimizationPassInferSymbolicShape 动态 shape 符号推导 │ ├── 组合算子分解 (DecompInterface → primitive operators) │ └── 通用 Pass 优化常量折叠、死代码消除等 │ ▼ Stage 2: CINN 编译 ├── PdOpToCinnOpPass / PdOpToDynamicShapeCinnOpPass算子映射 ├── add_cinn_pass → cinn_op.group算子融合 ├── OpLowerCompute Schedule→ LoweredFunc ├── CodeGenCUDA_Dev → CUDA source → NVRTC → CUfunction ├── CompilationCache编译缓存相同子图复用已编译 Kernel │ ▼ Stage 3: 执行 PirInterpreter 调度 → CinnJitInstruction → cuLaunchKernelSOT → PIR 的衔接是理解整条链路的关键SOT 捕获的 StatementIR 被包装为 Python 函数后通过paddle.jit.to_static(full_graphTrue)再次走 AST Transformer 路径编译为pir::Program参见 compile_cache.py。这意味着 SOT 负责「图捕获」而to_static负责「图编译」两者分工明确、衔接清晰。SOT字节码级的动转静前端SOTSymbolic Opcode Translator是 Paddle 3.0 的动转静前端。与旧的 AST Transformer将 Python 源码解析为 AST 再做语法树变换相比SOT 在 Python VM 字节码层面拦截并模拟执行用户代码精确追踪 Tensor 计算子图。AST 方案存在根本性局限无法区分x[0]是 numpy 索引还是 Tensor 索引、难以处理嵌套函数/闭包/装饰器等控制流边界、无法推断-1动态 shape、无法转换 numpy/scipy 等第三方库调用。SOT 的字节码方案天然规避了这些难点可处理 numpy/Tensor 互操作、动态控制流、第三方库调用等复杂场景。核心机制eval_frame 拦截与字节码模拟Python Frame │ ▼ PEP 523 eval_frame 拦截 PyInterpreterState.eval_frame │ ▼ OpcodeExecutor模拟 Python VM 字节码执行 │ ├─ Variable 体系 (TensorVariable, ConstantVariable, ContainerVariable, ...) │ ├─ Tracker 追踪来源 → 生成 Guard缓存有效性校验 │ └─ SideEffect 记录副作用全局变量修改、可变对象修改 ▼ FunctionGraph / StatementIR记录算子调用 │ ├─ 无 fallback: 完整子图 → to_static(full_graphTrue) → pir::Program └─ fallback: 子图切分 → 可静态化部分编译 不可静态化部分 Python 执行PEP 523Python 3.6提供了自定义帧求值能力PyInterpreterState.eval_frame被替换为 SOT 自定义函数后Python 每执行一帧函数调用都会先进入 SOT 逻辑——先检查该帧是否已有编译结果且 Guard 条件满足命中则直接执行缓存的 StaticFunction未命中则启动 OpcodeExecutor 模拟执行。核心组件及其职责组件说明OpcodeExecutor模拟 Python VM 执行字节码不真正计算而是追踪 Tensor 操作Variable 体系将 Python 对象包装为 VariableTensorVariable / ConstantVariable / ContainerVariable / CallableVariable / ModuleVariableTracker记录 Variable 来源provenance形成 DAG用于生成 GuardGuardCallable[[FrameType], bool]判断当前帧输入是否满足编译假设用于缓存命中判断FunctionGraph收集 Tensor 相关操作输出 StatementIRStatementIR4 种语句类型call_api / call_method / call_sir / call_layer最终经to_static(full_graphTrue)编译为 ProgramSideEffect记录并回放模拟执行中对全局变量和可变对象的修改保证语义等价OpcodeInlineExecutor跨函数边界模拟执行实现子图跨函数融合Variable 体系与 Tracker 追踪Variable 将 Python 对象包装为可在模拟层面追踪的实体TensorVariable包装paddle.Tensor并记录到 FunctionGraphConstantVariable包装 int/float/str/None 等常量并直接内联ContainerVariable包装 list/dict/tuple 并递归追踪容器内元素CallableVariable模拟函数/方法调用行为ModuleVariable追踪nn.Layer的子层与参数。每个 Variable 持有一个 Tracker 记录其来源Tracker 之间形成 DAG 结构x args[0] → LocalTracker(x) y x.shape[0] → GetAttrTracker(LocalTracker(x), shape) → GetItemTracker(..., 0) z paddle.add(x, y) → DummyTracker() # 计算结果由 FunctionGraph 追踪Tracker 的核心用途是生成 Guard从叶节点回溯到根节点即可生成一条检查链验证运行时输入是否满足编译假设。Guard 形如Callable[[FrameType], bool]概念上等价于def guard(frame: FrameType) - bool: x frame.f_locals[x] return ( isinstance(x, paddle.Tensor) and x.shape [2, 3] and x.dtype paddle.float32 )每个 Variable 的 Tracker 链自动生成 sub-guard所有 sub-guard 通过 AND 组合成完整 Guard。每个帧维护一个(Guard, StaticFunction)列表作为缓存执行时依次检查首个满足的即命中缓存直接执行对应函数。StatementIR 与跨函数融合StatementIR 包含 4 种语句类型call_api调用 Paddle API如paddle.add(x, y)、call_method调用 Tensor 方法如x.reshape([2, 3])、call_sir调用子 StatementIR即嵌套子图、call_layer调用 nn.Layer 的 forward。当 OpcodeExecutor 遇到函数调用时会创建 OpcodeInlineExecutor 进入被调用函数内部继续模拟从而跨函数边界追踪 Tensor 操作、将多个函数的操作融合进同一个子图、避免不必要的子图切分。Fallback 安全兜底当 OpcodeExecutor 遇到无法模拟的操作时触发 sub-graph fallback将当前已收集的子图编译执行无法模拟的部分交给 Python 原生执行随后开始新的子图收集。四类典型场景缩写全称场景DDCFData-Dependent Control Flow控制流条件依赖 Tensor 值如if x.sum() 0UNSPSUnsupported Simulation无法模拟的 Python 操作如某些 C 扩展、.numpy()CDBLCustom Blacklist用户或框架标记的不转换函数如产生 -1 shape 的算子UNIMPUnimplemented Opcode尚未实现模拟的字节码指令Fallback 是安全兜底任何无法处理的情况都退化为「部分子图编译 部分 Python 执行」不会导致报错。SideEffect 与语义等价Python 代码可能修改全局变量或可变对象如list.appendSOT 的 SideEffect 模块负责在模拟执行过程中记录所有此类修改并在生成的 StaticFunction 执行后按顺序回放确保编译后的代码与原始 Python 代码产生完全相同的副作用——这是动转静语义等价性的关键保证。使用方式import paddle paddle.jit.to_static # 默认 full_graphFalse启用 SOT 模式 def train_step(net, x, label): pred net(x) loss paddle.nn.functional.cross_entropy(pred, label) loss.backward() return loss # full_graphFalse默认SOT 模式字节码级别转换 自动 fallback # full_graphTrue传统 AST Transformer要求整图可转 net paddle.jit.to_static(net) # 默认 full_graphFalse即 SOT 模式 output net(x)SOT 相关源码入口集中在 python/paddle/jit/sot/to_static的 full_graph 分发在 api.pyeval_frame 入口在 eval_frame_callback.pyOpcodeExecutor 与 OpcodeInlineExecutor 分别在 opcode_executor.py 和 opcode_inline_executor.pyVariable 体系在executor/variables/目录Tracker、Guard、FunctionGraph、SideEffect 分别对应executor/tracker.py、executor/guard.py、executor/function_graph.py、executor/side_effects.pyStatementIR 及 SIR 编译缓存位于 symbolic/statement_ir.py 与 symbolic/compile_cache.py。PIRPaddle 3.0 的统一中间表示PIRPaddle Intermediate Representation采用 MLIR 风格的 SSA 设计替代旧的 ProgramDesc/OpDesc 体系。其核心动机是统一旧体系中三套断裂的类型系统——framework::proto::VarType静态图、DataType/DataLayoutPHI 算子库以及推理阶段的类型表示——它们之间靠大量switch-case硬编码转换难以维护和扩展。PIR 的设计目标可扩展新增类型无需修改核心框架、高性能类型相等性通过指针比较O(1) 复杂度、模块化类型归属于 Dialect独立注册。类型系统概念关键类说明TypeIDTypeID类型的唯一标识。利用 C 模板函数内static局部变量地址天然唯一——不同类型实例化不同函数地址自然不同通过TypeIDAllocator::GetT()获得AbstractTypeAbstractType类型的「类描述符」包含type_id_、所属Dialect、InterfaceMap、HasTraitFunction在IRContext中按 TypeID 注册一次TypeStorageTypeStorage类型实例的存储。无参数类型如Float32Type全局仅一个实例带参数类型如DenseTensorType按参数 hash 唯一化存储uniquing相同参数返回同一指针TypeType值语义轻量包装仅持有TypeStorage*指针。两个 Type 相等 ⟺ 指针相等O(1)参数化类型的代表DenseTensorType的存储键为std::tupleType, DDim, DataLayout, LoD, size_t获取实例通过DenseTensorType::get(ctx, dtype, dims, layout, lod, offset)IRContext内部通过StorageManager以 hash 表做 uniquing。日常使用方式Type t some_value.type(); // 类型判断 if (t.isaDenseTensorType()) { ... } // 类型转换失败返回空 Type if (auto dt t.dyn_castDenseTensorType()) { auto dims dt.dims(); } // 相等性指针比较O(1) if (t1 t2) { ... }Attribute 系统与 Type 共享相同的 uniquing 基础设施AbstractAttributeAttributeStorageAttribute区别在于语义Type 描述 Value 的类型Attribute 描述 Operation 的常量属性。每个 Operation 的属性集合用DictionaryAttribute存储内部是按 key 排序的(StrAttribute, Attribute)对查找走二分搜索。Value 系统与 Operation 内存布局Value 系统遵循三个设计原则严格 SSA每个 Value 有且仅有一个定义点所有使用点通过 use-chain 链接、Pimpl 模式用户侧Value/OpResult/OpOperand只是轻量句柄实际数据存于*Impl类、三层架构面向用户的 API 层 → Pimpl 实现层 → 连续内存布局层。ValueImpl持有Type type_与OpOperandImpl *first_user_以侵入式链表串联所有使用者。OpResultImpl算子输出index 0–5 为 Inline Result直接存储在 Operation 前方的连续内存中result index 编码在对象自身的低位 bitindex ≥ 6 为 Out-of-Line Result持有显式的result_index_字段。给定一个 OpResult 可通过地址运算直接定位所属 Operation无需额外指针。OpOperandImpl算子输入四个字段source_指向被使用的 Value、next_user_use-list 下一个使用者、back_addr_反向指针、owner_所属 Operation构成侵入式双向链表。遍历 use-chain 时从first_user_出发沿next_user_前进每个使用者经owner_回溯到所属 Operation。Operation 采用连续内存分配所有关联数据一次malloc完成低地址 ──────────────────────────────────────────── 高地址 [OpOutOfLineResults | OpInlineResults | Operation | OpOperands] ↑ this 指针Operation 核心字段包括DictionaryAttribute attrs_、指向OpInfoImpl的OpInfo info_、num_results_/num_operands_/num_regions_、parent_block_与动态分配的regions_数组。OpInfoImpl持有InterfaceMap按 TypeID 排序二分查找定位Concept*再调用函数指针即 concept-model 多态、has_trait_、verify_等。Block、Region 与 Dialect概念关键类说明Block/RegionBlock/RegionBlock 持有 Operation 列表最后一个必须是 terminator BlockArgumentRegion 是 Block 的有序容器约束 Value 作用域——Region 内部定义的 Value 不能被外部引用但内部可捕获外部 Value类似闭包语义DialectBuiltinDialect/PaddleDialect/CinnDialect模块化容器聚合一组 Type、Attribute、Op 定义经IRContext::RegisterDialectT()独立注册与扩展Trait/InterfaceOpTraitBase/ concept-model 多态Trait 是静态编译期标记如InplaceTrait、SideEffectTrait、SameOperandsAndResultTypeTraitInterface 通过 concept-modelConcept 纯虚接口 Model 具体实现实现动态分派一次间接跳转、无虚表开销替代 C 虚函数核心 Dialect 一览Dialect职责典型内容BuiltinDialectPIR 内置基础类型Float32Type,Int64Type,VectorType,DenseTensorTypePaddleDialectPaddle 算子定义pd_op.matmul,pd_op.relu,pd_op.conv2dCinnDialectCINN 编译器专用cinn_op.group,cinn_op.yield,cinn_op.generate_shapeControlFlowDialect控制流辅助cf.yield,cf.stack_create,cf.tuple_push,cf.tuple_popPaddleDialect控制流部分控制流算子pd_op.if,pd_op.whileProgram 结构与权重管理PIR Program 通过ParameterMapunordered_mapstring, shared_ptrParameter管理模型权重用两个专用 Op 桥接计算图与权重builtin.parameter(linear.weight)从参数表读取产生 Valuebuiltin.set_parameter(value, linear.weight)将计算结果写回参数表从而将权重存储与计算图解耦便于序列化与分布式参数分片。嵌套模型结构如下Program ├── weights: unordered_mapstring, shared_ptrParameter └── ModuleOp (顶层 Operation) └── Region[0] └── Block[0] ├── builtin.parameter(w) → %0 (从权重表读取参数) ├── pd_op.matmul(%input, %0) → %1 ├── pd_op.if(%cond) → %2 │ ├── Region[0] (then) │ │ └── Block[0]: pd_op.relu(%1) → cf.yield │ └── Region[1] (else) │ └── Block[0]: pd_op.tanh(%1) → cf.yield └── builtin.set_parameter(%2, out)嵌套规则为 Operation → Region → Block → Operation支持任意深度。此外 PIR 通过 view 语义处理 Tensor 别名与原地操作v_tensor类型表示与原始 Tensor 共享底层存储的 viewInplaceTrait标记原地操作如pd_op.relu_reshape/slice/transpose等产生v_tensor不拷贝数据——编译器在 buffer 分配与内存优化时需要追踪 view 关系以避免错误的内存复用。控制流Region 嵌套 Stack 反向机制PIR 通过 Region 嵌套实现结构化控制流避免传统 CFG 中的 phi 节点和复杂跳转。pd_op.if固定 2 个 RegionRegion[0] true 分支、Region[1] false 分支每个分支以cf.yield终止且两分支返回类型必须一致pd_op.while固定 1 个 body Regionbody 的 BlockArgument 与 loop_vars 一一对应cf.yield(new_cond, new_values...)的第一个返回值更新循环条件其余返回值更新 loop_varscond 为 false 时退出循环。控制流的反向求导面临核心问题前向执行中的局部变量如循环体内中间 Tensor在反向时可能需要使用但 Region 作用域限制使反向 Region 无法直接访问前向 Region 的 Value。PIR 用Stack 机制cf.stack_create/cf.tuple_push/cf.tuple_pop解决分三步构造修改前向在前向控制流中插入cf.tuple_push(%inlet, %x)等操作将反向需要的中间变量压入 Stack构造反向反向 WhileOp body 中按 LIFO 顺序cf.tuple_pop(%outlet)取出前向保存的变量先 pop 后入的 y再 pop x循环条件通过cf.has_elements(%stack)判断 Stack 是否还有元素剪枝反向图构建完成后执行 DCEDead Code EliminationPass移除前向中不被反向使用的tuple_push及对应stack_create。Stack 机制的优势Stack 在控制流 Op 外部创建对所有子 Region 可见作用域安全LIFO 语义天然匹配循环反向的逆序访问未使用的 Stack 可在编译期移除可剪枝IfOp 与 WhileOp 使用同一套机制统一处理。组合算子分解Prim与 Pass 框架将高层算子分解为基础算子primitive operators可降低编译器、分布式、新硬件适配成本前向分解DecompInterface→call_decomp_rule()→ 规则实现位于 composite.h反向分解VJP两条路径——VjpInterface经call_vjp()处理前向 op 的反向DecompVjpInterface经call_decomp_vjp()分解反向 op规则实现均在 details.hCustomVJP为 sigmoid、log_softmax 等数值敏感算子提供手写反向分解调度入口在 decomp_trans.cc基础算子与 VJP 接口分别在 primitive.h 与 vjp.h。PIR 的 Pass 基础设施是 MLIR 风格的Pass为单个优化 Pass 基类通过Run(Operation*)执行PassManager管理 Pass 执行顺序并支持嵌套 PipelinePatternRewritePass基于 Pattern Matching 重写通过RewritePattern定义匹配与替换规则。相关头文件见 paddle/pir/include/pass/ 与 pattern_match.h。ProgramTranslator旧 IR 到 PIR 的翻译ProgramTranslator将旧的ProgramDescprotobuf 描述的静态图翻译为pir::Program遍历每个 Block 中的 OpDesc优先查找OpTranslator::special_handlers_注册表中的特化翻译器如while→pd_op.while、conditional_block→pd_op.if、feed→builtin.parameter、fetch→builtin.set_parameter找不到则回退通用处理器按 OpDesc 的 inputs/outputs/attrs 一一映射构造pir::Operation同时维护 VarName → pir::Value 映射表并对 sub_block 递归翻译。CINN从 PIR Program 到 CUDA KernelCINNCompiler Infrastructure for Neural Networks将 PIR Program 中的算子子图编译为高性能 CUDA Kernel由 PirInterpreter 调度执行。当前默认走动态 shape主线。编译流水线含动态 shapePIR Program (pd_op.*) │ ▼ Stage 1: Frontend前端 ├── ShapeOptimizationPassInferSymbolicShape 符号推导 ├── PdOpToCinnOpPass / PdOpToDynamicShapeCinnOpPass算子映射 ├── add_broadcast_to_elementwise_pass显式 broadcast 插入 └── add_cinn_pass → cinn_op.group按 OpPatternKind 融合 │ ▼ Stage 2: Lowering后端下降 ├── PirCompiler → CompilationTaskper GroupOp │ ├── CompilationCache 查询命中则跳过编译 │ ├── OpLowerCompute → AST IR → Schedule │ ├── DynamicShapeGroupScheduler动态 shape 调度 │ └── LowerToAstVec → LoweredFunc │ ▼ Stage 3: CodeGen代码生成 ├── ir::Module → CodeGenCUDA_Dev → CUDA __global__ source └── nvrtc::Compiler → PTX → cubin → CUfunction │ ▼ Stage 4: Execution执行 └── cinn_runtime.jit_kernel (CINNKernelInfo: fn_ptr symbol_args_map) └── CinnJitInstruction → cuLaunchKernelStage 1 前端算子映射与融合前端负责将 PIR 中的 Paddle 算子映射为 CINN 算子并完成融合PdOp2CinnOpConverter将pd_op.*转换为cinn_op.*大部分一对一如pd_op.relu→cinn_op.relu少数需要拆分或重组add_broadcast_to_elementwise_pass为 elementwise 算子显式插入 broadcastPaddle 算子隐式支持 broadcast 语义但 CINN 后端要求 shape 严格匹配核心的build_cinn_pass将可融合算子聚合为cinn_op.groupGroupOppd_op.relu → pd_op.add → pd_op.sigmoid ↓ build_cinn_pass cinn_op.group { cinn_op.relu → cinn_op.add → cinn_op.sigmoid cinn_op.yield(...) }每个算子被标记一个OpPatternKind决定融合策略Kind含义典型算子kElementWise逐元素计算relu, add, multiplykBroadcast含广播语义broadcast_tokInjective单射映射reshape, transpose, slicekReduction规约操作reduce_sum, reduce_maxkOutFusible规约但输出可继续融合softmax 中间步骤kNonFusible不可融合custom_call, sort融合决策的基本原则kElementWise可与任何非kNonFusible的算子融合kReduction作为消费者时生产者必须是kElementWise或kBroadcastkNonFusible不参与融合、单独成组。Stage 2 LoweringCompute 三层抽象、AST IR 与 SchedulePirCompiler为每个 GroupOp 创建CompilationTask内部通过OpLower执行LowerOps → DoOpSchedule → DoGroupSchedule → PostProcess四步。每个 CINN 算子的计算语义通过三层函数描述pe::Relu(input, output_name) // 第1层算子语义入口Paddle Expressions → lang::Relu(input) // 第2层纯数学表达式 → lang::Compute(domain, lambda) // 第3层通用计算原语 → ComputeOp::Make(name, lambda, shape, reduce_axis) → ir::Tensor (包含 ComputeOp 节点)CINN 内部使用自己的 AST IR不同于 PIRIrNode为基类ExprNodeT派生出表达式节点IntImm/FloatImm立即数、Add/Sub/Mul/Div/Mod算术、_Var_/_Tensor_变量引用、Call/Cast、For/IfThenElse控制流、ScheduleBlock/ScheduleBlockRealize调度块、Load/Store/BufferOp内存操作等_Module_/_LoweredFunc_为顶层容器。LowerToAstVec将 Compute 结果经GenerateFunctionBody→ScheduleBlockRealize→ 嵌套 For 循环包裹 →AllocateBuffers→GenerateFunctionArgumentList→_LoweredFunc_::Make产出 LoweredFunc。调度分两级Op-level Schedule针对单个算子主要处理 Reduce 类算子根据 reduce 轴大小与数据量在 Block Reduce / Warp Reduce / Discrete Reduce 间选择策略Group-level Schedule由DynamicShapeGroupScheduler对融合组做全局调度按顺序执行步骤说明DoLoopAlignment对齐各算子的循环范围DoComputeInline将简单计算内联到消费者OptimizeReduction优化规约算子的并行策略DoHorizontalLoopFusion水平融合合并独立的并行循环DoVerticalLoopFusion垂直融合合并生产者-消费者循环BindCudaAxis绑定循环到 CUDA threadIdx/blockIdxAllocateStorage分配 shared memory 和 local bufferStage 3 CodeGen 与 Stage 4 执行CodeGenCUDA_Dev继承自CodeGenC重写 CUDA 特有语法生成__global__、__shared__、threadIdx.x、__syncthreads()将每个 LoweredFunc 编译为 CUDA__global__函数源码随后nvrtc::Compiler调用 NVIDIA NVRTC 运行时编译 API 生成 PTX → cubinCUDAModule::GetFunction经cuModuleLoadDatacuModuleGetFunction返回 CUfunction 句柄。编译产物通过cinn_runtime.jit_kernel在 PIR 中表示携带CINNKernelInfo含fn_name、fn_ptrCUfunction 指针、infer_shape_fn_ptr、以及动态 shape 符号参数映射symbol_args_map。PdOpLowerToKernelPass将 PIR Program 中的 GroupOp 整体替换为 JitKernelOp。执行层面由CinnJitInstruction负责从CINNKernelInfo获取fn_ptr→ 收集输入输出 Tensor 的 device pointer → 处理动态 int 参数shape 维度等→ 调用cuLaunchKernel。非 CINN 算子则通过 PHI Kernel 常规路径执行。编译缓存CINN 对已编译的 GroupOp 结果进行缓存基于 FusionInfo hash相同结构的子图直接复用已编译 Kernel避免重复编译开销实现在 compilation_cache.cc。完整端到端路径pd_op.relu pd_op.add→ GroupOp → Compute → AST IR → Schedule → LoweredFunc → CUDA source → PTX → CUfunction →cuLaunchKernel。执行器PirInterpreter 的依赖分析与异步调度编译完成的 kernel-level Program 由执行器翻译为可执行的 Instruction 序列核心流程为StandaloneExecutor→InterpreterCore→PirInterpreter。StandaloneExecutor遍历 Plan 中的每个 Job简单场景只有一个 Jobpipeline 并行等场景有多个对每个 Job 依次执行PdOpLowerToKernelPasspd_op → pd_kernel/onednn_kernel、可选InplacePass并创建持有 PirInterpreter 的 InterpreterCore。PirInterpreter 首次Run()执行Build 阶段结果缓存后续 Run 跳过然后进入Scheduling 阶段BuildInstruction遍历pir::Block中每个 Operation按所属 Dialect 创建对应 Instruction——builtin.CombineOp→BuiltinCombineInstructioncf.TuplePushOp/TuplePopOp/YieldOp→ 控制流 Instructionpd_op.IfOp→IfInstruction含 true/false 两个子 PirInterpreterpd_op.WhileOp→WhileInstruction含 body 子 PirInterpreterpd_op.PyLayerOp→PyLayerInstructionpd_kernel普通算子 →PhiKernelInstruction/ 旧算子 →LegacyKernelInstructiononednn_kernel→ OneDNN 系列 Instructioncinn_runtime.jit_kernel→CinnJitInstructioncustom_kernel→CustomKernelInstructionpy_func→PythonFunctionInstruction。控制流 Op 会递归创建子 PirInterpreter 处理内部 Block。BuildInstructionDependences基于数据依赖RAW/WAR/WAW构建有向无环图DAG传递性边被消除以减少冗余同步依赖边按两端 Instruction 的 KernelType 分为 SameThread同类算子放入同一线程 ready queue与 DifferentThread异类算子经线程池 AddTask 跨线程调度每个 Instruction 记录入度dependency_count为 0 时可调度。Stream 调度分析PirStreamAnalyzer::AnalyseAllEventInfo对跨 stream 边分类——kDirectRun同一 stream 连续算子stream 内天然有序无需同步与kEventRun不同 stream 之间的数据依赖用cudaEventRecordcudaEventWait同步每个 Instruction 执行前WaitEvent、执行后RecordEvent。Variable 引用计数计算每个非 persistable Variable 被后续 Instruction 使用的次数归零时 GC 回收内存。Scheduling 阶段为异步调度循环初始化时将dep_count0的 Instruction 推入优先级队列循环内 Pop 最高优先级 Instruction →RunInstructionBaseWaitEvent → 执行 kernel → RecordEvent→RunNextInstructionsDifferentThread 下游入度减一为 0 则 AddTask 到线程池SameThread 下游入度减一为 0 则推入本线程 queue→ GCref_count 为 0 回收内存。线程池驱动多个无依赖 Instruction 并行派发GPU 算子在 CUDA stream 上异步执行线程池仅负责 kernel launch。GC 按平台与模式选型EventGarbageCollectorGPU 默认基于 CUDA event 判断何时安全释放、FastGarbageCollectorCPU 直接释放、AsyncFastGarbageCollector异步快速释放、NoEventGarbageCollector无 event 模式。WhileOp 还支持early GC循环体内 Variable 动态引用计数降为 1 且不再被循环体后续使用时提前回收。调试速查与源码入口调试速查表场景应关注的文件SOT 捕获失败 / fallback 过多opcode_executor.py — 检查未支持的 opcodeSOT SIR 到 Program 编译失败compile_cache.py —to_static(full_graphTrue)环节PIR 动态 shape 推导错误shape_optimization_pass.ccCINN 融合策略问题add_cinn_pass.ccCINN 动态 shape 算子映射pd_to_cinn_pass.cc —PdOpToDynamicShapeCinnOpPassCINN 编译缓存命中 / 未命中compilation_cache.ccCINN Schedule 调试dy_shape_group_scheduler.ccCINN CodeGen CUDA 源码codegen_cuda_dev.cc执行器 Kernel 启动pir_interpreter.cc执行器依赖分析 / 调度stream_analyzer.cc执行器 Variable 内存泄漏paddle/fluid/framework/new_executor/garbage_collector/源码入口速查SOT 模块to_static入口full_graph 分发在 api.pyeval_frame 入口、OpcodeExecutor、OpcodeInlineExecutor、Variable 体系、Tracker、Guard、FunctionGraph、StatementIR、SIR 编译缓存、SideEffect、符号 shape 推导分别位于python/paddle/jit/sot/下对应文件详见上文 SOT 章节。PIR 核心paddle/pir/include/core/下的type.h、value.h、operation.h、block.h、program.hIRContext/StorageManager在 ir_context.cc 与 storage_manager.ccDialect 基类在 dialect.hPaddleDialect 在 op_dialect.h控制流 Dialect 与 Op 实现分别在 paddle/pir/include/dialect/control_flow/ir/ 与 control_flow_op.hShape Dialect 与InferSymbolicShape接口在 paddle/pir/include/dialect/shape/DecompInterface 在 decomp.h。CINN 模块总入口 Pass 与算子融合在 add_cinn_pass.cc 与 cinn_group_cluster_pass.ccPirCompiler、OpLower、编译任务、编译缓存分别在paddle/cinn/hlir/framework/pir_compiler.cc、op_lowering_impl.cc、compilation_task.cc、compilation_cache.ccSchedule、CodeGen、NVRTC 编译在 dy_shape_group_scheduler.cc、codegen_cuda_dev.cc、nvrtc_util.ccCINNKernelInfo与JitKernelOp定义分别在 utils.h 与 jit_kernel_op.h。执行器模块Python 入口在 executor.pyStandaloneExecutor、InterpreterCore、PirInterpreter、ProgramInterpreter旧 IR 兼容、PirStreamAnalyzer 分别在paddle/fluid/framework/new_executor/下的standalone_executor.cc、interpretercore.cc、pir_interpreter.cc、program_interpreter.cc、interpreter/stream_analyzer.ccInstruction 定义与 CinnJitInstruction 在instruction/目录Scope 与 GC 在 scope.cc 与garbage_collector/目录。结语Paddle 3.0 编译器全链路是一套环环相扣的工程体系SOT 以字节码级模拟解决了 AST 动转静无法逾越的互操作与控制流难题PIR 以 MLIR 风格的 SSA、uniquing 类型系统与 concept-model 多态为图优化和算子分解提供了统一、可扩展的中间表示CINN 则以 OpPatternKind 融合、多层 Schedule 与 NVRTC 代码生成将融合子图直接编译为可复用的 CUDA Kernel最终由 PirInterpreter 通过依赖 DAG、多 stream 事件同步与引用计数 GC 完成异步调度执行。掌握「SOT 捕获 → PIR 优化 → CINN 编译 → 执行器调度」这条主线及对应的源码入口是排查动转静失败、shape 推导异常、融合效果不佳与执行性能问题的关键能力。【免费下载链接】PaddlePArallel Distributed Deep LEarning: Machine Learning Framework from Industrial Practice 『飞桨』核心框架深度学习机器学习高性能单机、分布式训练和跨平台部署项目地址: https://gitcode.com/GitHub_Trending/pa/Paddle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →