.agents/skills/paddle-design-eager-graph/references/forward-call-chain.md
本文档详细说明 Paddle 动态图模式下,从 Python API 调用到 PHI Kernel 执行的完整 5 层调用链路。以 paddle.add(x, y) 为例。
前向链路中大部分 C++ 代码由 Python 脚本自动生成:
| 生成的文件 | 生成器脚本 |
|---|---|
paddle/fluid/pybind/ops_api.cc | paddle/fluid/pir/dialect/op_generator/ops_api_gen.py |
paddle/fluid/pybind/eager_op_function.cc | paddle/fluid/eager/auto_code_generator/generator/python_c_gen.py |
dygraph_functions.cc | paddle/fluid/eager/auto_code_generator/generator/eager_gen.py |
paddle/phi/api/lib/api.cc | paddle/phi/api/generator/api_gen.py |
文件:paddle/fluid/pybind/ops_api.cc
入口函数签名:
static PyObject *add(PyObject *self, PyObject *args, PyObject *kwargs)
核心职责:
GetTensorFromArgs 从 PyObject* 中提取 paddle::Tensoreager_api_addGetTensorFromArgs 的作用:
PyObject* 参数和位置索引DenseTensor、DistTensor 等)paddle::Tensor 引用并返回paddle::optional<Tensor>)的情况关键特征:该层代码由 ops_api_gen.py 根据算子 YAML 定义自动生成,开发者一般无需手动修改。
文件:paddle/fluid/pybind/eager_op_function.cc
入口函数签名:
static PyObject *eager_api_add(PyObject *self, PyObject *args, PyObject *kwargs)
执行流程:
参数解析:从 args/kwargs 中解析出所有输入 Tensor 和 Attribute。使用 CastPyArg2xxx 系列函数进行类型转换。
Dist Tensor 转换:若处于分布式模式,将普通 Tensor 转化为 DistTensor,附加分布式 placement 信息。
自定义前处理:部分算子有特殊的前处理逻辑(如参数校验、默认值填充)。
GIL 释放与执行:
{
eager_gil_scoped_release guard;
// 选择 backend,调用层③
out = add_ad_func(x, y);
}
释放 Python GIL 后进入纯 C++ 执行路径,执行完毕后自动重新获取 GIL。
Backend 选择:根据输入 Tensor 所在的设备(CPU/GPU/XPU 等)选择合适的后端。
返回结果:将 C++ paddle::Tensor 包装为 PyObject* 返回给 Python。
文件:paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.cc
入口函数签名:
paddle::Tensor add_ad_func(const paddle::Tensor& x, const paddle::Tensor& y)
这是构建反向图的核心层,执行流程如下:
auto p_autograd_x = egr::EagerUtils::nullable_autograd_meta(x);
auto p_autograd_y = egr::EagerUtils::nullable_autograd_meta(y);
bool trace_backward = egr::Controller::Instance().HasGrad();
bool require_any_grad = egr::EagerUtils::ComputeRequireGrad(
trace_backward, p_autograd_x, p_autograd_y);
只有当全局梯度开启且至少有一个输入需要梯度时,才构建反向图。
auto api_result = paddle::experimental::add(x, y);
若 require_any_grad 为 true,执行以下步骤:
1. 创建 GradNode
auto node = std::shared_ptr<AddGradNode>(new AddGradNode(...));
2. SetTensorWrapper — 保存前向 Tensor 供反向使用
node->SetTensorWrapperx(x);
node->SetTensorWrappery(y);
3. SetGradOutMeta — 建立 GradNode 的出度连接
// 将输入 Tensor 的 AutogradMeta 信息写入 GradNode 的 bwd_out_meta_
node->SetGradOutMeta(x, 0); // slot 0
node->SetGradOutMeta(y, 1); // slot 1
4. SetHistory — 将 GradNode 写入输出 Tensor 的 AutogradMeta
// 建立 out -> GradNode 的连接
egr::EagerUtils::SetHistory(&p_autograd_out, node);
5. SetGradInMeta — 设置 GradNode 的入度信息
// 记录输出 Tensor 的 meta 信息,供反向执行时校验
node->SetGradInMeta(api_result, 0);
反向图边的方向:out.AutogradMeta.grad_node_ 指向当前 GradNode,GradNode.bwd_out_meta_[i].adj_edge_ 指向后继(输入方向的)GradNode。
文件:paddle/phi/api/lib/api.cc
入口函数签名:
Tensor paddle::experimental::add(const Tensor& x, const Tensor& y)
执行流程:
auto kernel_key = ParseKernelKeyByInputArgs(x, y);
// kernel_key = {backend=GPU, layout=NCHW, dtype=float32}
KernelKey 的 32 位 Hash 结构:
|---31-20 扩展---|---19-12 DataType---|---11-8 DataLayout---|---7-0 Backend---|
auto kernel_result = KernelFactory::Instance().SelectKernelOrThrowError(
"add", kernel_key);
KernelFactory 内部维护两级 map:api_name -> {KernelKey -> Kernel}。若找不到精确匹配的 Layout,回退到 ALL_LAYOUT。
将输入 Tensor 转换到目标 backend/dtype/layout:
推导输出 Tensor 的 shape、dtype、layout 等元信息,分配输出内存。
using kernel_signature = void(*)(const Context&, const DenseTensor&,
const DenseTensor&, DenseTensor*);
auto* kernel_fn = kernel_result.kernel.GetVariadicKernelFn<kernel_signature>();
(*kernel_fn)(*dev_ctx, *input_x, *input_y, kernel_out);
最终执行注册在 PHI 算子库中的具体 Kernel 函数。Kernel 按 {算子名, Backend, DataType, DataLayout} 注册,通过宏 PD_REGISTER_KERNEL 完成注册。
Kernel 函数直接操作 DenseTensor(或 SelectedRowsTensor 等),执行底层数学计算。GPU Kernel 会调用 CUDA/HIP kernel launch。
SetTensorWrapper/SetGradOutMeta/SetHistory 是否正确。