chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
---
|
||||
name: paddle-build
|
||||
description: Use when needing to compile, rebuild, or install Paddle from source after code changes. Covers cmake configuration, ninja incremental build, wheel packaging, and common build failure diagnosis.
|
||||
---
|
||||
|
||||
# Paddle 源码编译
|
||||
|
||||
## 概览
|
||||
|
||||
Paddle 使用 CMake + Ninja 构建。典型流程:cmake 配置 → ninja 编译 → whl 打包安装。修改 C++/CUDA 代码后需重新编译才能生效。
|
||||
|
||||
## 编译流程
|
||||
|
||||
### 1. 环境准备(venv)
|
||||
|
||||
```bash
|
||||
cd /workspace/Paddle
|
||||
uv venv --relocatable --seed --python 3.10 # 首次创建
|
||||
source .venv/bin/activate
|
||||
uv pip install -r python/requirements.txt
|
||||
uv pip install func_timeout pandas numpy "numpy<2.0"
|
||||
```
|
||||
|
||||
若 `.venv` 已存在,直接 `source .venv/bin/activate` 即可。
|
||||
|
||||
### 2. CMake 配置
|
||||
|
||||
```bash
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DPY_VERSION=3.10 \
|
||||
-DPADDLE_VERSION=0.0.0 \
|
||||
-DCUDA_ARCH_NAME=Auto \
|
||||
-DWITH_GPU=ON \
|
||||
-DWITH_DISTRIBUTE=ON \
|
||||
-DWITH_CINN=ON \
|
||||
-DWITH_UNITY_BUILD=OFF \
|
||||
-DWITH_TESTING=OFF
|
||||
```
|
||||
|
||||
配置只需首次执行或 CMake 选项变更时重新执行。
|
||||
|
||||
### 3. 编译
|
||||
|
||||
```bash
|
||||
ninja -j$(nproc)
|
||||
```
|
||||
|
||||
Ninja 自动增量编译,仅重编变更文件及其依赖。
|
||||
|
||||
### 4. 安装
|
||||
|
||||
```bash
|
||||
cd /workspace/Paddle
|
||||
uv pip install build/python/dist/*.whl --no-deps --force-reinstall
|
||||
```
|
||||
|
||||
`--no-deps` 跳过依赖解析加速安装,`--force-reinstall` 确保覆盖旧版。
|
||||
|
||||
## 常用 CMake 选项
|
||||
|
||||
| 选项 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `WITH_GPU` | ON(有CUDA时) | GPU 支持 |
|
||||
| `WITH_DISTRIBUTE` | OFF | 分布式训练 |
|
||||
| `WITH_CINN` | OFF | CINN 编译器 |
|
||||
| `WITH_TESTING` | ON | C++ 单测(关闭可加速编译) |
|
||||
| `WITH_UNITY_BUILD` | OFF | 合并编译单元加速(可能掩盖头文件问题) |
|
||||
| `CUDA_ARCH_NAME` | Auto | GPU 架构,Auto 自动检测当前卡 |
|
||||
| `CMAKE_BUILD_TYPE` | Release | Debug 可调试但更慢 |
|
||||
| `CMAKE_EXPORT_COMPILE_COMMANDS` | OFF | 生成 `compile_commands.json` 供 clangd 使用 |
|
||||
| `WITH_TENSORRT` | OFF | TensorRT 推理加速 |
|
||||
| `WITH_ROCM` | OFF | AMD ROCm 支持 |
|
||||
| `WITH_XPU` | OFF | 百度昆仑 XPU 支持 |
|
||||
|
||||
## 增量编译策略
|
||||
|
||||
```dot
|
||||
digraph incremental {
|
||||
"修改了什么?" [shape=diamond];
|
||||
"Python 代码" [shape=box, label="无需编译\n同步源码到构建目录后测试"];
|
||||
"C++/CUDA kernel" [shape=box, label="ninja → 安装 whl"];
|
||||
"CMakeLists / cmake 选项" [shape=box, label="重新 cmake → ninja → 安装 whl"];
|
||||
"YAML (ops/backward)" [shape=box, label="ninja(触发代码生成)→ 安装 whl"];
|
||||
|
||||
"修改了什么?" -> "Python 代码" [label="python/"];
|
||||
"修改了什么?" -> "C++/CUDA kernel" [label="paddle/phi/"];
|
||||
"修改了什么?" -> "CMakeLists / cmake 选项" [label="cmake/"];
|
||||
"修改了什么?" -> "YAML (ops/backward)" [label="ops.yaml 等"];
|
||||
}
|
||||
```
|
||||
|
||||
- **仅改 Python**:无需编译。如果直接在 `build/python` 下编辑测试,改动即时生效。也可以在源码目录编辑后通过 `cp python/<src> build/python/<src>` 或者 `cp test/<src> build/test/<src>` 同步到构建目录。
|
||||
- **改 C++/CUDA**:`cd build && ninja -j$(nproc)` + 重新安装 whl。
|
||||
- **改 CMake 配置**:需重新 `cmake ..` 再 `ninja`。
|
||||
- **改 YAML(ops.yaml / backward.yaml)**:ninja 会自动触发代码生成脚本。
|
||||
|
||||
## 检查已有构建产物
|
||||
|
||||
复用已有 build 可大幅节约时间:
|
||||
|
||||
```bash
|
||||
# 检查是否已有 whl
|
||||
ls build/python/dist/*.whl 2>/dev/null && echo "已有构建产物" || echo "需要编译"
|
||||
|
||||
# 检查 compile_commands.json(clangd 需要)
|
||||
ls build/compile_commands.json 2>/dev/null
|
||||
```
|
||||
|
||||
## 常见编译问题
|
||||
|
||||
| 症状 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| `ninja: error: loading 'build.ninja'` | 未执行 cmake 配置 | 先执行 cmake 命令 |
|
||||
| CUDA arch 不匹配 | `CUDA_ARCH_NAME` 与实际 GPU 不符 | 设为 `Auto` 或指定具体架构 |
|
||||
| 链接时 OOM | 并行链接占用过多内存 | `ninja -j4` 减少并行度 |
|
||||
| protobuf 版本冲突 | 系统 protobuf 与编译版本不一致 | 在 venv 内编译,隔离系统包 |
|
||||
| `ccache` 缓存失效导致全量重编 | 头文件路径变更 | 清理 ccache: `ccache -C` |
|
||||
| whl 安装后 import 报错 | 旧 .so 残留 | `--force-reinstall` 或清理 `site-packages/paddle` |
|
||||
|
||||
## 完整一键编译示例
|
||||
|
||||
```bash
|
||||
cd /workspace/Paddle
|
||||
source .venv/bin/activate
|
||||
cd build
|
||||
ninja -j$(nproc) && cd .. && uv pip install build/python/dist/*.whl --no-deps --force-reinstall
|
||||
```
|
||||
|
||||
## 调试编译(Debug 模式)
|
||||
|
||||
需要 gdb 调试 C++ 代码时,将 `CMAKE_BUILD_TYPE` 改为 `Debug`:
|
||||
|
||||
```bash
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug [其他选项...]
|
||||
ninja -j$(nproc)
|
||||
```
|
||||
|
||||
Debug 模式编译产物更大、运行更慢,仅在需要调试时使用。
|
||||
|
||||
## 关键目录
|
||||
|
||||
| 目录 | 说明 |
|
||||
|------|------|
|
||||
| `build/` | 构建产物根目录 |
|
||||
| `build/python/dist/` | 生成的 whl 文件 |
|
||||
| `build/compile_commands.json` | clangd 索引文件 |
|
||||
| `paddle/phi/kernels/` | PHI kernel 源码 |
|
||||
| `paddle/phi/ops/yaml/` | 算子 YAML 定义 |
|
||||
| `cmake/` | CMake 模块和工具链 |
|
||||
|
||||
## 平台特定指南
|
||||
|
||||
| 平台 | 参考文档 |
|
||||
|------|---------|
|
||||
| macOS (Apple Silicon) CPU 编译 | [references/mac-build.md](references/mac-build.md) |
|
||||
@@ -0,0 +1,161 @@
|
||||
# macOS (Apple Silicon) 源码编译
|
||||
|
||||
在 macOS Apple Silicon (M1/M2/M3/M4 等) 上从源码编译 Paddle 的完整流程。仅支持 CPU 模式(无 GPU/CUDA)。
|
||||
|
||||
## 前置依赖
|
||||
|
||||
通过 Homebrew 安装:
|
||||
|
||||
```bash
|
||||
brew install cmake ninja uv
|
||||
```
|
||||
|
||||
需要的工具和最低版本:
|
||||
- **cmake** >= 3.19.2(Apple Silicon 支持从此版本开始)
|
||||
- **ninja**(推荐,比 make 快很多)
|
||||
- **uv**(Python 环境管理)
|
||||
- **Xcode Command Line Tools**:`xcode-select --install`
|
||||
|
||||
## 编译流程
|
||||
|
||||
### 1. 创建 Python 虚拟环境
|
||||
|
||||
```bash
|
||||
cd /path/to/Paddle
|
||||
PY_VERSION=3.10
|
||||
VENV_DIR=venvs/paddle-py${PY_VERSION//./}
|
||||
|
||||
uv venv --seed ${VENV_DIR} --python=${PY_VERSION}
|
||||
source ${VENV_DIR}/bin/activate
|
||||
uv pip install -r python/requirements.txt
|
||||
```
|
||||
|
||||
### 2. 获取 Python 路径
|
||||
|
||||
macOS 上需要显式指定 Python 库和头文件路径:
|
||||
|
||||
```bash
|
||||
PY_LIB_DIR=$(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
|
||||
PY_INCLUDE_DIR=$(python -c "import sysconfig; print(sysconfig.get_paths()['include'])")
|
||||
PY_LIBRARY=${PY_LIB_DIR}/libpython${PY_VERSION}.dylib
|
||||
```
|
||||
|
||||
### 3. CMake 配置
|
||||
|
||||
```bash
|
||||
mkdir -p build && cd build
|
||||
rm -rf CMakeCache.txt CMakeFiles/ # 首次或切换配置时需要清理
|
||||
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DPY_VERSION=${PY_VERSION} \
|
||||
-DPYTHON_INCLUDE_DIR=${PY_INCLUDE_DIR} \
|
||||
-DPYTHON_LIBRARY=${PY_LIBRARY} \
|
||||
-DWITH_GPU=OFF \
|
||||
-DWITH_ARM=ON \
|
||||
-DWITH_AVX=OFF \
|
||||
-DWITH_TESTING=ON \
|
||||
-DWITH_DISTRIBUTE=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
```
|
||||
|
||||
关键选项说明:
|
||||
|
||||
| 选项 | 值 | 原因 |
|
||||
|------|----|------|
|
||||
| `WITH_GPU` | OFF | macOS 无 CUDA |
|
||||
| `WITH_ARM` | ON | Apple Silicon 是 ARM 架构 |
|
||||
| `WITH_AVX` | OFF | ARM 无 AVX 指令集,`WITH_ARM=ON` 时自动禁用 |
|
||||
| `WITH_DISTRIBUTE` | OFF | macOS 不支持 NCCL 等分布式通信库 |
|
||||
| `WITH_TESTING` | ON/OFF | ON 编译测试二进制(更慢),OFF 跳过(更快) |
|
||||
| `CMAKE_EXPORT_COMPILE_COMMANDS` | ON | 生成 `compile_commands.json` 供 clangd/IDE 使用 |
|
||||
|
||||
### 4. 编译
|
||||
|
||||
```bash
|
||||
ninja -j$(sysctl -n hw.ncpu)
|
||||
```
|
||||
|
||||
macOS 使用 `sysctl -n hw.ncpu` 获取 CPU 核数(Linux 用 `nproc`)。
|
||||
|
||||
首次全量编译约需 30-60 分钟(取决于机器配置和 `WITH_TESTING` 开关)。后续增量编译通常几秒到几分钟。
|
||||
|
||||
### 5. 安装
|
||||
|
||||
```bash
|
||||
cd /path/to/Paddle
|
||||
uv pip install build/python/dist/*.whl --no-deps --force-reinstall
|
||||
```
|
||||
|
||||
### 6. 验证
|
||||
|
||||
```bash
|
||||
python -c "import paddle; print(paddle.__version__); paddle.utils.run_check()"
|
||||
```
|
||||
|
||||
## 一键脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
PY_VERSION=${1:-3.10}
|
||||
PADDLE_DIR=$(pwd)
|
||||
VENV_DIR=${PADDLE_DIR}/venvs/paddle-py${PY_VERSION//./}
|
||||
|
||||
# 环境准备
|
||||
if [ ! -d ${VENV_DIR} ]; then
|
||||
uv venv --seed ${VENV_DIR} --python=${PY_VERSION}
|
||||
fi
|
||||
source ${VENV_DIR}/bin/activate
|
||||
uv pip install -r python/requirements.txt
|
||||
|
||||
# Python 路径
|
||||
PY_LIB_DIR=$(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
|
||||
PY_INCLUDE_DIR=$(python -c "import sysconfig; print(sysconfig.get_paths()['include'])")
|
||||
|
||||
# CMake 配置 + 编译
|
||||
mkdir -p build && cd build
|
||||
rm -rf CMakeCache.txt CMakeFiles/
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DPY_VERSION=${PY_VERSION} \
|
||||
-DPYTHON_INCLUDE_DIR=${PY_INCLUDE_DIR} \
|
||||
-DPYTHON_LIBRARY=${PY_LIB_DIR}/libpython${PY_VERSION}.dylib \
|
||||
-DWITH_GPU=OFF \
|
||||
-DWITH_ARM=ON \
|
||||
-DWITH_AVX=OFF \
|
||||
-DWITH_TESTING=OFF \
|
||||
-DWITH_DISTRIBUTE=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
ninja -j$(sysctl -n hw.ncpu)
|
||||
|
||||
# 安装
|
||||
cd ${PADDLE_DIR}
|
||||
uv pip install build/python/dist/*.whl --no-deps --force-reinstall
|
||||
python -c "import paddle; print(paddle.__version__)"
|
||||
```
|
||||
|
||||
## macOS 特有的常见问题
|
||||
|
||||
| 症状 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| `Ignoring CMAKE_OSX_SYSROOT` + 配置失败 | pip 安装的 cmake 无法找到系统 SDK | 用 `brew install cmake` 的系统 cmake,不要用 venv 中的 |
|
||||
| `failed to recurse into submodule` | git worktree 残留导致 submodule config 中路径失效 | 修复 `.git/modules/*/config` 中的 `worktree` 路径,或 `git submodule deinit -f . && git submodule update --init --recursive` |
|
||||
| `CMakeCache.txt directory is different` | build 目录从别的路径(如 worktree)复制过来 | `rm -rf CMakeCache.txt CMakeFiles/` 清理缓存后重新 cmake |
|
||||
| `WITH_AVX` 相关编译错误 | 未设置 `WITH_ARM=ON` 导致尝试使用 x86 指令集 | 添加 `-DWITH_ARM=ON -DWITH_AVX=OFF` |
|
||||
| 链接时 `symbol not found` | SDK 或系统库版本不匹配 | 确保 Xcode CLT 是最新版本:`xcode-select --install`,并检查 `SDKROOT` 设置(如 `export SDKROOT=$(xcrun --show-sdk-path)`) |
|
||||
| `libpython*.dylib not found` | Python 路径不正确 | 用 `sysconfig` 动态获取路径,不要硬编码 |
|
||||
|
||||
## 与 Linux 编译的主要差异
|
||||
|
||||
| 方面 | Linux (x86_64 + CUDA) | macOS (Apple Silicon) |
|
||||
|------|----------------------|----------------------|
|
||||
| 架构标志 | 默认 x86_64 | `-DWITH_ARM=ON -DWITH_AVX=OFF` |
|
||||
| GPU | `-DWITH_GPU=ON` | `-DWITH_GPU=OFF` |
|
||||
| BLAS | MKL | Apple Accelerate(自动检测) |
|
||||
| CPU 核数 | `nproc` | `sysctl -n hw.ncpu` |
|
||||
| Python lib | `.so` | `.dylib` |
|
||||
| 分布式 | NCCL 支持 | 不支持 |
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: paddle-cross-ecosystem-custom-op
|
||||
description: 将原生 PyTorch 自定义算子库、Torch extension、生态库(TorchCodec/FlashInfer/DeepEP 等)以及 Kernel DSL 生态(Triton/TileLang/TVM FFI 等)以最小修改方式接入 PaddlePaddle。遇到以下场景务必使用:迁移外部算子库到 Paddle;分析 PFCCLab fork 与上游的兼容差异;处理 paddle.enable_compat、paddle.utils.cpp_extension、TORCH_LIBRARY、torch.ops、at::Tensor/c10 compat 问题;为 compat gap 设计最小 workaround 并准备 Paddle issue 最小复现。
|
||||
---
|
||||
|
||||
# Paddle 跨生态自定义算子迁移
|
||||
|
||||
## 任务定义
|
||||
|
||||
这个 skill 只做一件事:让上游 PyTorch 自定义算子仓库在 Paddle 上按原来的调用路径跑起来,同时保持后续 rebase / sync upstream 的能力。
|
||||
|
||||
一次完整的输出应该覆盖四个方面:
|
||||
|
||||
- 迁移方案
|
||||
- 最小修改边界
|
||||
- 验证路径
|
||||
- compat gap 处理策略
|
||||
|
||||
## 核心约束
|
||||
|
||||
- **最小修改**:不做额外格式化、优化、重构,不主动改公共 API。
|
||||
- **上游同步**:所有改动都要考虑后续 rebase / sync upstream 的便利性。
|
||||
- **compat 优先**:优先使用 Paddle 现有的 compat 机制,让 compat 层承担兼容职责。
|
||||
- **缺口要明确**:compat gap 要分类清楚、标明边界,并准备最小复现。
|
||||
- **验证要闭环**:至少跑通一条最小 build/test 路径。
|
||||
|
||||
## 工作顺序
|
||||
|
||||
1. 识别上游仓库、当前 fork、默认分支和实际迁移分支。PFCCLab 适配仓库的默认分支通常是 `paddle`,比较前先确认 parent 和默认分支。
|
||||
2. 按控制面把仓库分成四层:
|
||||
- 框架无关的内核 / 算法
|
||||
- 构建与打包
|
||||
- C++ compat API / 注册
|
||||
- Python 包装 / runtime glue / tests
|
||||
3. 如果任务是分析多个 PFCCLab fork,且用户明确要求并行,按仓库拆分并行分析;每个子任务都要输出 parent、比较分支、四层 diff 归类和可复用模式。
|
||||
4. 先确定第一轮改动的位置。首轮补丁通常集中在 build、runtime glue、device / stream / distributed 边界。
|
||||
5. 沿最小路径逐步推进验证:build → import → 最小功能测试 → 运行时对照。
|
||||
|
||||
## 默认改动边界
|
||||
|
||||
通常不需要动的部分:
|
||||
|
||||
- CUDA/C++ 核心 kernel 与算法逻辑
|
||||
- 原有 schema 定义
|
||||
- 大部分 `TORCH_LIBRARY` / pybind11 注册代码
|
||||
- 上游目录结构与 Python package 形状
|
||||
|
||||
通常需要先检查的部分:
|
||||
|
||||
- `setup.py` / `pyproject.toml`
|
||||
- 入口脚本、测试脚本、示例脚本
|
||||
- `torch.ops` / `torch.library` / `torch._dynamo` / `torch.profiler` 使用点
|
||||
- device / stream / distributed / DLPack / custom op registration glue
|
||||
|
||||
## 具体规则
|
||||
|
||||
- `setup.py` / `pyproject.toml`:优先加 `paddle.enable_compat()`,保留原有 `from torch.utils import cpp_extension` 的写法;只有代理路径覆盖不到时,才最小化地切到 `paddle.utils.cpp_extension` 或局部调整 include / lib / flags。
|
||||
- `TORCH_LIBRARY` / `TORCH_LIBRARY_IMPL` / pybind11:默认先保持原样,等编译或运行时真正失败了再定位具体缺口。
|
||||
- `at::Tensor` / `c10::TensorOptions` / `torch::empty` 等 C++ API:优先依赖 compat headers;遇到缺口时只桥接单个 API 点。
|
||||
- Python 入口与测试:运行时优先使用 `paddle.enable_compat(scope={...})`;短生命周期的 build script 可以用全局 `paddle.enable_compat()`。
|
||||
- 分布式 / stream / device:先把运行时上下文边界接上,再看是否需要深入 `phi::GPUContext`、`ProcessGroup`、DLPack 或 stream wrapper。
|
||||
- 分析 PFCCLab fork:输出要提炼成可复用的模式,覆盖 build / C++ / Python / tests 四层。
|
||||
|
||||
## 按需读取参考材料
|
||||
|
||||
不要一次性读取全部 reference。按当前任务只打开需要的文件:
|
||||
|
||||
| 当前任务 | 读取文件 |
|
||||
|---|---|
|
||||
| 先理解跨生态机制和分层口径 | [机制总览](references/mechanism-overview.md) |
|
||||
| 实际迁移一个新仓库 | [迁移手册](references/migration-playbook.md) |
|
||||
| 把错误定位到 Paddle 仓库内部 | [Paddle 内部锚点](references/paddle-internals.md) |
|
||||
| 分析 PFCCLab fork 或复用既有迁移经验 | [生态库差异模式](references/ecosystem-diff-patterns.md) |
|
||||
| 判断 compat gap、workaround、issue MRE | [compat 缺口处理](references/compat-gap-policy.md) |
|
||||
| build/import 已通但运行时行为不一致 | [运行时调试](references/runtime-debugging.md) |
|
||||
|
||||
## 输出要求
|
||||
|
||||
- 明确列出哪些文件不需要动、哪些文件需要改、每一处改动对应哪一层。
|
||||
- 如果需要 workaround,必须写清楚覆盖范围、删除条件,以及是否需要提 Paddle issue。
|
||||
- 如果问题进入运行时对照阶段,要指出第一次差异出现在哪一行、哪个调用点、属于哪一层。
|
||||
- 如果分析的是现有 fork,要总结出可复用的迁移顺序,并把 diff 提炼成稳定模式。
|
||||
|
||||
## 完成前检查
|
||||
|
||||
- 没有无关的格式化、清理、重命名。
|
||||
- 保留了上游目录结构和主要 API 形状。
|
||||
- 运行时的 `enable_compat` 已尽量限定 `scope`;build script 的全局 compat 只用在构建入口。
|
||||
- build/test 至少跑通了一条最小路径。
|
||||
- compat gap 已经准备了 issue MRE,或在结果中明确写出了缺口与临时 workaround。
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"skill_name": "paddle-cross-ecosystem-custom-op",
|
||||
"evals": [
|
||||
{
|
||||
"id": 1,
|
||||
"prompt": "请把一个使用 torch.utils.cpp_extension 和 TORCH_LIBRARY 的简单 PyTorch 自定义算子仓库迁移到 Paddle,要求只做最小修改,明确哪些文件不动,哪些文件要改,并区分 build script 的全局 paddle.enable_compat 与运行时 scoped paddle.enable_compat。",
|
||||
"expected_output": "输出应按 build / C++ / Python / tests 分层,build 层优先保留 torch.utils.cpp_extension import 并只加 paddle.enable_compat,优先保留注册代码和 kernel 逻辑,只修改测试入口和少量 compat 缺口。",
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"prompt": "请分析 PFCCLab/flashinfer 相对上游 flashinfer-ai/flashinfer 的改动,并总结哪些修改是 build 层、哪些是 Python glue、哪些属于框架兼容 workaround。",
|
||||
"expected_output": "输出应先确认 PFCCLab fork 的实际迁移分支和 upstream 分支,再按层分类改动,指出显式 workaround 和 compat gap 风险,而不是只罗列文件或盲目比较 main...main。",
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"prompt": "某个迁移中的自定义算子在 Paddle 编译时报错:torch::empty 不存在。请按最小修改原则给出局部桥接方案,并说明是否需要为 compat 缺口准备 Paddle issue 最小复现。",
|
||||
"expected_output": "输出应提供单点 C++ bridge 思路,说明为什么不应全量重写 tensor 逻辑,并给出 issue MRE 的边界。",
|
||||
"files": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
# compat 缺口处理
|
||||
|
||||
compat gap 处理的核心目标:把问题边界讲清楚,把 workaround 收敛在最小范围,并为后续的 Paddle 修复准备最小复现。
|
||||
|
||||
## 先做问题分类
|
||||
|
||||
### A. Paddle compat 覆盖缺口
|
||||
|
||||
典型特征:
|
||||
|
||||
- 常见 `at::*` / `torch::*` / `c10::*` API 当前没有 compat 实现
|
||||
- `TORCH_LIBRARY` / `torch.ops` / proxy 行为与现有 compat 测试不一致
|
||||
- 生态库依赖的是 PyTorch 公共 API,但在 Paddle compat 下失败
|
||||
|
||||
### B. 上游仓库依赖 PyTorch 私有行为
|
||||
|
||||
典型特征:
|
||||
|
||||
- 依赖 `torch._dynamo`、`torch.profiler`、`torch.library`、内部状态缓存、私有 module side effect
|
||||
- 依赖 PyTorch 当前的 import 顺序、模块级初始化、副作用或内部 handle
|
||||
|
||||
这类问题的处理重点是边界说明和最小 shim;是否属于 Paddle bug 要根据最小复现来判断。
|
||||
|
||||
## 处理顺序
|
||||
|
||||
1. 先拿到最小报错点。
|
||||
2. 把失败收缩成最小复现。
|
||||
3. 明确归类为 compat 覆盖缺口还是上游私有假设。
|
||||
4. 只写最小 workaround,同时写清删除条件。
|
||||
5. 应由 Paddle 修复的问题,准备 issue;如果只是当前仓库的构建入口选择或上游私有假设,不要制造假的 Paddle issue。
|
||||
|
||||
## 最小复现要求
|
||||
|
||||
最小复现应尽量满足:
|
||||
|
||||
- 单文件或极小目录结构
|
||||
- 最少依赖
|
||||
- 明确版本:Paddle commit / wheel 版本、Python、CUDA、驱动
|
||||
- 明确命令:build 命令、运行命令
|
||||
- 明确期望行为和实际报错
|
||||
|
||||
优先级更高的形式:
|
||||
|
||||
- 单个 `.py` 脚本
|
||||
- 极小 `setup.py + csrc/*.cc` 样例
|
||||
- 如果必须用分布式,再补一份单卡或伪最小脚本,并说明收缩边界
|
||||
|
||||
## Paddle issue 建议模板
|
||||
|
||||
标题建议:
|
||||
|
||||
```text
|
||||
[Cross-Ecosystem Custom Op] <具体 API / 行为> is missing or inconsistent in Paddle compat layer
|
||||
```
|
||||
|
||||
正文建议至少包含:
|
||||
|
||||
- Paddle 版本 / commit
|
||||
- Python / CUDA / 驱动版本
|
||||
- 最小复现代码
|
||||
- 运行命令
|
||||
- 期望行为
|
||||
- 实际行为
|
||||
- 对照:相同代码在 PyTorch 下是否正常
|
||||
- 临时 workaround(如果有)
|
||||
|
||||
## workaround 边界
|
||||
|
||||
workaround 适合在以下条件下使用:
|
||||
|
||||
- 只包住一个具体 incompatibility 点
|
||||
- 只影响当前库的局部路径
|
||||
- 公共 API 语义保持不变
|
||||
- 代码里带 TODO,最好有 issue 编号或待跟踪说明
|
||||
|
||||
不是所有 Paddle-specific 改动都需要 issue。比如直接使用 `paddle.utils.cpp_extension` 可能只是当前构建系统下最小的入口选择;只有当它明确绕过了 `torch.utils.cpp_extension` proxy / compat 的公共缺口时,才把它升级为 Paddle issue。
|
||||
|
||||
一旦出现以下信号,就应该转向 issue 与边界收缩:
|
||||
|
||||
- 为一个缺口连续改动多个核心 kernel
|
||||
- 已经开始改变库的原始语义
|
||||
- 已经依赖 Paddle 内部私有 API 才能继续
|
||||
- 相同模式在多个文件重复出现,说明问题已超出单点
|
||||
|
||||
## TODO 写法建议
|
||||
|
||||
推荐写法:
|
||||
|
||||
```text
|
||||
TODO(<owner or issue>): remove this workaround after Paddle compat supports <specific API/behavior>
|
||||
```
|
||||
|
||||
TODO 至少要说明:
|
||||
|
||||
- workaround 在解决什么问题
|
||||
- 当前为什么需要它
|
||||
- 未来怎样删除
|
||||
|
||||
## 什么时候应立即转向 issue
|
||||
|
||||
出现以下情况时,应优先整理 issue MRE:
|
||||
|
||||
- 同一调用点上,PyTorch 与 Paddle 的行为已经明确分叉
|
||||
- 问题来自 compat 公共行为
|
||||
- workaround 开始在多个文件扩散
|
||||
- 后续推进已经需要依赖 Paddle 内部私有接口
|
||||
|
||||
## 一个总判断标准
|
||||
|
||||
如果当前方案已经开始系统性改写整个 PyTorch 生态库的 API 形状,说明补丁边界需要回收。兼容方案应尽量保留上游形状,让 compat 层承担兼容职责,只在缺口位置放置最小桥接。
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
# 生态库差异模式
|
||||
|
||||
这份总结按控制面分类整理了 PFCCLab 现有适配仓库的迁移经验,重点关注三个问题:
|
||||
|
||||
- 这类库的主要控制面在哪里
|
||||
- 第一轮补丁应该落在哪一层
|
||||
- 哪些部分适合保持不变
|
||||
|
||||
参考对照如下:
|
||||
|
||||
- PFCCLab/DeepEP 对照 deepseek-ai/DeepEP
|
||||
- PFCCLab/tilelang-paddle 对照 tile-ai/tilelang
|
||||
- PFCCLab/paddlecodec 对照 meta-pytorch/torchcodec
|
||||
- PFCCLab/flashinfer 对照 flashinfer-ai/flashinfer
|
||||
- PFCCLab/FlashMLA 对照 deepseek-ai/FlashMLA
|
||||
- PFCCLab/sonic-moe 对照 Dao-AILab/sonic-moe
|
||||
- PFCCLab/DeepGEMM 对照 deepseek-ai/DeepGEMM
|
||||
|
||||
实际做 diff 前先确认 `parent` 和默认分支。PFCCLab 适配仓库的迁移分支通常是 `paddle`,而上游多为 `main`。
|
||||
|
||||
推荐先查元数据,再 compare:
|
||||
|
||||
```bash
|
||||
gh repo view PFCCLab/flashinfer --json parent,defaultBranchRef
|
||||
gh api repos/flashinfer-ai/flashinfer/compare/main...PFCCLab:paddle --jq '.files[].filename'
|
||||
```
|
||||
|
||||
不同仓库的 base/head 可能不一样,以上命令只是形状示例;不要在未确认分支前套用。
|
||||
|
||||
## 先做控制面分类
|
||||
|
||||
| 仓库 | 主控制面 | 第一落点 | 通常不动的部分 |
|
||||
|---|---|---|---|
|
||||
| DeepEP | distributed / communicator / stream | runtime glue | collective kernel 与算法主体 |
|
||||
| tilelang-paddle | adapter / device / stream / DLPack | runtime adapter | lowering 与 DSL 主体 |
|
||||
| paddlecodec | Python glue / private API shim | wrapper 与薄 shim | C++ custom op 主体 |
|
||||
| flashinfer | runtime feature gate / device 语义 / workaround 边界 | wrapper 与创建路径 | kernel 主体 |
|
||||
| FlashMLA | benchmark / profiler / harness | 验证层隔离 | 主算子路径 |
|
||||
| sonic-moe | import-time patch / Triton runtime wrapper | import 与 runtime 边界 | Triton kernel 主体 |
|
||||
| DeepGEMM | build / runtime header / macro 前提 | build 与 header | GEMM 内核与算法主体 |
|
||||
|
||||
选择第一落点时,可以直接参考这张表:
|
||||
|
||||
- diff 主要集中在 `setup.py`、编译标志、runtime header → 第一落点通常是 build / header
|
||||
- diff 主要集中在 device、stream、group、communicator helper → 第一落点通常是 runtime glue
|
||||
- diff 主要集中在 wrapper、private API shim、`torch._dynamo` / `torch.profiler` helper → 第一落点通常是 Python glue
|
||||
- diff 主要集中在 `paddle_test/`、benchmark、profiler harness → 第一落点通常是验证层隔离
|
||||
|
||||
## DeepEP:控制面在分布式上下文
|
||||
|
||||
这类库最关键的对象是 ProcessGroup、communicator、stream、event 以及相关上下文。通信 kernel 通常不需要动,迁移工作主要集中在这些上下文如何获取、如何传入底层。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- runtime glue
|
||||
- distributed context bridge
|
||||
- communicator / stream 初始化
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果上游代码默认"拿到一个 PyTorch group 对象后,后续通信都建立在这套语义上",迁移时应该先把 group 到 communicator/context 的桥接接好,再跑最小单测。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `setup.py`:确认 build 入口如何声明分布式相关能力
|
||||
- `csrc/deep_ep.hpp`:看 runtime context、communicator、stream 成员如何组织
|
||||
- `csrc/deep_ep.cpp`:看 communicator/context 初始化落点
|
||||
- `deep_ep/buffer.py`:看 Python 侧 group、event、stream 如何传到底层
|
||||
- `tests/utils.py`:看最小分布式测试如何起环境和 group
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- 先把 distributed glue 和上下文边界对齐
|
||||
- stream / event / communicator 初始化是一等公民,不能绕过
|
||||
- 依赖 Paddle 分布式内部接口时,要把依赖收敛在最小入口
|
||||
|
||||
## tilelang-paddle:控制面在 adapter 与 runtime
|
||||
|
||||
这类库的主体是编译器或 DSL,跨框架迁移时最常遇到的控制点是 current device、current stream、DLPack、JIT runtime 初始化。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- runtime adapter
|
||||
- device helper
|
||||
- stream helper
|
||||
- DLPack bridge
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果某个 backend 在导入库时默认依赖已经初始化好的 CUDA runtime,迁移时通常需要补 runtime preload 或 adapter,让环境准备在导入阶段就稳定下来。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `tilelang/__init__.py`:看导入阶段的 runtime preload 与环境准备
|
||||
- `tilelang/jit/adapter/base.py`:看 current device/current stream 的共用入口
|
||||
- `tilelang/jit/adapter/tvm_ffi.py`:看 backend 如何把框架张量送进 FFI
|
||||
- `tilelang/contrib/dlpack.py`:看跨框架张量协议边界
|
||||
- `tests_paddle/`:看当前已验证的 backend 路径
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- adapter 层通常就是第一轮补丁的位置
|
||||
- DLPack、device、stream 是最稳定的观察点
|
||||
- backend 较多时,先把主路径跑通,再逐步扩展
|
||||
|
||||
## paddlecodec:控制面在 Python glue
|
||||
|
||||
这类库表面上是 C++ custom op,但实际迁移中更关键的是 Python 层对 `torch.ops`、`torch._dynamo`、buffer 创建、metadata 管理的依赖。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- wrapper
|
||||
- 薄 shim
|
||||
- 私有 API 依赖边界
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果上游只要求存在一个类似 `torch._dynamo` 的对象来屏蔽某段图优化,迁移时可以先放一个最小 shim,让运行路径继续前进,同时把边界记录清楚。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `src/torchcodec/_core/ops.py`:看最厚的 Python glue
|
||||
- `src/torchcodec/_core/CMakeLists.txt`:看 C++ 扩展最终如何链接到 Paddle 侧库
|
||||
- `setup.py`:看打包入口的最小切换点
|
||||
- `src/torchcodec/__init__.py`:看对外 API 形状
|
||||
- `test_paddle/`:看当前验证覆盖了哪些用户路径
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- Python glue 很厚时,薄 shim 是性价比最高的入口
|
||||
- shim 要带边界与删除条件
|
||||
- shim 数量开始扩散时,应回查 compat gap
|
||||
|
||||
## flashinfer:控制面在 runtime feature gate 与 workaround 边界
|
||||
|
||||
这类高性能推理库的 kernel 主体通常比较稳定,跨框架迁移更常见的工作集中在 device 语义、custom op registration、通信路径以及 runtime feature gate。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- feature gate
|
||||
- 张量创建路径
|
||||
- wrapper 与 registration fallback
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果某条路径只在创建张量时触发 Paddle 当前行为差异,最小补丁通常应落在这个创建点,并同步整理 issue MRE。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `flashinfer/utils.py`:看 feature gate、device 判断、registration fallback
|
||||
- `flashinfer/fused_moe/core.py`:看高频运行路径里的框架分支
|
||||
- `flashinfer/comm/trtllm_ar.py`:看通信和张量创建路径
|
||||
- `flashinfer/decode.py`:看用户入口如何把 device/place 一路传下去
|
||||
- `tests/conftest.py`:看测试入口的 compat 范围与环境准备
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- feature gate 是定位 runtime 分支的重要线索
|
||||
- workaround 最适合停留在最小创建路径或最小 wrapper 层
|
||||
- 同类 workaround 开始扩散时,要转向 compat gap 处理
|
||||
|
||||
## FlashMLA:控制面在验证层隔离
|
||||
|
||||
这类仓库的常见情况是主算子路径已经基本跑通,主要差异集中在测试、benchmark、profiler 和验证脚本。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- Paddle 专用验证层
|
||||
- benchmark / profiler harness
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果 profiler 路径依赖 PyTorch 的私有上下文管理,而算子本身已经能正确计算,迁移工作更适合停留在 benchmark/test harness 层面。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `setup.py`:确认主构建入口的修改规模
|
||||
- `paddle_test/`:区分主实现问题与 Paddle 专用验证问题
|
||||
- `paddle_test/kernelkit/bench.py`:看 benchmark/profiler 适配如何组织
|
||||
- `flash_mla/flash_mla_interface.py`:看主算子入口是否已经稳定
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- 主实现和验证层要分开判断
|
||||
- 主路径已通时,外围验证体系适合独立收敛
|
||||
- profiler 差异本身不能直接推导出算子主体有问题
|
||||
|
||||
## sonic-moe:控制面在 import-time patch 与 Triton runtime wrapper
|
||||
|
||||
这类库的高频工作点通常是 Triton runtime wrapper、import 阶段的框架假设、stream 与 DLPack 边界。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- import-time patch
|
||||
- runtime wrapper
|
||||
- stream / DLPack helper
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果某个 Triton helper 只要求在编译阶段看到一组熟悉的 `torch` 命名空间语义,最小补丁往往适合停在 wrapper 层或 import 边界。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `sonicmoe/__init__.py`:看 import-time patch 是否集中在入口
|
||||
- `sonicmoe/triton_utils.py`:看 Triton runtime 隔离层
|
||||
- `sonicmoe/utils.py`:看 stream、DLPack、wrapper 共用逻辑
|
||||
- `sonicmoe/moe.py`:看业务入口如何串起 runtime 假设
|
||||
- `sonicmoe/functional/`:看 patch 是否已经扩散过深
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- import-time patch 的重量直接反映 compat 边界压力
|
||||
- Triton 生态常从 wrapper 与 runtime 边界切入
|
||||
- monkey patch 需要配合删除条件和 compat gap 判断
|
||||
|
||||
## DeepGEMM:控制面在 build 与 runtime header
|
||||
|
||||
这类库的 kernel 与算法主体通常高度框架无关,迁移价值主要来自把补丁收敛在 build、宏和 runtime header 边界。
|
||||
|
||||
### 第一落点
|
||||
|
||||
- `setup.py`
|
||||
- 编译标志
|
||||
- runtime header
|
||||
|
||||
### 一个具体例子
|
||||
|
||||
如果上游只在编译入口和少量 runtime header 里假设了 PyTorch 扩展环境,迁移时最自然的做法就是把补丁收在 build 入口和必要宏上。
|
||||
|
||||
### 优先查看的文件
|
||||
|
||||
- `setup.py`:看 build 入口如何最小切换
|
||||
- `csrc/jit/device_runtime.hpp`:看 device runtime、stream、环境前提
|
||||
- `csrc/jit/compiler.hpp`:看 JIT 编译边界需要哪些宏与运行时条件
|
||||
- `csrc/python_api.cpp`:看 Python 到 C++ 的入口形状
|
||||
- `tests/`:看最小验证是否覆盖真实用户路径
|
||||
|
||||
### 可复用结论
|
||||
|
||||
- 框架无关核心越多,patch 面越要克制
|
||||
- build / header 经常就是足够的迁移边界
|
||||
- capability 假定要通过最小验证逐条确认
|
||||
|
||||
## 新库如何复用这些案例
|
||||
|
||||
### 第一步:先判断主控制面
|
||||
|
||||
新库通常会更接近以下四类之一:
|
||||
|
||||
- 普通 extension:build、compat 头、最小测试
|
||||
- distributed / stream glue 较重:运行时上下文和通信桥接
|
||||
- Python glue 较重:wrapper、私有 API 依赖、薄 shim
|
||||
- DSL / compiler:adapter、DLPack、current device/current stream
|
||||
|
||||
### 第二步:复用判断顺序
|
||||
|
||||
真正可复用的是判断顺序:
|
||||
|
||||
1. 先定位主控制面
|
||||
2. 再确定第一落点
|
||||
3. 最后圈出适合保持不变的部分
|
||||
|
||||
### 第三步:用 rebase 能力做最终校验
|
||||
|
||||
如果迁移方案开始显著破坏 upstream rebase 能力,或者开始系统性改写上游 API 形状,说明当前补丁边界需要重新收缩。
|
||||
@@ -0,0 +1,114 @@
|
||||
# 机制总览
|
||||
|
||||
跨生态迁移要维持一条完整的控制路径:先让 build 和 import 跑通,再让 Python wrapper 正确地把参数传到注册层,注册层把调用分发到 C++ 实现,最后 C++ compat 层维持 Tensor 和设备语义的一致性。官方文档把这套机制组织成四层。
|
||||
|
||||
## 官方口径的四层兼容机制
|
||||
|
||||
| 迁移问题 | 对应层 | 主要锚点 | 常见信号 |
|
||||
|---|---|---|---|
|
||||
| C++ 调用能否编译并保持 Tensor 语义 | C++ API 兼容层 | `paddle/phi/api/include/compat/` | `at::*` / `torch::*` / `c10::*` 缺失,或 device / dtype / place 语义偏差 |
|
||||
| 算子如何注册与调度 | 算子注册兼容层 | `torch/library.h`、`torch/library.cpp`、`torch_compat.h` | `torch.ops` 找不到算子、schema 不匹配、dispatch 错位 |
|
||||
| Python wrapper 是否保持参数与 metadata 语义 | Python 接口兼容层 | 外部库自己的 wrapper 与 helper | 参数重排、shape / dtype / place 在进入 C++ 前已经偏了 |
|
||||
| `import torch` 如何映射到 Paddle | Python API 代理层 | `paddle.enable_compat()`、`python/paddle/compat/proxy.py` | import 行为异常、scope 边界不对、代理模块缺失 |
|
||||
|
||||
### 1. C++ API 兼容层
|
||||
|
||||
这一层负责处理 C++ 侧常见的 `at::*`、`torch::*`、`c10::*` 调用,让上游自定义算子代码尽量不改就能继续编译。
|
||||
|
||||
- 代码锚点:`paddle/phi/api/include/compat/`
|
||||
- 常见入口:
|
||||
- `ATen/Functions.h`
|
||||
- `ATen/core/TensorBody.h`
|
||||
- `c10/core/TensorOptions.h`
|
||||
|
||||
需要注意的一点:compat `at::Tensor` 的底层包装对象是 `paddle::Tensor`。因此上游代码的调用方式通常可以保持不变,真正需要关注的是底层张量与设备语义如何映射到 Paddle。
|
||||
|
||||
迁移时动作要克制:先让现有 C++ 代码用上 compat 头文件,再定位具体缺失的 API,最后只桥接单个缺口。
|
||||
|
||||
### 2. 算子注册兼容层
|
||||
|
||||
这一层负责 schema、namespace、dispatch、runtime lookup,以及 `TORCH_LIBRARY` / `torch.ops` 路径能否继续正常工作。
|
||||
|
||||
- 代码锚点:
|
||||
- `paddle/phi/api/include/compat/torch/library.h`
|
||||
- `paddle/phi/api/include/compat/torch/library.cpp`
|
||||
- `paddle/fluid/pybind/torch_compat.h`
|
||||
|
||||
这也是为什么不少仓库在保留 `TORCH_LIBRARY`、`TORCH_LIBRARY_IMPL` 和 pybind11 入口的情况下,依然可以在 Paddle 下跑通最小路径。
|
||||
|
||||
判断标准很直接:如果 build 和 import 都已经跑通,但 `torch.ops.xxx` 查找失败、schema 对不上、dispatch 落错实现,第一轮检查就应该放在注册层。
|
||||
|
||||
### 3. Python 接口兼容层
|
||||
|
||||
这一层负责 Python wrapper、辅助函数、张量预处理与后处理的行为一致性。
|
||||
|
||||
控制面通常分散在外部库自己的 Python 文件里,尤其是:
|
||||
|
||||
- wrapper 里的参数重排、cast、reshape、split、pack / unpack
|
||||
- device / place / stream helper
|
||||
- `torch._dynamo`、`torch.profiler`、`torch.library` 等私有 glue
|
||||
|
||||
自定义算子的实际调用路径通常会先经过 Python wrapper,再进入 `torch.ops` 或 pybind glue。如果运行时问题在进入 C++ 之前就出现了 `shape`、`dtype`、`place` 偏差,优先检查这一层。
|
||||
|
||||
### 4. Python API 代理层
|
||||
|
||||
这一层负责 `import torch` 与命名空间映射,让外部库在 Paddle 环境下仍能按原始导入路径运行。
|
||||
|
||||
- 对外入口:`python/paddle/__init__.py` 暴露的 `paddle.enable_compat()` / `paddle.disable_compat()`
|
||||
- 具体实现:`python/paddle/compat/proxy.py`
|
||||
|
||||
迁移时通常会在入口脚本、测试脚本或构建脚本中先启用 compat。运行时入口更适合 `scope={...}`;build script 作为短生命周期的入口,可以使用全局 compat 来接住顶层 `torch` import。
|
||||
|
||||
## 四层之外的两个支撑点
|
||||
|
||||
### 构建与扩展工具
|
||||
|
||||
官方四层没有把 build system 单独列成一层,但实际迁移里 build 往往是第一落点。
|
||||
|
||||
- 代码锚点:
|
||||
- `python/paddle/utils/cpp_extension/cpp_extension.py`
|
||||
- `python/paddle/utils/cpp_extension/extension_utils.py`
|
||||
- 主要作用:
|
||||
- 映射或直接替代 `torch.utils.cpp_extension`
|
||||
- 注入 Paddle include / lib 路径
|
||||
- 把 compat 头目录加入 include path
|
||||
|
||||
这也是为什么很多仓库的第一处修改只需要在 build 入口前加一行 `paddle.enable_compat()`。
|
||||
|
||||
### TVM FFI / DLPack 支撑
|
||||
|
||||
对 TVM FFI、TileLang、Triton 一类生态,DLPack、current device、current stream、runtime preload 才是高频控制面。Paddle 已经对 DLPack 提供了较好的支撑,因此这类库的第一轮补丁往往集中在 adapter 和 runtime glue。
|
||||
|
||||
## 用四层判断问题归属
|
||||
|
||||
### 编译期
|
||||
|
||||
- 缺 `at::*` / `torch::*` / `c10::*` → 先查 **C++ API 兼容层**
|
||||
- `TORCH_LIBRARY`、`torch.ops` 路径编译失败 → 先查 **算子注册兼容层**
|
||||
- `setup.py`、安装行为、include / lib 注入异常 → 先查 **构建支撑点**
|
||||
|
||||
### 运行期
|
||||
|
||||
- import 行为、模块作用域、proxy 边界异常 → 先查 **Python API 代理层**
|
||||
- wrapper 把参数或 `place` 改歪了 → 先查 **Python 接口兼容层**
|
||||
- `torch.ops` 找不到算子或 dispatch 错位 → 先查 **算子注册兼容层**
|
||||
- 进入 C++ 后 tensor metadata、dtype、device、layout、pointer 语义不一致 → 先查 **C++ API 兼容层**
|
||||
|
||||
## 一个快速判断例子
|
||||
|
||||
如果一个简单 custom op 仓库已经满足:
|
||||
|
||||
- `pip install . --no-build-isolation` 成功
|
||||
- `import extension` 成功
|
||||
- Python wrapper 调用时报"找不到 `torch.ops.extension_cpp.muladd_cpp`"
|
||||
|
||||
第一落点应放在 **算子注册兼容层**。此时需要核对 namespace、schema、operator name 和 dispatch 路径;然后再回看 Python wrapper 调用名是否与注册层一致。
|
||||
|
||||
## 参考验证点
|
||||
|
||||
- Python 代理测试:`test/compat/test_torch_proxy.py`
|
||||
- `TORCH_LIBRARY` 兼容测试:`test/cpp/compat/torch_library_test.cc`
|
||||
- dispatch 兼容测试:`test/cpp/compat/torch_library_dispatch_test.cc`
|
||||
- cpp_extension 测试:`test/cpp_extension/`
|
||||
|
||||
如果需要继续深入 Paddle 仓库内部文件,转去 [Paddle 内部锚点](paddle-internals.md)。如果运行时已经进入逐段对照阶段,继续看 [运行时调试](runtime-debugging.md)。
|
||||
@@ -0,0 +1,215 @@
|
||||
# 迁移手册
|
||||
|
||||
本手册的目标很直接:在最大限度保留上游代码形状的前提下,把一个原生 PyTorch 自定义算子仓库接到 Paddle 上跑起来。
|
||||
|
||||
## 步骤 0:先确认上游基线
|
||||
|
||||
迁移前先确认三件事:
|
||||
|
||||
- 原仓库在推荐环境下能成功 build / import / run。
|
||||
- 至少有一条最小测试路径可以复现正确行为。
|
||||
- build 入口、调用入口、测试入口已经找全。
|
||||
|
||||
## 步骤 1:先分层,再动代码
|
||||
|
||||
按控制面把仓库分成四层:
|
||||
|
||||
| 层 | 处理原则 |
|
||||
|---|---|
|
||||
| 框架无关的内核 / 算法 | 默认不动 |
|
||||
| 构建与打包 | 往往是第一批要改的地方 |
|
||||
| C++ compat API / 注册 | 先让 compat 层接住 |
|
||||
| Python 包装 / runtime glue / tests | 第二批要改的地方 |
|
||||
|
||||
这一步的输出应该包含两张清单:
|
||||
|
||||
- 当前不需要动的文件
|
||||
- 当前最可能需要先改的文件
|
||||
|
||||
## 步骤 2:先让 build 跑通
|
||||
|
||||
很多仓库的第一处修改只需要落在 build script 顶部,让原始 import 语句继续生效。
|
||||
|
||||
### 典型改法
|
||||
|
||||
```diff
|
||||
+import paddle
|
||||
+paddle.enable_compat()
|
||||
from torch.utils import cpp_extension
|
||||
```
|
||||
|
||||
这样 `from torch.utils import cpp_extension` 会通过 proxy 走到 Paddle 的扩展构建实现,改动面最小,也最利于后续 rebase。
|
||||
|
||||
如果当前仓库的 import 顺序、构建工具或代理边界需要直接入口,再局部切到 Paddle:
|
||||
|
||||
```diff
|
||||
-from torch.utils import cpp_extension
|
||||
+from paddle.utils import cpp_extension
|
||||
```
|
||||
|
||||
直接切到 `paddle.utils.cpp_extension` 不一定就是 compat gap。只有当它是在绕过一个明确的 proxy / compat 缺口时,才需要在代码或结果里记录 TODO、删除条件和 issue MRE;如果它只是当前构建系统下更小的入口选择,把原因写清楚即可。
|
||||
|
||||
### build 层的控制原则
|
||||
|
||||
- 保留 package 名称和目录布局。
|
||||
- 保留 `setup.py` / `pyproject.toml` 主体结构。
|
||||
- 首轮只加 compat 前置准备;编译入口、include / lib 来源、flags 只在实测失败后再调整。
|
||||
- 版本号策略、打包布局、wheel 命名保持与上游一致,除非迁移本身明确要求变更。
|
||||
|
||||
## 步骤 3:让 compat 头先接住 C++ API
|
||||
|
||||
很多库的 C++ 部分可以先按原状编译:
|
||||
|
||||
- `#include <ATen/Functions.h>`
|
||||
- `#include <torch/library.h>`
|
||||
- `TORCH_LIBRARY(...)`
|
||||
- `TORCH_LIBRARY_IMPL(...)`
|
||||
- pybind11 module 定义
|
||||
|
||||
先编译,确认真实缺口落在哪个 API,再做单点桥接。
|
||||
|
||||
### 典型的单点桥接:`torch::empty`
|
||||
|
||||
原始代码:
|
||||
|
||||
```cpp
|
||||
at::Tensor result = torch::empty(a_contig.sizes(), a_contig.options());
|
||||
```
|
||||
|
||||
如果 compat 层当前没有这个入口,可以只桥接这一点:
|
||||
|
||||
```cpp
|
||||
auto paddle_size = a_contig.sizes()._PD_ToPaddleIntArray();
|
||||
auto paddle_dtype = compat::_PD_AtenScalarTypeToPhiDataType(a_contig.dtype());
|
||||
auto paddle_place = a_contig.options()._PD_GetPlace();
|
||||
auto paddle_result = paddle::experimental::empty(
|
||||
paddle_size, paddle_dtype, paddle_place);
|
||||
at::Tensor result(paddle_result);
|
||||
```
|
||||
|
||||
这里需要维持三条边界:
|
||||
|
||||
- 原函数签名保持不变
|
||||
- 调用路径保持不变
|
||||
- surrounding logic 保持不变
|
||||
|
||||
## 步骤 4:保持注册路径稳定
|
||||
|
||||
注册层默认先按上游原样继续工作,例如:
|
||||
|
||||
```cpp
|
||||
TORCH_LIBRARY(extension_cpp, m) {
|
||||
m.def("muladd_cpp(Tensor a, Tensor b, float c) -> Tensor");
|
||||
}
|
||||
|
||||
TORCH_LIBRARY_IMPL(extension_cpp, CPU, m) {
|
||||
m.impl("muladd_cpp", &muladd_cpu);
|
||||
}
|
||||
```
|
||||
|
||||
以及:
|
||||
|
||||
```cpp
|
||||
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
只有在 schema、dispatch、class registration 或 private registry 语义确实落到 compat gap 上时,才需要修改注册代码。
|
||||
|
||||
## 步骤 5:运行时入口优先用 scoped compat
|
||||
|
||||
对实际入口、最小示例、测试脚本,优先使用 scoped compat:
|
||||
|
||||
```python
|
||||
import paddle
|
||||
|
||||
paddle.enable_compat(scope={"extension"})
|
||||
|
||||
import extension
|
||||
```
|
||||
|
||||
build script 适合全局 compat;运行时入口更适合 scoped compat,这样更容易收敛问题边界。
|
||||
|
||||
## 步骤 6:按生态类型选择第一落点
|
||||
|
||||
### A. 普通 Torch extension / custom op 仓库
|
||||
|
||||
优先检查:
|
||||
|
||||
- `setup.py`
|
||||
- `csrc/*.cc` / `*.cu`
|
||||
- `extension/__init__.py`
|
||||
- `test.py` 或最小示例
|
||||
|
||||
首轮改动通常集中在 build 入口、scoped compat,以及少量缺失的 C++ API。
|
||||
|
||||
### B. runtime glue 较重的生态库
|
||||
|
||||
例如 FlashInfer、DeepEP、TorchCodec、SonicMoE。
|
||||
|
||||
优先检查:
|
||||
|
||||
- `torch.ops` / `torch.library` / `torch._dynamo` / `torch.profiler`
|
||||
- distributed group / stream / event / device helpers
|
||||
- 自定义 wrapper、monkey patch、private API 依赖
|
||||
|
||||
这类库的第一落点通常是运行时上下文边界。
|
||||
|
||||
### C. Kernel DSL / compiler 生态
|
||||
|
||||
例如 Triton、TileLang、TVM FFI。
|
||||
|
||||
优先检查:
|
||||
|
||||
- DLPack 转换
|
||||
- current device / current stream 获取
|
||||
- JIT compile cache
|
||||
- profiler / runtime hooks
|
||||
- import 阶段的 CUDA runtime 初始化
|
||||
|
||||
这类库常见的首轮补丁集中在 runtime adapter。
|
||||
|
||||
## 步骤 7:按最小成本验证
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. `pip install . --no-build-isolation` 或等价 build 命令
|
||||
2. 最小 import 测试
|
||||
3. 单个最小功能测试
|
||||
4. 再跑更完整的 test suite
|
||||
|
||||
每一步都要先做最便宜的验证,确认没问题了再扩大范围。
|
||||
|
||||
## 步骤 8:运行时不一致时,沿最小样本逐段对照
|
||||
|
||||
当 build 和 import 都跑通了,但运行结果、`place`、stream、分布式行为或性能路径开始出现偏差,下一步应切换到逐段对照模式。
|
||||
|
||||
推荐做法:
|
||||
|
||||
1. 选一个上游已有的最小测试,或者自己抽一个最小脚本。
|
||||
2. 保证 PyTorch 与 Paddle 输入一致,包括随机种子、dtype、device / place、shape、环境变量。
|
||||
3. 在 Python wrapper、custom op 调用点、关键张量变换点、必要的 C++ 入口处加观测点。
|
||||
4. 记录第一次差异出现在哪一行、哪个调用点、属于哪一层。
|
||||
|
||||
详细做法见 [运行时调试](runtime-debugging.md)。
|
||||
|
||||
## 迁移边界
|
||||
|
||||
迁移过程中始终保持这些边界:
|
||||
|
||||
- `torch` 的写法优先保留,让 compat 层承担映射职责。
|
||||
- import、目录布局、主要 API 形状优先保留。
|
||||
- workaround 需要带 TODO、删除条件;只有确认是 Paddle compat 公共缺口时才准备 issue 信息。
|
||||
- 无关的格式化、风格清理、重命名、顺手重构都不在迁移范围内。
|
||||
|
||||
## 官方最小示例
|
||||
|
||||
官方文档中的示例仓库是 `PFCCLab/cross-ecosystem-custom-op-example`。
|
||||
|
||||
它清楚展示了一个典型顺序:
|
||||
|
||||
- build script 先接入 compat
|
||||
- 测试入口再接入 scoped compat
|
||||
- C++ 侧只桥接少量 compat 尚未覆盖到的 API 点
|
||||
- `TORCH_LIBRARY` 通常可以保持不变
|
||||
@@ -0,0 +1,85 @@
|
||||
# Paddle 内部锚点
|
||||
|
||||
当迁移问题需要深入 Paddle 仓库内部时,先按所属抽象层定位。下面这些锚点对应的是 compat 机制里最稳定的控制面。
|
||||
|
||||
## Python 代理层
|
||||
|
||||
| 路径 | 作用 | 适用场景 |
|
||||
|---|---|---|
|
||||
| `python/paddle/__init__.py` | 对外暴露 `enable_compat` / `disable_compat` | 确认公开 API 入口 |
|
||||
| `python/paddle/compat/proxy.py` | `torch` import 代理、scope、blocked modules、guard 实现 | import 行为异常、scope 不生效、模块代理边界不对 |
|
||||
| `test/compat/test_torch_proxy.py` | Python 代理层测试 | 核对现有代理语义与边界 |
|
||||
|
||||
## build / cpp_extension 层
|
||||
|
||||
| 路径 | 作用 | 适用场景 |
|
||||
|---|---|---|
|
||||
| `python/paddle/utils/cpp_extension/cpp_extension.py` | `setup`、`CppExtension`、`CUDAExtension`、`BuildExtension` 实现 | `setup.py` 迁移、build 安装行为异常、shared library 命名问题 |
|
||||
| `python/paddle/utils/cpp_extension/extension_utils.py` | include/lib 注入、compat include path、生成 Python stub、custom op registration | include path、link flags、custom op Python 包装异常 |
|
||||
| `test/cpp_extension/` | cpp_extension 相关测试 | 核对 build / install / JIT 既有行为 |
|
||||
|
||||
`extension_utils.py` 会把 `paddle/phi/api/include/compat/` 相关目录加入 include path,因此很多 PyTorch 风格头文件会直接被 compat 头接住。
|
||||
|
||||
## C++ compat 头层
|
||||
|
||||
| 路径 | 作用 | 适用场景 |
|
||||
|---|---|---|
|
||||
| `paddle/phi/api/include/compat/ATen/Functions.h` | 常见 `ATen` 函数入口 | 某个 `at::*` 函数找不到 |
|
||||
| `paddle/phi/api/include/compat/ATen/core/TensorBody.h` | `at::Tensor` 的 compat 包装,底层包的是 `paddle::Tensor` | tensor 方法、`data_ptr`、sizes、device、dtype 行为问题 |
|
||||
| `paddle/phi/api/include/compat/c10/core/TensorOptions.h` | compat 版 `TensorOptions` | `options()`、device、dtype、memory_format 问题 |
|
||||
| `paddle/phi/api/include/compat/torch/library.h` | `TORCH_LIBRARY` / `TORCH_LIBRARY_IMPL` 宏与注册接口 | operator 注册、dispatch、schema 问题 |
|
||||
| `paddle/phi/api/include/compat/torch/library.cpp` | compat operator/class registry 实现 | runtime lookup、dispatch、class registration 行为异常 |
|
||||
|
||||
## Python 到 C++ 的调度桥
|
||||
|
||||
| 路径 | 作用 | 适用场景 |
|
||||
|---|---|---|
|
||||
| `paddle/fluid/pybind/torch_compat.h` | 运行时把 Python 参数转成 compat `IValue` / `FunctionArgs`,并通过 registry 调度 | `torch.ops` / `TORCH_LIBRARY` 注册成功但调用异常 |
|
||||
|
||||
## compat 测试锚点
|
||||
|
||||
| 路径 | 作用 |
|
||||
|---|---|
|
||||
| `test/cpp/compat/torch_library_test.cc` | 基本 `TORCH_LIBRARY` / class registration 行为 |
|
||||
| `test/cpp/compat/torch_library_dispatch_test.cc` | dispatch key 选择与 fallback 行为 |
|
||||
| `test/cpp/compat/CMakeLists.txt` | compat 测试入口清单 |
|
||||
|
||||
## 典型路由方式
|
||||
|
||||
### 场景 1:`import torch` 行为异常
|
||||
|
||||
优先查看:
|
||||
|
||||
1. `python/paddle/compat/proxy.py`
|
||||
2. `test/compat/test_torch_proxy.py`
|
||||
|
||||
### 场景 2:`setup.py` / `pip install .` 行为异常
|
||||
|
||||
优先查看:
|
||||
|
||||
1. `cpp_extension.py`
|
||||
2. `extension_utils.py`
|
||||
3. `test/cpp_extension/`
|
||||
|
||||
### 场景 3:C++ 编译时报某个 `at::*` / `c10::*` API 不存在
|
||||
|
||||
优先查看:
|
||||
|
||||
1. `ATen/Functions.h`
|
||||
2. `ATen/core/TensorBody.h`
|
||||
3. `c10/core/TensorOptions.h`
|
||||
|
||||
compat 头当前没有覆盖时,再决定是否加入最小桥接。
|
||||
|
||||
### 场景 4:`TORCH_LIBRARY` 编译通过但运行失败
|
||||
|
||||
优先查看:
|
||||
|
||||
1. `torch/library.h`
|
||||
2. `torch/library.cpp`
|
||||
3. `torch_compat.h`
|
||||
4. `test/cpp/compat/torch_library_test.cc`
|
||||
|
||||
### 场景 5:device / stream / distributed 的私有行为依赖
|
||||
|
||||
先回到外部库自己的 glue layer,看当前 device / current stream、distributed group / communicator、profiler / dynamo / custom op registration 的私有假设如何组织;只有需要确认 compat 机制边界时,再进入 Paddle 内部文件。
|
||||
@@ -0,0 +1,250 @@
|
||||
# 运行时调试
|
||||
|
||||
本章的前提:仓库已经能 build、能 import,但运行时开始出现报错、结果偏差、`device` / `place` / `stream` 语义不一致,或者只在分布式和高性能路径上出问题。
|
||||
|
||||
这里的任务是把控制路径收缩到一个最小样本,找出**第一次语义偏离**发生在哪一层。
|
||||
|
||||
## 调试目标
|
||||
|
||||
一次有效的运行时排查,最后应该回答四个问题:
|
||||
|
||||
1. PyTorch 原始路径的关键状态是在哪一行建立的。
|
||||
2. Paddle 迁移路径第一次偏离是在哪一行出现的。
|
||||
3. 偏离发生时,张量的 `shape`、`dtype`、`place`、layout、stream、group 等关键上下文分别是什么。
|
||||
4. 这个偏离更可能落在 Python 代理层、Python wrapper、注册调度层、C++ compat 层,还是库自身逻辑改动。
|
||||
|
||||
## 调试入口
|
||||
|
||||
### 步骤 1:只保留一个最小样本
|
||||
|
||||
优先顺序保持简单:
|
||||
|
||||
1. 上游已有的最小单测
|
||||
2. 当前 fork 中最稳定的最小单测
|
||||
3. 自己抽出来的最小脚本
|
||||
|
||||
这个样本应满足四个条件:
|
||||
|
||||
- 输入小,便于重复运行
|
||||
- 路径短,调用链清楚
|
||||
- 能固定随机种子
|
||||
- 不依赖太多 benchmark、profiler、训练框架状态
|
||||
|
||||
### 步骤 2:先把两边的输入对齐
|
||||
|
||||
在开始插桩前,先把下面这些量打印出来并固定:
|
||||
|
||||
- 随机种子
|
||||
- 输入 `shape`
|
||||
- 输入 `dtype`
|
||||
- 输入 `device` / `place`
|
||||
- 环境变量
|
||||
- 是否开启额外优化路径
|
||||
|
||||
如果这一步没有对齐,后面的逐行对照就没有结论价值。
|
||||
|
||||
## 阶段 1:先看 `place`
|
||||
|
||||
`place` 是跨生态迁移里最容易被忽略、又最容易把调试结论带偏的一层。很多段错误、非法访问、结果漂移,根因其实是张量根本不在你以为的那块内存上。
|
||||
|
||||
### 先确认三种内存语义
|
||||
|
||||
在 Paddle 路径里,至少要区分下面三类位置:
|
||||
|
||||
| 观测值 | 含义 | 调试时的理解 |
|
||||
|---|---|---|
|
||||
| `Place(cpu)` | 普通 host 内存 | 只能按 CPU 张量处理 |
|
||||
| `Place(gpu_pinned)` | host pinned memory | 仍是 host 内存,只是便于 DMA / 异步拷贝 |
|
||||
| `Place(gpu:x)` | device memory | 才能直接当作 GPU tensor 进入 CUDA 路径 |
|
||||
|
||||
`Place(gpu_pinned)` 和 `Place(gpu:x)` 要严格区分。前者的名字里虽然带 `gpu`,语义仍然是 pinned host memory。
|
||||
|
||||
### 为什么这一步在 Paddle 尤其重要
|
||||
|
||||
Paddle 的 Python 创建 API 在 `device` / `place` 没有显式传入时,会走当前 expected place。也就是说,`paddle.tensor(...)`、`paddle.to_tensor(...)`、某些 helper 内部创建张量时,实际落点可能跟当前 dygraph guard 或全局 expected place 绑定;在 GPU 环境下,这些调用完全可能直接落到 GPU。
|
||||
|
||||
这和很多 PyTorch 生态库的默认假设不同。上游 helper 如果默认"未指定 device 时先创建 CPU tensor",迁到 Paddle 后,完全相同的调用方式也可能因为 expected place 在 GPU 上而直接得到 `Place(gpu:0)`。
|
||||
|
||||
因此,运行时对比里必须记录真实 `place`,不能只看调用代码长得像不像。
|
||||
|
||||
### expected place 的来源
|
||||
|
||||
调试时至少要分清 expected place 的两个来源:
|
||||
|
||||
- 当前 dygraph guard 或显式设备上下文
|
||||
- Paddle 的全局 expected place
|
||||
|
||||
如果当前没有额外 guard,Paddle 会回到全局 expected place。GPU 版本且有可见设备时,这个默认值可以直接是 `CUDAPlace(0)`;设备不可用时才会退回 CPU。
|
||||
|
||||
这也是为什么同一段 helper 代码在 PyTorch 和 Paddle 下可能出现不同落点:
|
||||
|
||||
| 调用方式 | PyTorch 生态库的常见假设 | Paddle 迁移时需要实际确认的 |
|
||||
|---|---|---|
|
||||
| 创建张量时省略 `device` | helper 会先得到 CPU tensor | helper 会落到当前 expected place;GPU 环境下可能直接得到 `Place(gpu:0)` |
|
||||
| 需要 host staging 时开启 pinned memory | helper 仍把它视作 host tensor | 结果可能是 `Place(gpu_pinned)`,后续 copy / stream / `data_ptr` 逻辑都要按 pinned host 处理 |
|
||||
|
||||
因此,建议在 Python wrapper 入口和 custom op 调用前各打一次:
|
||||
|
||||
- `paddle.framework._current_expected_place_()`
|
||||
- 关键输入张量的 `tensor.place`
|
||||
|
||||
这些 underscored API 只适合作为调试观测点,不要把它们沉淀成生态库的长期 runtime workaround。
|
||||
|
||||
### pinned memory 也要单独确认
|
||||
|
||||
Paddle 的创建与拷贝路径显式支持 `gpu_pinned` / `CUDAPinnedPlace`,而且 `pin_memory=True` 会把结果收敛到 pinned memory 路径。数据管线和 reader 代码里也常见 CPU → CUDAPinned → CUDA 的 staging。
|
||||
|
||||
这意味着迁移库里的中间张量可能落在 `Place(gpu_pinned)`。如果上游代码把这类张量当作 device tensor 继续传给 CUDA runtime 或自定义 kernel,就很容易出现段错误、非法地址访问,或者更隐蔽的异步崩溃。
|
||||
|
||||
### Python 侧第一轮日志建议
|
||||
|
||||
第一轮只打最必要的信息:
|
||||
|
||||
```python
|
||||
def dump_tensor(tag, tensor):
|
||||
print(
|
||||
tag,
|
||||
{
|
||||
"shape": list(tensor.shape),
|
||||
"dtype": str(tensor.dtype),
|
||||
"place": str(tensor.place),
|
||||
"stop_gradient": tensor.stop_gradient,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
print("expected_place", paddle.framework._current_expected_place_())
|
||||
dump_tensor("input", x)
|
||||
```
|
||||
|
||||
先在 PyTorch 版和 Paddle 版的同一调用点各打一轮,再决定下一跳去 wrapper、注册层还是 C++ 入口。
|
||||
|
||||
## 阶段 2:沿调用链逐层收缩
|
||||
|
||||
推荐观测点如下:
|
||||
|
||||
| 位置 | 第一轮先看什么 | 更可能对应的层 |
|
||||
|---|---|---|
|
||||
| 测试入口 | seed、shape、dtype、place 是否一致 | 排除环境差异 |
|
||||
| Python wrapper 前后 | 参数是否被改写、重排、cast、split | Python 接口兼容层 |
|
||||
| `torch.ops` / custom op 调用点 | 调用名、namespace、参数顺序是否一致 | 算子注册兼容层 |
|
||||
| C++ 入口 | sizes、dtype、device、layout、pointer 来源 | C++ API 兼容层 |
|
||||
| kernel 前后 | 哪一步开始产生结果偏差 | kernel 或上游输入已错 |
|
||||
| 返回 Python 后 | post-process、pack/unpack、gather、profiler glue | Python 接口兼容层 |
|
||||
|
||||
一次只扩一层。Python wrapper 没对齐前,不要先去 kernel 里铺满日志。
|
||||
|
||||
## 阶段 3:`data_ptr` 只能在确认 `place` 之后看
|
||||
|
||||
### 为什么 `data_ptr` 是高风险点
|
||||
|
||||
Paddle compat 里的 `at::Tensor::data_ptr()` 直接返回底层 `tensor_.data()` 指针。这个指针只表达"当前地址",不表达这块地址对应的是 CPU、pinned host 还是 CUDA device。
|
||||
|
||||
所以只要有下面这类情况,`data_ptr` 就是高风险点:
|
||||
|
||||
- Python wrapper 或 helper 先把张量建在 `Place(cpu)`
|
||||
- 创建路径带了 `pin_memory=True`
|
||||
- 中间 staging 张量落在 `Place(gpu_pinned)`
|
||||
- 上游代码默认"这里已经是 CUDA tensor",直接把 `data_ptr` 交给 CUDA kernel、CUDA runtime、Triton runtime 或自定义 C API
|
||||
|
||||
这类问题的表现常常不会先变成稳定的 Python 异常,常见现象包括:
|
||||
|
||||
- 段错误
|
||||
- `illegal memory access`
|
||||
- 某一行之后才报出的异步 CUDA 错误
|
||||
- 偶发崩溃或结果随机漂移
|
||||
|
||||
### 排查顺序
|
||||
|
||||
1. 先在 Python 侧确认输入张量真实 `place`。
|
||||
2. 进入 C++ 后先记下 `tensor.device()`、`tensor.is_cuda()`、sizes、dtype。
|
||||
3. 确认张量确实在目标设备上之后,再看 `data_ptr()` 和后续 kernel 调用。
|
||||
4. 如果实际是 CPU 或 `gpu_pinned`,先回到 wrapper / 创建路径找谁改变了 `place`。
|
||||
|
||||
### 对 `gpu_pinned` 的额外判断
|
||||
|
||||
如果张量是 `gpu_pinned`,下一步要确认它属于代码设计里的 staging buffer,还是本应继续进入 device memory 的张量却停在了 pinned host 上。
|
||||
|
||||
前者通常需要继续沿 copy / stream / async 边界排查;后者通常说明 wrapper、helper、copy 路径或 TensorOptions 语义已经偏了。
|
||||
|
||||
## 阶段 4:把"第一次偏离"写成对照表
|
||||
|
||||
建议维护一张最小表格,不靠记忆推进:
|
||||
|
||||
| PyTorch 路径 | Paddle 路径 | 观察值 | 结论 |
|
||||
|---|---|---|---|
|
||||
| 测试入口 | 对应测试入口 | 输入一致 | 继续向下 |
|
||||
| wrapper 某一行 | 对应迁移行 | `place` 开始不同 | 回查 Python wrapper / 创建路径 |
|
||||
| `torch.ops` 调用 | 对应迁移行 | operator 名称或 schema 不一致 | 转查注册层 |
|
||||
| C++ 入口 | 对应迁移行 | `device` 一致但 dtype 偏了 | 转查 compat API 或 wrapper |
|
||||
|
||||
这张表的目的很单纯:固定"第一次偏离"发生的位置,避免被最后一处崩溃带偏。
|
||||
|
||||
## 常见问题分型
|
||||
|
||||
### 结果不对,但不崩
|
||||
|
||||
先查:
|
||||
|
||||
- Python wrapper 有没有先改写输入
|
||||
- `dtype` / layout / `place` 有没有中途变化
|
||||
- 返回 Python 后有没有额外 post-process
|
||||
|
||||
### `torch.ops` 找不到算子,或者调错实现
|
||||
|
||||
先查:
|
||||
|
||||
- namespace
|
||||
- schema
|
||||
- 注册顺序
|
||||
- dispatch key
|
||||
|
||||
### 只在 GPU、stream、distributed 路径出问题
|
||||
|
||||
先查:
|
||||
|
||||
- current device / current stream 获取点
|
||||
- event / communicator / group 初始化点
|
||||
- 是否有异步错误被后面一行才观察到
|
||||
- copy 路径里是否经过 CPU 或 `gpu_pinned` staging
|
||||
|
||||
### 只在 benchmark、profiler、compile 路径出问题
|
||||
|
||||
先查:
|
||||
|
||||
- 这些路径是否依赖 PyTorch 私有 API
|
||||
- 主算子路径是否已经正常
|
||||
- 问题是否只存在于外围 harness
|
||||
|
||||
## 如何判断更像哪一层
|
||||
|
||||
### 更像 Python API 代理层
|
||||
|
||||
信号通常是:`import torch` 本身异常、`scope` 表现不稳定、代理模块没有进入目标命名空间。
|
||||
|
||||
### 更像 Python 接口兼容层
|
||||
|
||||
信号通常是:参数在进入 C++ 之前就已经被改写,或者 `shape`、`dtype`、`place` 在 wrapper 中途就偏了。
|
||||
|
||||
### 更像算子注册兼容层
|
||||
|
||||
信号通常是:调用名一致,但 operator 找不到、schema 不匹配,或者 dispatch 落到错误实现。
|
||||
|
||||
### 更像 C++ API 兼容层
|
||||
|
||||
信号通常是:已经进入同一个 C++ 函数,但 sizes、dtype、device、layout、pointer 语义和 PyTorch 不一致。
|
||||
|
||||
## 什么时候该抽成 Paddle issue MRE
|
||||
|
||||
出现下面任一情况,就应该开始整理最小复现:
|
||||
|
||||
- PyTorch 与 Paddle 在同一调用点上行为已经明确分叉
|
||||
- 问题来自 compat 公共行为,不属于当前库自己的特例
|
||||
- workaround 开始在多个文件扩散
|
||||
- 继续推进已经需要依赖 Paddle 内部私有接口
|
||||
|
||||
## 与 `paddle-debug` skill 的关系
|
||||
|
||||
本章只覆盖跨生态迁移场景里的最小样本逐层对照。
|
||||
|
||||
如果问题已经落到 Paddle 核心实现、复杂 CUDA 崩溃、sticky error、分布式 runtime 深层异常等更底层范围,继续交给 `paddle-debug` skill 做专项调试和报告。
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
name: paddle-debug
|
||||
description: 在 Paddle 代码库中定位问题并输出高质量调试报告的专用技能。当遇到以下场景时优先使用:(1) Paddle 框架 bug 调试,(2) 算子实现问题排查,(3) 训练脚本异常诊断,(4) 分布式训练故障定位,(5) CUDA/GPU 相关错误处理,(6) 需要生成结构化调试报告。
|
||||
---
|
||||
|
||||
# Paddle 仓库调试
|
||||
|
||||
## 调试流程概览
|
||||
|
||||
|
||||
调试遵循以下步骤:
|
||||
|
||||
1. 描述问题并构造最小复现
|
||||
2. 代码定位与多假设验证
|
||||
3. 先写问题分析报告,再做最小修复
|
||||
4. 利用 Git / CI 收束和巩固结论
|
||||
|
||||
## 步骤 1:描述问题并构造最小复现
|
||||
|
||||
用简洁的自然语言说明:
|
||||
- 触发步骤(命令、脚本、关键配置)
|
||||
- 期望行为 vs 实际行为
|
||||
- 是否只在特定环境 / 机器 / 设备 / 数据子集上出现
|
||||
|
||||
**先确认 bug 能被稳定复现**。若无法复现:
|
||||
- 检查命令是否抄错、参数是否缺失
|
||||
- 比对并对齐环境(Paddle / Python / CUDA / CUDNN / 驱动 / 显卡型号等)
|
||||
- 确认与最初出问题的环境一致后再继续
|
||||
|
||||
抽取独立的 Python 脚本承载问题:
|
||||
- 固定随机种子(`numpy` / `random` / `paddle.seed` 等)
|
||||
- 使用固定、可序列化的小数据
|
||||
- 去掉与问题无关的逻辑
|
||||
|
||||
目标:一条命令即可复现 `python reproduce_xxx.py`。
|
||||
|
||||
## 步骤 2:代码定位与多假设验证
|
||||
|
||||
### 使用工具定位代码
|
||||
|
||||
- **ast-grep**:用于结构化代码搜索,快速定位特定代码模式
|
||||
|
||||
### 带观测点的复现
|
||||
|
||||
阅读报错栈和相关代码时,先列出**多个可能原因假设**(数据异常、shape 错误、数值不稳定、环境不一致、算子实现问题等),不要立刻改代码。
|
||||
|
||||
围绕假设在关键路径上加入**观测点**:
|
||||
|
||||
| 观测方式 | 用途 |
|
||||
|---------|------|
|
||||
| 打印与断言 | 在关键算子调用前后,打印 Tensor 的 shape、dtype、device、数值范围(min/max/mean) |
|
||||
| 对比法 | 对同一逻辑分别在 CPU / GPU 上运行,比较中间结果差异 |
|
||||
| 版本与环境信息 | 记录 `paddle.__version__`、CUDA/CUDNN 版本、驱动信息等 |
|
||||
|
||||
每完成一次带观测点的复现:
|
||||
- 基于运行时数据**排除不成立的假设**
|
||||
- 在更窄的范围内继续加观测点,逐步缩小问题所在的模块 / 算子 / 配置
|
||||
|
||||
将调试日志保存到 `.paddle-agent/debug-logs/` 目录。
|
||||
|
||||
## 步骤 3:先写问题分析报告,再做最小修复
|
||||
|
||||
基于已有观测和对比结果,先完成**问题分析报告**:
|
||||
|
||||
```markdown
|
||||
# [问题标题]
|
||||
|
||||
## 复现方式
|
||||
- 命令:
|
||||
- 环境:
|
||||
- 最小脚本路径:
|
||||
|
||||
## 现象描述
|
||||
[错误信息或异常行为]
|
||||
|
||||
## 根因分析
|
||||
[配置 / 数据 / 框架 / 算子 / 环境中的哪一处有问题]
|
||||
|
||||
## 关键证据
|
||||
[日志片段、对比结果、重要观测点输出]
|
||||
```
|
||||
|
||||
报告存放在 `.paddle-agent/debug-analysis/` 目录,没有该目录请创建。
|
||||
|
||||
归因时考虑以下维度:
|
||||
- **接口 / 形状 / dtype**:哪个 Tensor 的 shape / dtype 与预期不符
|
||||
- **NaN / Inf / 数值发散**:哪一层首次出现异常数值
|
||||
- **性能与显存**:瓶颈在 CPU、IO 还是 GPU kernel
|
||||
|
||||
**只有在分析结论较为充分时**,才进入最小修复阶段:
|
||||
- 设计改动面尽量小的修改来验证根因
|
||||
- 先用最小复现脚本验证修复
|
||||
- 再用完整训练 / 推理脚本验证关键业务路径
|
||||
|
||||
## 步骤 4:利用 Git / CI 收束和巩固结论,最后总结保存为文件
|
||||
|
||||
当判断问题可能由近期提交引入时:
|
||||
- 使用 `git bisect` 对可疑提交范围做二分定位
|
||||
|
||||
对已定位的问题:
|
||||
- 补充覆盖最小复现脚本逻辑的单测
|
||||
- 留意 CI 中相关用例是否出现新增失败
|
||||
- 将最终结论沉淀到 `.paddle-agent/debug-analysis/`
|
||||
|
||||
## CUDA / GPU 调试
|
||||
|
||||
**详细的 CUDA 调试技巧**:见 [references/cuda-debug.md](references/cuda-debug.md)
|
||||
|
||||
快速参考:
|
||||
```bash
|
||||
# 启用错误检查环境变量复现问题
|
||||
export PYTHONPATH=$(pwd)/Paddle/build/python
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python reproduce.py
|
||||
```
|
||||
|
||||
关键点:
|
||||
- CUDA 错误通常是异步的,使用 `FLAGS_check_cuda_error=1` 让错误立即暴露
|
||||
- GPU kernel 调用前必须检查 numel/shape 是否为空
|
||||
- 空 Tensor(numel=0)会导致 grid size=0,触发 CUDA error(9)
|
||||
- CUDA API 返回值必须全部检查,忽略返回值会导致 sticky error 残留
|
||||
- `PADDLE_ENFORCE_GPU_SUCCESS` 不会调用 `cudaGetLastError()`,在错误路径上需手动清除
|
||||
- **CUDA context 在 fork 后不可用**:父进程初始化了 CUDA 后 fork 子进程(如 DataLoader worker),子进程中所有 CUDA API 调用都会返回 `cudaErrorInitializationError`(3)——详见 [references/cuda-debug.md](references/cuda-debug.md) 中的 **CUDA Fork Safety** 章节
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 调试的第一目标是**稳定复现并缩小范围**,不要一开始就尝试大规模重构
|
||||
- 任何「只在某些机器上出现」的问题,优先从环境差异入手
|
||||
- 在 Paddle 仓库遇到 bug 时,优先按本 skill 流程执行,再考虑具体修复实现
|
||||
|
||||
### 算子修复注意事项
|
||||
|
||||
- **前向和反向 kernel 要一并检查**:反向 kernel 往往复用相同的计算逻辑,同样存在边界问题
|
||||
- **检查所有入口函数**:底层公共函数可能被多个入口调用,确保边界检查在正确的层级
|
||||
- **头文件修改需完整重编**:修改 `.h` 后需重新编译所有引用它的 `.cu`,并重新链接 `.so`
|
||||
|
||||
### CUDA API 与 Sticky Error 注意事项
|
||||
|
||||
- **所有 CUDA API 返回值必须检查**:包括 `cudaEventSynchronize`、`cudaStreamSynchronize` 等,忽略返回值不仅丢失错误信息,还会导致 CUDA runtime 中残留 sticky error
|
||||
- **错误路径必须清除 last error**:在 `PADDLE_ENFORCE_GPU_SUCCESS` 抛出异常之前,手动调用 `cudaGetLastError()` 清除残留错误,否则 Python `try/except` 捕获异常后 CUDA 状态仍被污染
|
||||
- **跨测试状态污染**:unittest 中一个测试的 CUDA sticky error 会影响后续所有测试,排查时需关注测试执行顺序
|
||||
- **定位 sticky error 污染源**:通过逐步删减测试来二分定位产生残留错误的源头测试
|
||||
|
||||
### CUDA Fork Safety 注意事项
|
||||
|
||||
- **CUDA context 在 fork 后不可用**:如果父进程已初始化 CUDA(创建了 GPU tensor、调用过 CUDA API),fork 出的子进程中所有 CUDA 调用都会返回 `cudaErrorInitializationError`(3)
|
||||
- **典型触发场景**:主进程中运行了 GPU 测试/训练后,DataLoader 使用 `num_workers > 0` fork 子进程;子进程继承了父进程中 GPU tensor 的引用,GC 回收时触发 `cudaFree`
|
||||
- **修复模式**:在 CUDA API 调用前检测 context 是否可用,对 fork 后不可用的场景做 graceful skip
|
||||
- **判断依据**:`cudaGetDevice()` 返回 `cudaErrorInitializationError`(3)、`cudaErrorNoDevice`(100)、`cudaErrorInsufficientDriver`(35) 均表示 CUDA 不可用
|
||||
- **安全性**:跳过 `cudaFree` 是安全的,因为 fork 后子进程中的 GPU 内存不属于该进程,进程退出时由 OS/driver 回收
|
||||
|
||||
### Paddle 编译验证流程
|
||||
|
||||
修改 kernel 头文件后的增量编译:
|
||||
```bash
|
||||
cd build
|
||||
# 编译修改的 kernel
|
||||
ninja paddle/phi/CMakeFiles/phi_gpu.dir/kernels/gpu/<kernel_name>.cu.o -j512
|
||||
# 重新链接 phi_gpu
|
||||
ninja phi_gpu -j512
|
||||
# 重新链接 libpaddle.so
|
||||
ninja paddle/fluid/pybind/libpaddle.so -j512
|
||||
# 如果 Python 库未自动更新,手动复制
|
||||
cp paddle/fluid/pybind/libpaddle.so python/paddle/base/libpaddle.so
|
||||
```
|
||||
|
||||
### .so 部署验证(关键踩坑点)
|
||||
|
||||
Paddle 构建产物存在两套路径,增量编译后 Python 加载的可能仍是旧版本:
|
||||
|
||||
| 构建产物路径 | Python 加载路径 | 说明 |
|
||||
|---|---|---|
|
||||
| `build/paddle/phi/libphi_core.so` | `build/python/paddle/libs/libphi_core.so` | phi core 库 |
|
||||
| `build/paddle/phi/libphi_gpu.so` | `build/python/paddle/libs/libphi_gpu.so` | phi GPU 库 |
|
||||
| `build/paddle/fluid/pybind/libpaddle.so` | `build/python/paddle/base/libpaddle.so` | 主绑定库 |
|
||||
|
||||
**增量编译后务必检查**:
|
||||
```bash
|
||||
# 确认 Python 实际加载了哪个 .so
|
||||
python -c "import paddle; import os; print(os.path.realpath(paddle.__file__))"
|
||||
|
||||
# 比较构建时间戳
|
||||
stat build/paddle/phi/libphi_core.so
|
||||
stat build/python/paddle/libs/libphi_core.so
|
||||
|
||||
# 如果时间戳不一致,手动同步
|
||||
cp build/paddle/phi/libphi_core.so build/python/paddle/libs/libphi_core.so
|
||||
cp build/paddle/phi/libphi_gpu.so build/python/paddle/libs/libphi_gpu.so
|
||||
```
|
||||
|
||||
**典型症状**:修改了源码并重新编译,但运行时错误信息中的**行号不变**——这说明 Python 加载的仍是旧 `.so`。
|
||||
|
||||
### 多路径调用链分析方法
|
||||
|
||||
当崩溃发生在公共底层函数(如 `GetCurrentDeviceId`、`cudaFree`)时,需穷举所有调用路径来定位真正的入口:
|
||||
|
||||
1. **从崩溃点出发,向上追溯**:用 Grep 搜索崩溃函数的所有调用者,逐层向上展开
|
||||
2. **结合分配器类型缩小范围**:根据 FLAGS(如 `FLAGS_use_system_allocator`)确定实际使用的分配器链路
|
||||
3. **Tensor 生命周期追踪**:`DenseTensor::~DenseTensor` -> `shared_ptr<Allocation>` -> `AllocationDeleter` -> 具体分配器的 `FreeImpl`
|
||||
4. **在崩溃点添加 backtrace 日志**:临时加入 `backtrace_symbols_fd` 打印调用栈,确认实际触发路径
|
||||
5. **注意虚函数/宏展开**:`PADDLE_ENFORCE_GPU_SUCCESS` 是宏,行号由 `__LINE__` 决定;`FreeImpl` 是虚函数,实际调用取决于运行时类型
|
||||
|
||||
## 调试案例
|
||||
|
||||
见 [references/case-studies.md](references/case-studies.md) 了解实际调试案例。
|
||||
@@ -0,0 +1,414 @@
|
||||
# 调试案例
|
||||
|
||||
## 案例:one_hot kernel CUDA error(9) 修复
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python test_one_hot_v2_op.py
|
||||
```
|
||||
报错:`CUDA error(9), invalid configuration argument`
|
||||
|
||||
### 根因分析
|
||||
1. 测试用例 `TestOneHotOp_ZeroSize` 使用 `x_shape=[0, 10, 7, 3]`,即 `numel=0`
|
||||
2. `one_hot_kernel.cu` 中代码顺序:
|
||||
```cpp
|
||||
funcs::set_constant(dev_ctx, out, 0.0); // 先调用 kernel
|
||||
if (numel == 0) return; // 后检查边界
|
||||
```
|
||||
3. `set_constant` 内部启动 CUDA kernel,numel=0 导致 grid size=0,触发 CUDA error(9)
|
||||
|
||||
### 修复方案
|
||||
将边界检查移到 kernel 调用之前:
|
||||
```cpp
|
||||
if (numel == 0) return; // 先检查边界
|
||||
funcs::set_constant(dev_ctx, out, 0.0); // 后调用 kernel
|
||||
```
|
||||
|
||||
### 修复文件
|
||||
- `paddle/phi/kernels/gpu/one_hot_kernel.cu`
|
||||
- `paddle/phi/kernels/legacy/gpu/one_hot_kernel.cu`
|
||||
|
||||
### 经验总结
|
||||
- GPU kernel 调用前必须检查 numel/shape 是否为空
|
||||
- 同一算子可能有多个实现(主版本和 legacy),需同步修复
|
||||
- 使用 `FLAGS_check_cuda_error=1` 可以将异步 CUDA 错误立即暴露
|
||||
|
||||
---
|
||||
|
||||
## 案例:tril_triu kernel CUDA error(9) 修复
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python test_tril_triu_op.py
|
||||
```
|
||||
6 个与 `ZeroSize` / `ZeroDim` 相关的测试用例失败,报错:`CUDA error(9), invalid configuration argument`
|
||||
|
||||
### 根因分析
|
||||
1. 测试用例使用 `X.shape = [0, 3, 9, 4]`(numel=0)
|
||||
2. `TrilTriuKernel` 和 `TrilTriuGradKernel` 使用 `ForRange` 调度 kernel
|
||||
3. 当 `numel=0` 时,`ForRange` 以 `limit=0` 被调用,导致 `grid_size=0, block_size=0`
|
||||
4. 虽然 `TrilKernel`/`TriuKernel` 有 `numel==0` 检查,但底层的 `TrilTriuKernel` 没有
|
||||
|
||||
### 修复方案
|
||||
在 `TrilTriuKernel` 和 `TrilTriuGradKernel` 中添加提前返回:
|
||||
```cpp
|
||||
// 在 kernel 调用前添加
|
||||
if (x.numel() == 0) {
|
||||
return; // 提前返回,避免无效的 CUDA kernel 启动
|
||||
}
|
||||
```
|
||||
|
||||
### 修复文件
|
||||
- `paddle/phi/kernels/impl/tril_triu_kernel_impl.h`(前向 kernel)
|
||||
- `paddle/phi/kernels/impl/tril_triu_grad_kernel_impl.h`(反向 kernel)
|
||||
|
||||
### 与 one_hot 案例的关键差异
|
||||
|
||||
| 维度 | one_hot 案例 | tril_triu 案例 |
|
||||
|------|-------------|---------------|
|
||||
| 修复位置 | `.cu` 文件 | `.h` 头文件模板 |
|
||||
| 修复范围 | 前向 kernel | 前向 + 反向 kernel |
|
||||
| 入口函数 | 单一入口 | 多入口(tril/triu/tril_triu) |
|
||||
| 编译验证 | 编译 .cu 即可 | 需重新编译所有引用该头文件的 .cu |
|
||||
|
||||
### 经验总结
|
||||
- **前向和反向 kernel 要一并检查**:反向 kernel 往往复用相同的计算逻辑,同样存在边界问题
|
||||
- **检查所有入口函数**:`TrilKernel`/`TriuKernel` 虽有检查,但它们调用的 `TrilTriuKernel` 没有
|
||||
- **头文件修改需完整重编**:修改 `.h` 后需重新编译所有引用它的 `.cu`,并确保 Python 加载的 `.so` 是最新的
|
||||
- **验证 Python 库路径**:`build/python/paddle/base/libpaddle.so` 可能与 `build/paddle/fluid/pybind/libpaddle.so` 不同步,需手动复制或重新链接
|
||||
|
||||
---
|
||||
|
||||
## 案例:CudaEvent::ElapsedTime CUDA error(400) sticky error 修复
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python test/compat/test_event_stream_apis.py
|
||||
```
|
||||
`test_event_stream_timing_functionality` 在 `paddle.randn()` 时报错:`CUDA error(400), invalid resource handle`。
|
||||
|
||||
### 根因分析
|
||||
|
||||
**直接原因**:`paddle/phi/api/profiler/event.cc` 的 `CudaEvent::ElapsedTime()` 存在两个缺陷:
|
||||
1. `cudaEventSynchronize()` 的返回值**未被检查**(直接丢弃)
|
||||
2. 错误路径上**未调用 `cudaGetLastError()` 清除 CUDA last error**
|
||||
|
||||
**触发序列**:
|
||||
1. `test_event_stream_error_handling` 对**未 record 的** Event 调用 `elapsed_time()`
|
||||
2. `cudaEventSynchronize(unrecorded_event)` 返回 `cudaErrorInvalidResourceHandle`(400),但返回值被忽略
|
||||
3. CUDA runtime 的 last error 被设置为 400
|
||||
4. `cudaEventElapsedTime` 也失败,`PADDLE_ENFORCE_GPU_SUCCESS` 抛出 C++ 异常
|
||||
5. Python `try/except` 捕获异常,但 **CUDA last error 未被清除**(sticky error 残留)
|
||||
6. 后续 `FLAGS_check_cuda_error=1` 的 `CUDAErrorCheck` 调用 `cudaGetLastError()` 检测到残留错误 400
|
||||
7. 此后所有 CUDA 操作报错
|
||||
|
||||
**问题代码**:
|
||||
```cpp
|
||||
// paddle/phi/api/profiler/event.cc (修复前)
|
||||
float CudaEvent::ElapsedTime(CudaEvent *end_event) {
|
||||
float milliseconds = 0;
|
||||
cudaEventSynchronize(end_event->GetRawCudaEvent()); // ← 返回值未检查!
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaEventElapsedTime( // ← 异常路径未清除 last error
|
||||
&milliseconds, event_, end_event->GetRawCudaEvent()));
|
||||
return milliseconds;
|
||||
}
|
||||
```
|
||||
|
||||
### 最小复现(不依赖 unittest)
|
||||
```python
|
||||
import paddle
|
||||
paddle.device.set_device('gpu:0')
|
||||
event1 = paddle.device.Event()
|
||||
event2 = paddle.device.Event()
|
||||
try:
|
||||
event1.elapsed_time(event2) # 未 record 的 event → CUDA error(400)
|
||||
except Exception:
|
||||
pass # Python 捕获了异常,但 CUDA last error 仍残留
|
||||
|
||||
# 后续任何 CUDA 操作都会失败(在 FLAGS_check_cuda_error=1 下)
|
||||
stream = paddle.device.Stream(device='gpu:0')
|
||||
with paddle.device.stream_guard(stream):
|
||||
x = paddle.randn([100, 100]) # ← CUDA error(400)!
|
||||
```
|
||||
|
||||
### 修复方案
|
||||
|
||||
**C++ 修复**(`paddle/phi/api/profiler/event.cc`):
|
||||
- 检查 `cudaEventSynchronize` 返回值
|
||||
- 错误路径调用 `cudaGetLastError()` 清除 CUDA last error
|
||||
|
||||
```cpp
|
||||
float CudaEvent::ElapsedTime(CudaEvent *end_event) {
|
||||
float milliseconds = 0;
|
||||
gpuError_t sync_err = cudaEventSynchronize(end_event->GetRawCudaEvent());
|
||||
if (sync_err != cudaSuccess) {
|
||||
cudaGetLastError(); // 清除 CUDA last error
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(sync_err);
|
||||
}
|
||||
gpuError_t elapsed_err = cudaEventElapsedTime(
|
||||
&milliseconds, event_, end_event->GetRawCudaEvent());
|
||||
if (elapsed_err != cudaSuccess) {
|
||||
cudaGetLastError(); // 清除 CUDA last error
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(elapsed_err);
|
||||
}
|
||||
return milliseconds;
|
||||
}
|
||||
```
|
||||
|
||||
**测试修复**(`test/compat/test_event_stream_apis.py`):
|
||||
- 不再对未 record 的 events 调用 `elapsed_time`(这是 CUDA 层的未定义行为)
|
||||
- 改为先 record events 后再调用 `elapsed_time`
|
||||
|
||||
### 修复文件
|
||||
- `paddle/phi/api/profiler/event.cc`(C++ 核心修复)
|
||||
- `test/compat/test_event_stream_apis.py`(测试修复)
|
||||
|
||||
### 调试过程中的关键手段
|
||||
|
||||
| 手段 | 具体操作 | 效果 |
|
||||
|------|---------|------|
|
||||
| 二分测试 | 通过逐步去掉/保留 unittest 中各测试,定位到 `test_event_stream_error_handling` | 从 7 个测试缩小到 1 个关键测试 |
|
||||
| 最小化复现 | 将 unittest 三类交互抽象为 10 行脚本 | 确认了根因链条 |
|
||||
| 手动清除 CUDA error | 在 Python 中用 ctypes 调 `cudaGetLastError()` | 验证了 sticky error 假设 |
|
||||
| 测试执行顺序分析 | 用 `unittest.TestLoader` 打印测试顺序 | 发现错误只在特定测试序列下出现 |
|
||||
|
||||
### 经验总结
|
||||
|
||||
1. **CUDA API 返回值必须全部检查**:即使是 `cudaEventSynchronize` 这类"辅助"调用,忽略返回值也会在 CUDA runtime 中留下残留错误
|
||||
2. **CUDA error 清除机制**:
|
||||
- CUDA runtime 的 last error 需通过 `cudaGetLastError()` 显式清除
|
||||
- `PADDLE_ENFORCE_GPU_SUCCESS` 只检查传入的错误码,**不会**调用 `cudaGetLastError()` 来清除 runtime 残留
|
||||
- Python `try/except` 捕获 C++ 异常后,CUDA last error 仍残留
|
||||
3. **`FLAGS_check_cuda_error=1` 的放大效应**:该 flag 使每个算子前后都调用 `cudaDeviceSynchronize()` + `cudaGetLastError()`,能检测到之前任何残留的错误——即使错误发生在完全不相关的代码路径上
|
||||
4. **跨测试状态污染**:unittest 中一个测试产生的 CUDA sticky error 可以影响后续所有测试,问题表现为"看似无关的测试随机失败"
|
||||
5. **最小复现的缩减策略**:对于仅在特定测试序列下出现的 bug,应关注测试执行顺序、逐个删除测试来二分定位"污染源"测试
|
||||
|
||||
---
|
||||
|
||||
## 案例:RecordedGpuMallocHelper::Free CUDA error(3) fork safety 修复
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python test/legacy_test/test_newprofiler.py
|
||||
```
|
||||
`TestTimerOnly::test_with_dataloader` 失败,DataLoader worker 子进程报错:`CUDA error(3), initialization error`,随后 abort。
|
||||
|
||||
### 关键现象
|
||||
|
||||
- **全部测试一起跑才出现**:单独运行 `test_with_dataloader` 通过
|
||||
- **需要 `FLAGS_use_system_allocator=1`**:默认分配器下不触发(因为有缓存池,不会立即 `cudaFree`)
|
||||
- **错误发生在 DataLoader worker 子进程中**(fork 出来的进程)
|
||||
|
||||
### 根因分析
|
||||
|
||||
**触发链**:
|
||||
1. `TestProfiler::test_profiler` 在主进程中初始化了 CUDA(创建了 GPU tensor)
|
||||
2. `TestTimerOnly::test_with_dataloader` 使用 `DataLoader(num_workers=2)` fork 子进程
|
||||
3. 子进程继承了父进程中 GPU tensor 的 `shared_ptr<Allocation>` 引用
|
||||
4. 子进程中 GC 回收 tensor 时,触发 `DenseTensor::~DenseTensor()`
|
||||
5. 析构链:`CUDAAllocator::FreeImpl` -> `RecordedGpuFree` -> `RecordedGpuMallocHelper::Free`
|
||||
6. `Free` 方法构造 `CUDADeviceGuard(dev_id_)` -> `GetCurrentDeviceId()` -> `cudaGetDevice()`
|
||||
7. fork 后子进程中 CUDA context 不可用,`cudaGetDevice()` 返回 error 3
|
||||
8. `PADDLE_ENFORCE_GPU_SUCCESS` 将此视为致命错误并 abort
|
||||
|
||||
**代码位置**:
|
||||
- 崩溃点:`paddle/phi/backends/gpu/cuda/cuda_info.cc:179` — `GetCurrentDeviceId()` 中的 `PADDLE_ENFORCE_GPU_SUCCESS(cudaGetDevice(&device_id))`
|
||||
- 问题入口:`paddle/phi/core/platform/device/gpu/gpu_info.cc:338` — `RecordedGpuMallocHelper::Free()` 中的 `CUDADeviceGuard guard(dev_id_)`
|
||||
|
||||
### 修复方案
|
||||
|
||||
在 `RecordedGpuMallocHelper::Free()` 和 `FreeAsync()` 中,在 `CUDADeviceGuard` 之前添加 CUDA context 可用性检查:
|
||||
|
||||
```cpp
|
||||
{
|
||||
int device_id;
|
||||
auto device_err = cudaGetDevice(&device_id);
|
||||
if (device_err == cudaErrorInitializationError ||
|
||||
device_err == cudaErrorNoDevice ||
|
||||
device_err == cudaErrorInsufficientDriver) {
|
||||
cudaGetLastError(); // 清除 sticky error
|
||||
return; // 跳过释放,由 OS/driver 回收
|
||||
}
|
||||
}
|
||||
CUDADeviceGuard guard(dev_id_); // 现在安全了
|
||||
```
|
||||
|
||||
### 修复文件
|
||||
|
||||
- `paddle/phi/core/platform/device/gpu/gpu_info.cc`(`RecordedGpuMallocHelper::Free` 和 `FreeAsync`)
|
||||
|
||||
### 调试过程中的关键踩坑点
|
||||
|
||||
| 踩坑点 | 说明 | 解决方法 |
|
||||
|--------|------|---------|
|
||||
| .so 未同步 | `ninja phi_gpu` 编译了新 `.so`,但 Python 加载的 `build/python/paddle/libs/libphi_core.so` 是旧版本 | 手动 `cp build/paddle/phi/libphi_core.so build/python/paddle/libs/` |
|
||||
| 行号不变判断法 | 修改代码后错误消息中行号没变(仍显示 :179),暴露了旧 `.so` 问题 | 利用行号作为判断 .so 是否更新的 indicator |
|
||||
| 调用链穷举 | `GetCurrentDeviceId` 被多处调用,需要确认实际触发路径 | 在崩溃函数中加 `backtrace_symbols_fd` 临时日志 |
|
||||
|
||||
### 经验总结
|
||||
|
||||
1. **"单独通过,一起失败"的 bug 优先检查跨测试副作用**:前一个测试初始化了 CUDA context,后一个测试 fork 了子进程,两者组合导致问题
|
||||
2. **CUDA fork safety 是底层框架必须处理的边界条件**:任何可能在 fork 后子进程中调用的 CUDA API,都需要做 context 可用性检查
|
||||
3. **`FLAGS_use_system_allocator=1` 绕过了缓存池**:使问题在正常路径下隐藏的 bug 暴露出来(默认分配器有缓存,不会每次都 `cudaFree`)
|
||||
4. **增量编译后必须验证 .so 部署**:Paddle 的构建产物和 Python 加载路径不同,`ninja` 只更新了前者,需要手动同步后者
|
||||
5. **修复必须覆盖所有并行路径**:`Free` 和 `FreeAsync` 都需要添加保护,不能只修一处
|
||||
|
||||
---
|
||||
|
||||
## 案例:put_along_axis (scatter) CUDA Graph 模式下内存越界修复
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
compute-sanitizer --tool memcheck --target-processes all python test_put_along_axis.py >run.log 2>&1
|
||||
```
|
||||
`compute-sanitizer` 报告大量 `Invalid __global__ atomic of size 4 bytes` 错误,出错 kernel 为 `phi::funcs::PickWinnersScatterKernel<long>`,访问地址远超分配大小(偏移数十亿字节)。**不使用 CUDA Graph 时完全正常**。
|
||||
|
||||
### 关键现象
|
||||
|
||||
- 仅在 CUDA Graph `graph.replay()` 阶段触发,capture 阶段无报错
|
||||
- 越界访问发生在 `atomicMax(&winners[replace_index_self], ...)` 处
|
||||
- `replace_index_self` 的值异常巨大,说明上游 `ComputeOffset` 的输入数据(`shape_strides`)是垃圾值
|
||||
- Host backtrace 中出现 `cudaGraphLaunch` → `CUDAGraph::Replay()`,确认是 graph replay 触发
|
||||
|
||||
### 根因分析
|
||||
|
||||
**问题代码**(`paddle/phi/kernels/funcs/gather_scatter_functor.cu`,`gpu_gather_scatter_functor::operator()` 中):
|
||||
```cpp
|
||||
DenseTensor shape_stride_dev;
|
||||
shape_stride_dev.Resize({3 * ndim});
|
||||
dev_ctx.Alloc<int64_t>(&shape_stride_dev);
|
||||
{ // deallocate host once the copy is done
|
||||
DenseTensor shape_stride_host;
|
||||
shape_stride_host.Resize({3 * ndim});
|
||||
dev_ctx.template HostAlloc<int64_t>(&shape_stride_host);
|
||||
int64_t* host_data = shape_stride_host.data<int64_t>();
|
||||
// ... 填充 host_data ...
|
||||
phi::Copy(dev_ctx, shape_stride_host, dev_ctx.GetPlace(), false, &shape_stride_dev);
|
||||
} // ← shape_stride_host 在此处析构,pinned memory 被释放
|
||||
```
|
||||
|
||||
**触发链**:
|
||||
1. `phi::Copy` 在 CUDA Graph capture 期间被录制为 `cudaMemcpyAsync(H2D)` 节点
|
||||
2. CUDA Graph 录制的是 H2D memcpy 的**源地址指针**(host pinned memory 地址),而非数据内容
|
||||
3. `shape_stride_host` 是局部变量,在 `{}` 作用域结束后析构,pinned memory 被释放
|
||||
4. `graph.replay()` 时,CUDA runtime 从**已释放的 host 地址**读取垃圾数据到 device
|
||||
5. 垃圾 `shape_strides` → `ComputeOffset` 计算出错误的偏移 → `atomicMax` 严重越界 → CUDA error 719
|
||||
|
||||
**影响范围**:文件中共有 **7 处**完全相同模式的 H2D 拷贝(前向 1 处 + 反向 6 处),均存在 CUDA Graph 不兼容问题。
|
||||
|
||||
### 修复方案
|
||||
|
||||
参照 Paddle 已有的 `concat_and_split_functor.cu` 中的做法,使用 `RestoreHostMemIfCapturingCUDAGraph` 在 CUDA Graph 捕获期间对 host 数据做快照,确保 graph replay 时 H2D memcpy 的源地址仍然有效。
|
||||
|
||||
```cpp
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
|
||||
// 修复后:
|
||||
{
|
||||
DenseTensor shape_stride_host;
|
||||
shape_stride_host.Resize({3 * ndim});
|
||||
dev_ctx.template HostAlloc<int64_t>(&shape_stride_host);
|
||||
int64_t* host_data = shape_stride_host.data<int64_t>();
|
||||
// ... 填充 host_data ...
|
||||
auto* restored =
|
||||
phi::backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
host_data, 3 * ndim);
|
||||
phi::backends::gpu::GpuMemcpyAsync(
|
||||
shape_stride_dev.data<int64_t>(),
|
||||
restored,
|
||||
3 * ndim * sizeof(int64_t),
|
||||
phi::gpuMemcpyHostToDevice,
|
||||
stream);
|
||||
}
|
||||
```
|
||||
|
||||
`RestoreHostMemIfCapturingCUDAGraph` 的原理:
|
||||
- 非 CUDA Graph 模式:直接返回原指针,零开销
|
||||
- CUDA Graph capture 模式:在堆上分配一份 host 数据快照(`new uint8_t[nbytes]` + `memcpy`),通过 `AddPostResetCallbackIfCapturingCUDAGraph` 注册回调在 graph 重置时释放,确保 graph 整个生命周期内源地址有效
|
||||
|
||||
### 修复文件
|
||||
- `paddle/phi/kernels/funcs/gather_scatter_functor.cu`(7 处 H2D 拷贝全部修复)
|
||||
|
||||
### 验证结果
|
||||
|
||||
| 指标 | 修复前 | 修复后 |
|
||||
|------|--------|--------|
|
||||
| compute-sanitizer 错误数 | 大量 `Invalid __global__ atomic` | **0 errors** |
|
||||
| CUDA Graph replay | CUDA error 719 (launch failure) | **PASS** |
|
||||
|
||||
### 经验总结
|
||||
|
||||
1. **CUDA Graph 不兼容 H2D memcpy 中使用临时 host 内存**:CUDA Graph 录制的是地址而非数据,如果 host 源地址在 replay 时已失效,GPU 会读取垃圾数据。这不会在 capture 阶段报错,只会在 replay 时产生难以预料的内存越界
|
||||
2. **`RestoreHostMemIfCapturingCUDAGraph` 是 Paddle 标准的 CUDA Graph 安全 H2D 模式**:任何在 CUDA Graph capture 期间需要 H2D memcpy 且 host 源为临时变量的场景,都应使用此函数做快照保护
|
||||
3. **同文件中重复模式需全部修复**:本案例中 7 处完全相同的代码模式均存在同一问题,不能只修前向不修反向
|
||||
4. **compute-sanitizer 是定位 CUDA Graph 内存问题的利器**:普通运行不报错(垃圾偏移可能"碰巧"落在合法范围内),但 `compute-sanitizer --tool memcheck` 能精确检测到越界访问
|
||||
5. **非 CUDA Graph 正常 + CUDA Graph 异常 → 优先排查 H2D/D2H memcpy 和 host 内存生命周期**:这是 CUDA Graph 模式最常见的兼容性问题类别
|
||||
|
||||
---
|
||||
|
||||
## 案例:put_along_axis CUDA Graph 模式下 Python API 层隐式 D2H 同步导致 error(906)
|
||||
|
||||
### 问题描述
|
||||
```bash
|
||||
PYTHONPATH=build/python python test_put_along_axis.py
|
||||
```
|
||||
在 CUDA Graph capture 区间内调用 `paddle.put_along_axis(x, index, value, axis=1)` 时,抛出 `CUDA error(906): cudaErrorStreamCaptureImplicit`。
|
||||
|
||||
### 关键现象
|
||||
|
||||
- 不使用 CUDA Graph 时完全正常
|
||||
- 错误栈指向 Python API 层(`manipulation.py`),而非 C++ kernel
|
||||
- 错误信息:`operation would make the legacy stream depend on a capturing blocking stream`
|
||||
|
||||
### 根因分析
|
||||
|
||||
**问题代码**(`python/paddle/tensor/manipulation.py`,`put_along_axis` 函数中):
|
||||
```python
|
||||
if (paddle.in_dynamic_mode() and indices.numel() == 0) or (
|
||||
not paddle.in_dynamic_mode() and 0 in indices.shape
|
||||
):
|
||||
return paddle.assign(arr)
|
||||
```
|
||||
|
||||
**触发链**:
|
||||
1. `indices.numel()` 返回一个 0-d GPU Tensor
|
||||
2. `== 0` 触发 `Tensor.__eq__` → 返回 boolean GPU Tensor
|
||||
3. `if` 语句触发 `Tensor.__bool__()` → `__nonzero__()`
|
||||
4. `__nonzero__()` 内部调用 `np.array(self)` → `self.numpy(False)`
|
||||
5. `numpy()` 需要 GPU→CPU 数据拷贝(D2H memcpy + stream sync on legacy stream)
|
||||
6. CUDA Graph capture 期间,legacy stream 上的 D2H 操作违反 capture 约束 → error 906
|
||||
|
||||
**影响范围**:`put_along_axis` 和 `put_along_axis_`(inplace 版本)均受影响。
|
||||
|
||||
### 修复方案
|
||||
|
||||
将 `indices.numel() == 0` 替换为 `0 in indices.shape`。`shape` 是 host 端 Python tuple,不触发任何 GPU 同步:
|
||||
|
||||
```python
|
||||
# 修复前(触发 D2H sync,CUDA Graph 不兼容)
|
||||
if (paddle.in_dynamic_mode() and indices.numel() == 0) or (
|
||||
not paddle.in_dynamic_mode() and 0 in indices.shape
|
||||
):
|
||||
|
||||
# 修复后(纯 host 端操作,CUDA Graph safe)
|
||||
if 0 in indices.shape:
|
||||
```
|
||||
|
||||
### 修复文件
|
||||
- `python/paddle/tensor/manipulation.py`(`put_along_axis` 和 `put_along_axis_` 两处)
|
||||
|
||||
### 验证结果
|
||||
|
||||
| 测试 | 修复前 | 修复后 |
|
||||
|------|--------|--------|
|
||||
| `put_along_axis` 普通模式 | PASS | PASS |
|
||||
| `put_along_axis_` (inplace) 普通模式 | PASS | PASS |
|
||||
| `put_along_axis` CUDA Graph capture + replay | **CUDA error(906)** | PASS |
|
||||
| `put_along_axis_` (inplace) CUDA Graph capture + replay | **CUDA error(906)** | PASS |
|
||||
|
||||
### 经验总结
|
||||
|
||||
1. **CUDA Graph 不兼容 Python API 层的隐式 D2H 同步**:`Tensor.__bool__()`、`Tensor.__nonzero__()`、`Tensor.numpy()` 等方法会触发 GPU→CPU 数据拷贝,在 CUDA Graph capture 期间使用会导致 error 906。这类问题的根因在 Python 层而非 C++ kernel 层,容易被忽略
|
||||
2. **`tensor.numel() == 0` 是常见的 CUDA Graph 不兼容模式**:`numel()` 返回 GPU Tensor → `== 0` 触发 `__bool__` → `numpy()` → D2H sync。应替换为 `0 in tensor.shape`(host 端 tuple 操作,零 GPU 开销)
|
||||
3. **CUDA Graph 调试时 `FLAGS_check_cuda_error=1` 不可用**:该 flag 会在每个算子前后插入 `cudaDeviceSynchronize()`,这在 capture 期间本身就会触发 error 906,不能用于定位 CUDA Graph 相关问题。应直接运行并观察原始错误栈
|
||||
4. **排查 CUDA Graph error 906 的优先级**:先检查 Python API 层是否有隐式 D2H 同步(`numpy()`、`__bool__()`、`item()`、`tolist()` 等),再检查 C++ 层的 H2D/D2H memcpy 和 stream 使用
|
||||
@@ -0,0 +1,193 @@
|
||||
# CUDA / GPU 调试技巧
|
||||
|
||||
## 常用调试环境变量
|
||||
|
||||
| 环境变量 | 作用 |
|
||||
|---------|------|
|
||||
| `FLAGS_check_cuda_error=1` | 启用 CUDA 同步错误检查,将异步错误立即暴露 |
|
||||
| `FLAGS_use_system_allocator=1` | 使用系统内存分配器,便于排查显存相关问题 |
|
||||
| `CUDA_LAUNCH_BLOCKING=1` | 强制 CUDA kernel 同步执行,便于定位出错的 kernel |
|
||||
| `FLAGS_cudnn_exhaustive_search=0` | 关闭 cuDNN 算法搜索,排除算法选择导致的不确定性 |
|
||||
| `FLAGS_cudnn_deterministic=1` | 启用 cuDNN 确定性模式 |
|
||||
| `NCCL_DEBUG=INFO` | 启用 NCCL 调试日志(分布式训练问题排查) |
|
||||
|
||||
## 常见 CUDA 错误码
|
||||
|
||||
| 错误码 | 名称 | 常见原因 |
|
||||
|--------|------|----------|
|
||||
| `CUDA error(1)` | cudaErrorInvalidValue | 非法参数值,如空指针、越界 |
|
||||
| `CUDA error(2)` | cudaErrorMemoryAllocation | 显存分配失败,OOM |
|
||||
| `CUDA error(3)` | cudaErrorInitializationError | CUDA 初始化失败,常见于 fork 后的子进程中(CUDA context 不可用) |
|
||||
| `CUDA error(4)` | cudaErrorLaunchFailure | kernel 启动失败 |
|
||||
| `CUDA error(9)` | cudaErrorInvalidConfiguration | kernel 配置无效(grid/block size 为 0 或超限) |
|
||||
| `CUDA error(11)` | cudaErrorInvalidValue | 非法设备指针或参数 |
|
||||
| `CUDA error(35)` | cudaErrorInsufficientDriver | CUDA driver 版本不足或异常 |
|
||||
| `CUDA error(100)` | cudaErrorNoDevice | 无可用 GPU 设备 |
|
||||
| `CUDA error(400)` | cudaErrorInvalidResourceHandle | 无效的 CUDA 资源句柄(stream/event 未初始化或已销毁) |
|
||||
| `CUDA error(700)` | cudaErrorIllegalAddress | 非法内存访问 |
|
||||
| `CUDA error(719)` | cudaErrorLaunchFailure | kernel 执行期间出错 |
|
||||
|
||||
## 边界条件检查要点
|
||||
|
||||
GPU kernel 对边界条件特别敏感,常见需要检查的场景:
|
||||
|
||||
- **空 Tensor / numel=0**:确保在调用 kernel 前检查,避免 grid size 为 0
|
||||
- **0-d Tensor(标量)**:shape=() 时 numel=1,但处理逻辑可能与高维不同
|
||||
- **极小 batch**:batch=1 或某个维度为 1 时,可能触发特殊分支
|
||||
- **极大 shape**:可能导致 int32 溢出或超出 GPU 线程限制
|
||||
- **数值边界**:NaN、Inf、极大/极小值可能导致数值不稳定
|
||||
|
||||
## 调试步骤示例
|
||||
|
||||
1. 启用错误检查环境变量复现问题:
|
||||
```bash
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python reproduce.py
|
||||
```
|
||||
|
||||
2. 分析错误栈,定位到具体 kernel 或 API 调用
|
||||
|
||||
3. 检查该路径的边界条件处理:
|
||||
- 是否在调用 kernel 前检查了 numel == 0?
|
||||
- 是否正确处理了 0-d tensor?
|
||||
- grid/block size 计算是否可能为 0?
|
||||
|
||||
4. 在关键位置添加日志,打印 shape、numel、配置参数
|
||||
|
||||
5. 修复后使用相同环境变量验证
|
||||
|
||||
## CUDA Sticky Error(残留错误)机制
|
||||
|
||||
### 什么是 CUDA Sticky Error
|
||||
|
||||
CUDA runtime 维护一个 "last error" 状态。当 CUDA API 调用失败时,错误会被记录到这个状态中。这个残留错误**不会自动清除**,必须通过 `cudaGetLastError()` 显式读取并清除。
|
||||
|
||||
如果一个错误未被清除,后续所有依赖 `cudaGetLastError()` 检查的操作都会检测到它——即使后续操作本身没有问题。
|
||||
|
||||
### 为什么这在 Paddle 中特别重要
|
||||
|
||||
Paddle 的 `FLAGS_check_cuda_error=1` 模式下,每个算子前后都会调用:
|
||||
```cpp
|
||||
void CUDAErrorCheck(const std::string& check_tag) {
|
||||
cudaDeviceSynchronize(); // 同步所有 pending 操作
|
||||
cudaGetLastError(); // 检查并清除 last error → 如果非0则抛异常
|
||||
}
|
||||
```
|
||||
因此,之前任何未清除的 CUDA error 都会在下一个算子执行时被检测到,表现为"看似无关的代码报错"。
|
||||
|
||||
### 常见 Sticky Error 产生场景
|
||||
|
||||
| 场景 | 原因 | 表现 |
|
||||
|------|------|------|
|
||||
| 未检查的 CUDA API 返回值 | 忽略了 `cudaEventSynchronize` 等 API 的返回值 | 错误残留,后续操作失败 |
|
||||
| try/catch 捕获 CUDA 异常 | C++ 异常被捕获但未调用 `cudaGetLastError()` | 异常虽被处理,错误仍残留 |
|
||||
| 异步 kernel 失败 | kernel 在异步执行中出错,直到同步时才被发现 | 错误在首次同步点被报告 |
|
||||
|
||||
### 防御编码规范
|
||||
|
||||
```cpp
|
||||
// 错误示例:忽略返回值
|
||||
cudaEventSynchronize(event); // ← 返回值丢弃,错误残留
|
||||
|
||||
// 正确示例 1:使用 PADDLE_ENFORCE_GPU_SUCCESS 检查
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaEventSynchronize(event));
|
||||
|
||||
// 正确示例 2:手动检查并清除(适用于允许失败的场景)
|
||||
gpuError_t err = cudaEventSynchronize(event);
|
||||
if (err != cudaSuccess) {
|
||||
cudaGetLastError(); // 清除 last error
|
||||
// 进行错误处理...
|
||||
}
|
||||
|
||||
// 注意:PADDLE_ENFORCE_GPU_SUCCESS 不会调用 cudaGetLastError(),
|
||||
// 如果需要在抛异常前清除 last error,必须手动调用。
|
||||
```
|
||||
|
||||
### 调试 Sticky Error 的方法
|
||||
|
||||
1. **确认是否为残留错误**:在报错点之前手动插入 `cudaGetLastError()` 调用,如果能清除错误且后续正常,则说明是残留
|
||||
2. **二分测试定位污染源**:逐步删减之前执行的测试/操作,找到产生残留错误的源头
|
||||
3. **Python 层快速验证**:
|
||||
```python
|
||||
import ctypes
|
||||
libcudart = ctypes.CDLL("libcudart.so")
|
||||
err = libcudart.cudaGetLastError()
|
||||
print(f"CUDA last error: {err}") # 0 表示无错误
|
||||
```
|
||||
|
||||
## CUDA Fork Safety(进程 fork 与 CUDA 的冲突)
|
||||
|
||||
### 背景
|
||||
|
||||
CUDA runtime 的 context(包括 GPU 内存句柄、stream、event 等)**在 `fork()` 后不可用**。这是 NVIDIA CUDA 的设计约束:fork 出的子进程继承了父进程的虚拟地址空间,但 CUDA driver 内部状态在子进程中是无效的。
|
||||
|
||||
任何在 fork 后的子进程中调用 CUDA API(如 `cudaGetDevice`、`cudaFree`、`cudaSetDevice`)都会返回 `cudaErrorInitializationError`(3)。
|
||||
|
||||
### 典型触发场景
|
||||
|
||||
```
|
||||
主进程: 初始化 CUDA (创建 GPU tensor / 运行 GPU 测试)
|
||||
|
|
||||
|-- fork --> DataLoader worker 子进程
|
||||
|
|
||||
|-- 继承了父进程中 GPU tensor 的 shared_ptr
|
||||
|-- GC 回收时触发 DenseTensor::~DenseTensor()
|
||||
|-- 析构链调用 cudaFree / cudaGetDevice
|
||||
|-- CUDA error(3)! ABORT!
|
||||
```
|
||||
|
||||
**关键条件组合**(三个条件同时满足才触发):
|
||||
1. 父进程已初始化 CUDA(任何 GPU 操作都算)
|
||||
2. 使用了 `fork` 方式创建子进程(如 `DataLoader(num_workers>0)`)
|
||||
3. 子进程中触发了 GPU 内存释放(继承的 GPU tensor 被 GC 回收)
|
||||
|
||||
### Paddle 中的具体调用链
|
||||
|
||||
```
|
||||
DenseTensor::~DenseTensor()
|
||||
-> ~shared_ptr<phi::Allocation>()
|
||||
-> AllocationDeleter()
|
||||
-> CUDAAllocator::FreeImpl()
|
||||
-> RecordedGpuFree()
|
||||
-> RecordedGpuMallocHelper::Free()
|
||||
-> CUDADeviceGuard(dev_id_)
|
||||
-> GetCurrentDeviceId()
|
||||
-> cudaGetDevice() <-- error 3!
|
||||
```
|
||||
|
||||
### Paddle 中的内存分配器路径
|
||||
|
||||
不同 FLAGS 配置下,GPU 内存释放走不同路径:
|
||||
|
||||
| 配置 | 分配器链 | Free 路径 |
|
||||
|------|---------|-----------|
|
||||
| 默认 | StatAllocator -> RetryAllocator -> StreamSafeCUDA -> AutoGrowth -> CUDAAllocator | 缓存池管理,不立即 cudaFree |
|
||||
| `FLAGS_use_system_allocator=1` | CUDAAllocator (直接) | 每次都调用 cudaFree |
|
||||
|
||||
`FLAGS_use_system_allocator=1` 下更容易触发此问题,因为每个 tensor 释放都直接走 `cudaFree`。
|
||||
|
||||
### 修复模式
|
||||
|
||||
在调用 CUDA API 前先做 context 可用性检查:
|
||||
|
||||
```cpp
|
||||
// 在 cudaFree / CUDADeviceGuard 之前添加
|
||||
{
|
||||
int device_id;
|
||||
auto err = cudaGetDevice(&device_id);
|
||||
if (err == cudaErrorInitializationError || // fork 后
|
||||
err == cudaErrorNoDevice || // 无 GPU
|
||||
err == cudaErrorInsufficientDriver) { // driver 异常
|
||||
cudaGetLastError(); // 清除 sticky error
|
||||
return; // 跳过释放,由 OS 回收
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
跳过 `cudaFree` 是安全的:fork 后子进程中的 GPU 内存不属于该进程,进程退出时 OS/driver 自动回收。
|
||||
|
||||
### 排查要点
|
||||
|
||||
1. **确认是否为 fork 问题**:检查错误是否发生在子进程(DataLoader worker)中,且父进程之前有 GPU 操作
|
||||
2. **单独运行不复现**:fork safety 问题通常只在多测试/多进程场景下出现——单独运行某个测试通过,全部一起跑才失败
|
||||
3. **穷举 CUDA API 调用路径**:修复时要覆盖所有可能的 CUDA API 调用点(`Free`、`FreeAsync` 等),不能只修一处
|
||||
4. **验证 .so 实际加载**:确保 Python 加载的 `.so` 是重新编译后的版本(行号对比法——如果错误消息中的行号和修改后的源码行号不一致,说明加载了旧 `.so`)
|
||||
@@ -0,0 +1,341 @@
|
||||
---
|
||||
name: paddle-design-compiler
|
||||
description: "Use when working with Paddle 3.0 compiler full pipeline: SOT (Symbolic Opcode Translator) for bytecode-level dy2st graph capture, PIR (Paddle IR) for SSA-based intermediate representation, CINN for fused CUDA kernel generation, operator decomposition (Prim), or the end-to-end flow from Python eager code to optimized GPU execution."
|
||||
---
|
||||
|
||||
# Paddle 3.0 编译器全链路
|
||||
|
||||
Paddle 3.0 的编译器体系通过 **SOT → PIR → CINN** 三阶段流水线,将用户的动态图 Python 代码编译为高性能 GPU Kernel,实现「动态图编写、编译器加速」的开发体验。
|
||||
|
||||
## 全链路概览
|
||||
|
||||
```
|
||||
用户 Python 代码(动态图 eager mode)
|
||||
│
|
||||
▼ Stage 0: SOT 图捕获
|
||||
PEP 523 eval_frame 拦截 → OpcodeExecutor 字节码模拟
|
||||
→ FunctionGraph / StatementIR
|
||||
→ paddle.jit.to_static(full_graph=True) 编译子图
|
||||
→ pir::Program
|
||||
│
|
||||
▼ Stage 1: PIR Pass 优化
|
||||
pir::Program(SSA 形式的 pd_op.* 算子图)
|
||||
│ ├── ShapeOptimizationPass(InferSymbolicShape 动态 shape 符号推导)
|
||||
│ ├── 组合算子分解 (DecompInterface → primitive operators)
|
||||
│ └── 通用 Pass 优化(常量折叠、死代码消除等)
|
||||
│
|
||||
▼ Stage 2: CINN 编译
|
||||
├── PdOpToCinnOpPass / PdOpToDynamicShapeCinnOpPass(算子映射)
|
||||
├── add_cinn_pass → cinn_op.group(算子融合)
|
||||
├── OpLower(Compute + Schedule)→ LoweredFunc
|
||||
├── CodeGenCUDA_Dev → CUDA source → NVRTC → CUfunction
|
||||
├── CompilationCache(编译缓存,相同子图复用已编译 Kernel)
|
||||
│
|
||||
▼ Stage 3: 执行
|
||||
PirInterpreter 调度 → CinnJitInstruction → cuLaunchKernel
|
||||
```
|
||||
|
||||
**SOT → PIR 的衔接**:SOT 捕获的 StatementIR 被包装为 Python 函数后,通过 `paddle.jit.to_static(full_graph=True)` 再次走 AST Transformer 路径编译为 `pir::Program`(参见 `python/paddle/jit/sot/symbolic/compile_cache.py`)。这意味着 SOT 负责"图捕获",而 `to_static` 负责"图编译"。
|
||||
|
||||
## SOT(Symbolic Opcode Translator)
|
||||
|
||||
SOT 是 Paddle 3.0 的动转静前端,在 Python VM 字节码层面拦截和模拟执行用户代码,精确捕获 Tensor 计算子图。相比旧的 AST Transformer 方案,SOT 能处理 numpy/Tensor 互操作、动态控制流、第三方库调用等复杂场景。
|
||||
|
||||
### 核心机制
|
||||
|
||||
```
|
||||
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_graph=True) → pir::Program
|
||||
└─ fallback: 子图切分 → 可静态化部分编译 + 不可静态化部分 Python 执行
|
||||
```
|
||||
|
||||
| 组件 | 说明 |
|
||||
|------|------|
|
||||
| **OpcodeExecutor** | 模拟 Python VM 执行字节码,不真正计算,而是追踪 Tensor 操作 |
|
||||
| **Variable 体系** | 将 Python 对象包装为 Variable(TensorVariable / ConstantVariable / ContainerVariable / CallableVariable) |
|
||||
| **Tracker** | 记录 Variable 来源(provenance),形成 DAG,用于生成 Guard |
|
||||
| **Guard** | `Callable[[FrameType], bool]`,判断当前帧输入是否满足编译假设,用于缓存命中判断 |
|
||||
| **FunctionGraph** | 收集 Tensor 相关操作,输出 StatementIR |
|
||||
| **StatementIR** | 4 种语句类型(call_api / call_method / call_sir / call_layer),最终经 `to_static(full_graph=True)` 编译为 Program |
|
||||
| **SideEffect** | 记录并回放模拟执行中对全局变量和可变对象的修改,保证语义等价 |
|
||||
| **OpcodeInlineExecutor** | 跨函数边界模拟执行,实现子图跨函数融合 |
|
||||
|
||||
### Fallback 场景
|
||||
|
||||
| 缩写 | 全称 | 场景 |
|
||||
|------|------|------|
|
||||
| **DDCF** | Data-Dependent Control Flow | 控制流条件依赖 Tensor 值(如 `if x.sum() > 0`) |
|
||||
| **UNSPS** | Unsupported Simulation | 无法模拟的 Python 操作(如某些 C 扩展、`.numpy()`) |
|
||||
| **CDBL** | Custom Blacklist | 用户或框架标记的不转换函数(如产生 -1 shape 的算子) |
|
||||
| **UNIMP** | Unimplemented Opcode | 尚未实现模拟的字节码指令 |
|
||||
|
||||
Fallback 是安全兜底:任何无法处理的情况退化为部分子图编译 + 部分 Python 执行,不会导致报错。
|
||||
|
||||
### 使用方式
|
||||
|
||||
```python
|
||||
# full_graph=False(默认):启用 SOT 模式(字节码级别捕获 + 自动 fallback)
|
||||
# full_graph=True:使用传统 AST Transformer(要求整图可转)
|
||||
net = paddle.jit.to_static(net) # 默认 full_graph=False,即 SOT 模式
|
||||
output = net(x)
|
||||
```
|
||||
|
||||
## PIR(Paddle Intermediate Representation)
|
||||
|
||||
PIR 是 Paddle 3.0 的统一中间表示,采用 MLIR 风格的 SSA 设计,替代旧的 ProgramDesc/OpDesc 体系。
|
||||
|
||||
### 核心概念
|
||||
|
||||
| 概念 | 关键类 | 说明 |
|
||||
|------|--------|------|
|
||||
| **Type** | `TypeID` / `AbstractType` / `TypeStorage` / `Type` | 统一类型系统:TypeID 用 static 变量地址做唯一标识,Type 本质是指向 TypeStorage 的指针,相等性通过指针比较 O(1) |
|
||||
| **Value** | `ValueImpl` / `OpResultImpl` / `OpOperandImpl` | SSA 值系统:OpResult 是算子输出(inline 0-5 / out-of-line),OpOperand 通过侵入式双向链表管理 use-chain |
|
||||
| **Operation** | `Operation`(连续内存布局) | 核心执行单元:`[OutOfLineResults | InlineResults | Operation | Operands]` 连续分配 |
|
||||
| **Block/Region** | `Block` / `Region` | Block 持有 Operation 列表 + BlockArgument + terminator;Region 是 Block 的容器,约束 Value 作用域 |
|
||||
| **Dialect** | `BuiltinDialect` / `PaddleDialect` / `CinnDialect` | 模块化容器:聚合一组 Type、Attribute、Op 定义,支持独立注册与扩展 |
|
||||
| **Trait/Interface** | `OpTraitBase` / concept-model 多态 | Trait 是静态标记,Interface 通过 concept-model 实现多态分派,替代 C++ 虚函数 |
|
||||
|
||||
### 核心 Dialect
|
||||
|
||||
| Dialect | 职责 | 典型内容 |
|
||||
|---------|------|---------|
|
||||
| `BuiltinDialect` | PIR 内置基础类型 | `Float32Type`, `Int64Type`, `VectorType`, `DenseTensorType` |
|
||||
| `PaddleDialect` | Paddle 算子定义 | `pd_op.matmul`, `pd_op.relu`, `pd_op.conv2d` |
|
||||
| `CinnDialect` | CINN 编译器专用 | `cinn_op.group`, `cinn_op.yield`, `cinn_op.generate_shape` |
|
||||
| `ControlFlowDialect` | 控制流辅助 | `cf.yield`, `cf.stack_create`, `cf.tuple_push`, `cf.tuple_pop` |
|
||||
| `PaddleDialect`(控制流部分)| 控制流算子 | `pd_op.if`, `pd_op.while` |
|
||||
|
||||
### PIR Program 结构
|
||||
|
||||
```
|
||||
Program
|
||||
├── weights: unordered_map<string, shared_ptr<Parameter>>
|
||||
└── 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")
|
||||
```
|
||||
|
||||
### 组合算子分解(Prim)
|
||||
|
||||
将高层算子分解为基础算子(primitive operators),降低编译器 / 分布式 / 新硬件适配成本:
|
||||
|
||||
- **前向分解**:`DecompInterface` → `call_decomp_rule()` → `composite.h`
|
||||
- **反向分解**(VJP):两条路径——`VjpInterface` 经 `call_vjp()` 处理前向 op 的反向;`DecompVjpInterface` 经 `call_decomp_vjp()` 分解反向 op。规则实现均在 `details.h`
|
||||
- **CustomVJP**:为 sigmoid、log_softmax 等数值敏感算子提供手写反向
|
||||
|
||||
### PIR Pass 框架
|
||||
|
||||
PIR 提供 MLIR 风格的 Pass 基础设施,用于图优化:
|
||||
|
||||
- `Pass`:单个优化 Pass 基类,通过 `Run(Operation*)` 执行
|
||||
- `PassManager`:管理 Pass 执行顺序,支持嵌套 Pipeline
|
||||
- `PatternRewritePass`:基于 Pattern Matching 的重写 Pass,通过 `RewritePattern` 定义匹配和替换规则
|
||||
|
||||
## CINN 编译与执行
|
||||
|
||||
CINN(Compiler Infrastructure for Neural Networks)将 PIR Program 中的算子子图编译为高性能 CUDA Kernel,由 PirInterpreter 调度执行。当前默认走**动态 shape**主线。
|
||||
|
||||
### 编译流水线(含动态 shape)
|
||||
|
||||
```
|
||||
PIR Program (pd_op.*)
|
||||
│
|
||||
▼ Stage 1: Frontend(前端)
|
||||
├── ShapeOptimizationPass(InferSymbolicShape 符号推导)
|
||||
├── PdOpToCinnOpPass / PdOpToDynamicShapeCinnOpPass(算子映射)
|
||||
├── add_broadcast_to_elementwise_pass(显式 broadcast 插入)
|
||||
└── add_cinn_pass → cinn_op.group(按 OpPatternKind 融合)
|
||||
│
|
||||
▼ Stage 2: Lowering(后端下降)
|
||||
├── PirCompiler → CompilationTask(per GroupOp)
|
||||
│ ├── CompilationCache 查询(命中则跳过编译)
|
||||
│ ├── OpLower:Compute → 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 → cuLaunchKernel
|
||||
```
|
||||
|
||||
### OpPatternKind 融合规则
|
||||
|
||||
| Kind | 含义 | 典型算子 |
|
||||
|------|------|---------|
|
||||
| `kElementWise` | 逐元素计算 | relu, add, multiply |
|
||||
| `kBroadcast` | 含广播语义 | broadcast_to |
|
||||
| `kInjective` | 单射映射 | reshape, transpose, slice |
|
||||
| `kReduction` | 规约操作 | reduce_sum, reduce_max |
|
||||
| `kOutFusible` | 规约但输出可继续融合 | softmax 中间步骤 |
|
||||
| `kNonFusible` | 不可融合 | custom_call, sort |
|
||||
|
||||
### Group-level Schedule(DynamicShapeGroupScheduler)
|
||||
|
||||
| 步骤 | 说明 |
|
||||
|------|------|
|
||||
| `DoLoopAlignment` | 对齐各算子的循环范围 |
|
||||
| `DoComputeInline` | 将简单计算内联到消费者 |
|
||||
| `OptimizeReduction` | 优化规约算子的并行策略 |
|
||||
| `DoHorizontalLoopFusion` | 水平融合:合并独立的并行循环 |
|
||||
| `DoVerticalLoopFusion` | 垂直融合:合并生产者-消费者循环 |
|
||||
| `BindCudaAxis` | 绑定循环到 CUDA threadIdx/blockIdx |
|
||||
| `AllocateStorage` | 分配 shared memory 和 local buffer |
|
||||
|
||||
### 编译缓存(CompilationCache)
|
||||
|
||||
CINN 对已编译的 GroupOp 结果进行缓存(基于 FusionInfo hash),相同结构的子图可直接复用已编译的 Kernel,避免重复编译开销。
|
||||
|
||||
### 执行(PirInterpreter)
|
||||
|
||||
编译完成的 Kernel 最终由 PirInterpreter 调度执行:
|
||||
|
||||
```
|
||||
StandaloneExecutor
|
||||
└─ PirInterpreter (per Job)
|
||||
│
|
||||
├─ Build(首次 Run,结果缓存)
|
||||
│ ├── 为每个 Op 构建 Instruction(Kernel 选择 + 数据传输插入)
|
||||
│ ├── 构建算子依赖 DAG → 传递性边消除
|
||||
│ ├── PirStreamAnalyzer 流调度分类(direct / event / sync)
|
||||
│ └── Variable 引用计数 → GC 生命周期管理
|
||||
│
|
||||
└─ Scheduling(每次 Run)
|
||||
├── dep_count=0 的 Instruction 推入 work queue
|
||||
├── 线程池并行派发 → kernel launch
|
||||
├── 跨 stream 同步:cudaEventRecord + cudaEventWait
|
||||
└── ref_count=0 时回收 Variable 内存
|
||||
```
|
||||
|
||||
CINN 编译产物通过 `CinnJitInstruction` 执行:从 `CINNKernelInfo` 获取 `fn_ptr`,收集输入输出 device pointer,调用 `cuLaunchKernel`。非 CINN 算子则通过 PHI Kernel 常规路径执行。
|
||||
|
||||
## 调试速查
|
||||
|
||||
| 场景 | 应关注的文件 |
|
||||
|------|------------|
|
||||
| SOT 捕获失败 / fallback 过多 | `python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py` — 检查未支持的 opcode |
|
||||
| SOT SIR 到 Program 编译失败 | `python/paddle/jit/sot/symbolic/compile_cache.py` — `to_static(full_graph=True)` 环节 |
|
||||
| PIR 动态 shape 推导错误 | `paddle/pir/src/dialect/shape/transforms/shape_optimization_pass.cc` |
|
||||
| CINN 融合策略问题 | `paddle/cinn/hlir/dialect/operator/transforms/add_cinn_pass.cc` |
|
||||
| CINN 动态 shape 算子映射 | `paddle/cinn/hlir/dialect/operator/transforms/pd_to_cinn_pass.cc` — `PdOpToDynamicShapeCinnOpPass` |
|
||||
| CINN 编译缓存命中 / 未命中 | `paddle/cinn/hlir/framework/pir/compilation_cache.cc` |
|
||||
| CINN Schedule 调试 | `paddle/cinn/ir/group_schedule/dy_shape_group_scheduler.cc` |
|
||||
| CINN CodeGen CUDA 源码 | `paddle/cinn/backends/codegen_cuda_dev.cc` |
|
||||
| 执行器 Kernel 启动 | `paddle/fluid/framework/new_executor/pir_interpreter.cc` |
|
||||
| 执行器依赖分析 / 调度 | `paddle/fluid/framework/new_executor/interpreter/stream_analyzer.cc` |
|
||||
| 执行器 Variable 内存泄漏 | `paddle/fluid/framework/new_executor/garbage_collector/` |
|
||||
|
||||
## 什么场景看什么文件
|
||||
|
||||
| 场景 | 参考文档 |
|
||||
|------|---------|
|
||||
| SOT 架构设计(eval_frame / OpcodeExecutor / Guard / Fallback) | [references/sot-design.md](references/sot-design.md) |
|
||||
| PIR 类型系统、Dialect、Trait/Interface 设计 | [references/pir-basics.md](references/pir-basics.md) |
|
||||
| PIR Program/Value/Operation 内存结构、ProgramTranslator | [references/pir-program.md](references/pir-program.md) |
|
||||
| CINN 从 GroupOp 到 CUDA Kernel 的完整编译流程 | [references/cinn-pipeline.md](references/cinn-pipeline.md) |
|
||||
| PIR 控制流(IfOp/WhileOp)、反向 Stack 机制 | [references/control-flow.md](references/control-flow.md) |
|
||||
| PIR 执行器(PirInterpreter)、Instruction 调度、Stream 分析、GC | [references/executor.md](references/executor.md) |
|
||||
|
||||
## 源码入口
|
||||
|
||||
### SOT
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| to_static 入口(full_graph 分发) | `python/paddle/jit/api.py` |
|
||||
| eval_frame 入口 | `python/paddle/jit/sot/opcode_translator/eval_frame_callback.py` |
|
||||
| OpcodeExecutor | `python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py` |
|
||||
| OpcodeInlineExecutor | `python/paddle/jit/sot/opcode_translator/executor/opcode_inline_executor.py` |
|
||||
| Variable 体系 | `python/paddle/jit/sot/opcode_translator/executor/variables/` |
|
||||
| Tracker | `python/paddle/jit/sot/opcode_translator/executor/tracker.py` |
|
||||
| Guard | `python/paddle/jit/sot/opcode_translator/executor/guard.py` |
|
||||
| FunctionGraph | `python/paddle/jit/sot/opcode_translator/executor/function_graph.py` |
|
||||
| StatementIR | `python/paddle/jit/sot/symbolic/statement_ir.py` |
|
||||
| SIR 编译缓存 | `python/paddle/jit/sot/symbolic/compile_cache.py` |
|
||||
| SideEffect | `python/paddle/jit/sot/opcode_translator/executor/side_effects.py` |
|
||||
| 符号 Shape 推导 | `python/paddle/jit/sot/symbolic_shape/` |
|
||||
|
||||
### PIR
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| PIR 核心 | `paddle/pir/include/core/` — `type.h`, `value.h`, `operation.h`, `block.h`, `program.h` |
|
||||
| IRContext / StorageManager | `paddle/pir/src/core/ir_context.cc`, `storage_manager.cc` |
|
||||
| Dialect 基类 | `paddle/pir/include/core/dialect.h` |
|
||||
| PaddleDialect | `paddle/fluid/pir/dialect/operator/ir/op_dialect.h` |
|
||||
| 控制流 Dialect | `paddle/pir/include/dialect/control_flow/ir/cf_op.h`, `cf_type.h` |
|
||||
| 控制流 Op 实现 | `paddle/fluid/pir/dialect/operator/ir/control_flow_op.h` |
|
||||
| Shape Dialect | `paddle/pir/include/dialect/shape/` |
|
||||
| ShapeOptimizationPass | `paddle/pir/src/dialect/shape/transforms/shape_optimization_pass.cc` |
|
||||
| InferSymbolicShape 接口 | `paddle/pir/include/dialect/shape/interface/infer_symbolic_shape/` |
|
||||
| Pass 框架 | `paddle/pir/include/pass/pass.h`, `pass_manager.h` |
|
||||
| Pattern Rewrite | `paddle/pir/include/pattern_rewrite/pattern_match.h` |
|
||||
| DecompInterface(Prim 前向分解接口)| `paddle/fluid/pir/dialect/operator/interface/decomp.h` |
|
||||
|
||||
### 组合算子(Prim)
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| 前向分解规则 | `paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h` |
|
||||
| 反向分解规则(VJP) | `paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h` |
|
||||
| 分解调度入口 | `paddle/fluid/primitive/base/decomp_trans.cc` |
|
||||
| Primitive 基础算子 | `paddle/fluid/primitive/primitive/primitive.h` |
|
||||
| VJP 接口 | `paddle/fluid/primitive/vjp_interface/vjp.h` |
|
||||
| Backend 适配 | `paddle/fluid/primitive/backend/backend.h` |
|
||||
|
||||
### CINN
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| CINN 总入口 Pass | `paddle/cinn/hlir/dialect/operator/transforms/add_cinn_pass.cc` |
|
||||
| 算子映射(含动态 shape)| `paddle/cinn/hlir/dialect/operator/transforms/pd_to_cinn_pass.cc` |
|
||||
| 算子融合 | `paddle/cinn/hlir/dialect/operator/transforms/cinn_group_cluster_pass.cc` |
|
||||
| PirCompiler | `paddle/cinn/hlir/framework/pir_compiler.cc` |
|
||||
| OpLower 实现 | `paddle/cinn/hlir/framework/pir/op_lowering_impl.cc` |
|
||||
| 编译任务 | `paddle/cinn/hlir/framework/pir/compilation_task.cc` |
|
||||
| 编译缓存 | `paddle/cinn/hlir/framework/pir/compilation_cache.cc` |
|
||||
| DynamicShapeGroupScheduler | `paddle/cinn/ir/group_schedule/dy_shape_group_scheduler.cc` |
|
||||
| CodeGen | `paddle/cinn/backends/codegen_cuda_dev.cc` |
|
||||
| NVRTC 编译 | `paddle/cinn/backends/nvrtc/nvrtc_util.cc` |
|
||||
| CINNKernelInfo 定义 | `paddle/cinn/hlir/framework/pir/utils.h` |
|
||||
| JitKernelOp 定义 | `paddle/cinn/hlir/dialect/runtime/ir/jit_kernel_op.h` |
|
||||
| AST IR 节点 | `paddle/cinn/ir/` |
|
||||
| Schedule 原语 | `paddle/cinn/ir/schedule/` |
|
||||
|
||||
### 执行器(PIR-based)
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| Python Executor 入口 | `python/paddle/base/executor.py` |
|
||||
| StandaloneExecutor | `paddle/fluid/framework/new_executor/standalone_executor.cc` |
|
||||
| InterpreterCore 统一入口 | `paddle/fluid/framework/new_executor/interpretercore.cc` |
|
||||
| PirInterpreter | `paddle/fluid/framework/new_executor/pir_interpreter.cc` |
|
||||
| ProgramInterpreter(旧 IR 兼容) | `paddle/fluid/framework/new_executor/program_interpreter.cc` |
|
||||
| PirStreamAnalyzer | `paddle/fluid/framework/new_executor/interpreter/stream_analyzer.cc` |
|
||||
| Instruction 定义 | `paddle/fluid/framework/new_executor/instruction/` |
|
||||
| CinnJitInstruction | `paddle/fluid/framework/new_executor/instruction/` |
|
||||
| Scope(变量容器) | `paddle/fluid/framework/scope.cc` |
|
||||
| GC 实现 | `paddle/fluid/framework/new_executor/garbage_collector/` |
|
||||
@@ -0,0 +1,185 @@
|
||||
# CINN 编译流水线
|
||||
|
||||
CINN (Compiler Infrastructure for Neural Networks) 将 PIR Program 中的算子子图编译为高性能 CUDA Kernel。整个流程分为 4 个阶段。
|
||||
|
||||
## Stage 1: Frontend(前端)
|
||||
|
||||
前端负责将 PIR 中的 Paddle 算子映射为 CINN 算子,并进行算子融合。
|
||||
|
||||
### 1.1 PdOp2CinnOpConverter
|
||||
|
||||
将 `pd_op.*` 算子转换为 `cinn_op.*` 算子。大部分映射是一对一的(如 `pd_op.relu` → `cinn_op.relu`),少数需要拆分或重组。
|
||||
|
||||
### 1.2 add_broadcast_to_elementwise_pass
|
||||
|
||||
为 elementwise 类算子显式插入 broadcast 算子。Paddle 算子隐式支持 broadcast 语义,但 CINN 后端要求 shape 严格匹配,因此前端需要补齐。
|
||||
|
||||
### 1.3 build_cinn_pass:算子融合
|
||||
|
||||
核心 Pass,将可融合的算子聚合为 `cinn_op.group`(GroupOp):
|
||||
|
||||
```
|
||||
pd_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 融合规则
|
||||
|
||||
每个算子被标记一个 `OpPatternKind`,决定融合策略:
|
||||
|
||||
| Kind | 含义 | 典型算子 |
|
||||
|------|------|---------|
|
||||
| `kElementWise` | 逐元素计算 | relu, add, multiply |
|
||||
| `kBroadcast` | 含广播语义 | broadcast_to |
|
||||
| `kInjective` | 单射映射(reshape/transpose) | reshape, transpose, slice |
|
||||
| `kReduction` | 规约操作 | reduce_sum, reduce_max |
|
||||
| `kOutFusible` | 规约但输出可继续融合 | softmax 中间步骤 |
|
||||
| `kNonFusible` | 不可融合 | custom_call, sort |
|
||||
|
||||
融合决策的基本原则:
|
||||
- `kElementWise` 可以与任何非 `kNonFusible` 的算子融合
|
||||
- `kReduction` 作为消费者时,生产者必须是 `kElementWise` 或 `kBroadcast`
|
||||
- `kNonFusible` 不参与融合,单独成组
|
||||
|
||||
## Stage 2: Lowering(后端下降)
|
||||
|
||||
将 GroupOp 中的 CINN 高层算子下降为 AST IR,并进行调度优化。
|
||||
|
||||
### 2.1 PirCompiler → OpLower
|
||||
|
||||
`PirCompiler` 为每个 GroupOp 创建 `CompilationTask`,内部通过 `OpLower` 执行 4 步流程:
|
||||
|
||||
```
|
||||
LowerOps → DoOpSchedule → DoGroupSchedule → PostProcess
|
||||
```
|
||||
|
||||
### 2.2 Compute:三层抽象
|
||||
|
||||
每个 CINN 算子的计算语义通过三层函数描述:
|
||||
|
||||
```
|
||||
pe::Relu(input, output_name) // 第1层:算子语义入口
|
||||
→ lang::Relu(input) // 第2层:数学表达式
|
||||
→ lang::Compute(domain, lambda) // 第3层:通用计算原语
|
||||
→ ComputeOp::Make(name, lambda, shape, reduce_axis)
|
||||
→ ir::Tensor (包含 ComputeOp 节点)
|
||||
```
|
||||
|
||||
- **pe 层**(Paddle Expressions):对外接口,处理算子特殊逻辑(如 reduce 轴处理)
|
||||
- **lang 层**:纯数学表达式描述
|
||||
- **Compute 层**:生成 AST IR 节点(`ComputeOp`),产出 `ir::Tensor`
|
||||
|
||||
### 2.3 AST IR 类型系统
|
||||
|
||||
CINN 内部使用自己的 AST IR(不同于 PIR):
|
||||
|
||||
```
|
||||
IrNode (基类)
|
||||
├── ExprNode<T> → Expr (表达式节点)
|
||||
│ ├── IntImm, FloatImm // 立即数
|
||||
│ ├── Add, Sub, Mul, Div, Mod // 算术运算
|
||||
│ ├── _Var_, _Tensor_ // 变量/张量引用
|
||||
│ ├── Call, Cast // 函数调用/类型转换
|
||||
│ ├── For, IfThenElse // 控制流
|
||||
│ ├── ScheduleBlock, ScheduleBlockRealize // 调度块
|
||||
│ ├── Load, Store, BufferOp // 内存操作
|
||||
│ └── Block // 语句块
|
||||
└── _Module_, _LoweredFunc_ // 顶层容器
|
||||
```
|
||||
|
||||
`Expr` 与 `IrNodeRef` 的关系:`Expr` 是 `IrNodeRef` 的子类,`IrNodeRef` 内部持有 `shared_ptr<IrNode>`。
|
||||
|
||||
### 2.4 LowerToAstVec:从 Compute 到 LoweredFunc
|
||||
|
||||
```
|
||||
GenerateFunctionBody
|
||||
→ ScheduleBlockRealize(ScheduleBlock(compute_body))
|
||||
→ 嵌套 For 循环包裹
|
||||
→ AllocateBuffers (分配中间 buffer)
|
||||
→ GenerateFunctionArgumentList (参数列表)
|
||||
→ _LoweredFunc_::Make(name, args, body)
|
||||
```
|
||||
|
||||
### 2.5 Schedule:调度优化
|
||||
|
||||
#### Op-level Schedule
|
||||
|
||||
针对单个算子的调度策略,主要处理 Reduce 类算子:
|
||||
|
||||
- Block Reduce / Warp Reduce / Discrete Reduce
|
||||
- 根据 reduce 轴大小和数据量选择策略
|
||||
|
||||
#### Group-level Schedule(DynamicShapeGroupScheduler)
|
||||
|
||||
针对整个融合组的全局调度,按顺序执行:
|
||||
|
||||
| 步骤 | 说明 |
|
||||
|------|------|
|
||||
| `DoLoopAlignment` | 对齐各算子的循环范围 |
|
||||
| `DoComputeInline` | 将简单计算内联到消费者 |
|
||||
| `OptimizeReduction` | 优化规约算子的并行策略 |
|
||||
| `DoHorizontalLoopFusion` | 水平融合:合并独立的并行循环 |
|
||||
| `DoVerticalLoopFusion` | 垂直融合:合并生产者-消费者循环 |
|
||||
| `BindCudaAxis` | 绑定循环到 CUDA threadIdx/blockIdx |
|
||||
| `AllocateStorage` | 分配 shared memory 和 local buffer |
|
||||
|
||||
## Stage 3: CodeGen(代码生成)
|
||||
|
||||
将调度优化后的 AST IR 编译为 CUDA 可执行代码:
|
||||
|
||||
```
|
||||
ir::Module (包含多个 LoweredFunc)
|
||||
│
|
||||
├─ CodeGenCUDA_Dev::Compile(module)
|
||||
│ → 遍历每个 LoweredFunc,生成 CUDA __global__ 函数源码
|
||||
│ → 处理 shared memory 声明、thread 同步等
|
||||
│
|
||||
├─ nvrtc::Compiler::operator()(cuda_source)
|
||||
│ → 调用 NVIDIA NVRTC 运行时编译 API
|
||||
│ → 生成 PTX → cubin
|
||||
│
|
||||
└─ CUDAModule::GetFunction(func_name)
|
||||
→ cuModuleLoadData + cuModuleGetFunction
|
||||
→ 返回 CUfunction 句柄
|
||||
```
|
||||
|
||||
`CodeGenCUDA_Dev` 继承自 `CodeGenC`,重写了 CUDA 特有的语法生成(如 `__global__`、`__shared__`、`threadIdx.x`、`__syncthreads()`)。
|
||||
|
||||
## Stage 4: Execution(执行)
|
||||
|
||||
### JitKernelOp
|
||||
|
||||
编译产物通过 `cinn_runtime.jit_kernel` 在 PIR 中表示:
|
||||
|
||||
```cpp
|
||||
struct CINNKernelInfo {
|
||||
std::string fn_name;
|
||||
void *fn_ptr; // CUfunction 指针
|
||||
void *infer_shape_fn_ptr; // shape 推导函数指针
|
||||
// 动态 shape 符号参数映射:kernel 参数位置 → 来源(ArgDimIdx 或 ArgValueIdx)
|
||||
std::map<int, SymbolArgBindInfo> symbol_args_map;
|
||||
};
|
||||
```
|
||||
|
||||
### PdOpLowerToKernelPass
|
||||
|
||||
将整个 PIR Program 中的 GroupOp 替换为 JitKernelOp:
|
||||
|
||||
```
|
||||
cinn_op.group { ... } → cinn_runtime.jit_kernel (携带 CINNKernelInfo)
|
||||
```
|
||||
|
||||
### CinnJitInstruction
|
||||
|
||||
执行器层面,`CinnJitInstruction` 负责实际的 Kernel 启动:
|
||||
|
||||
1. 从 `CINNKernelInfo` 获取 `fn_ptr`
|
||||
2. 收集输入/输出 Tensor 的 device pointer
|
||||
3. 处理动态 int 参数(shape 维度等)
|
||||
4. 调用 `cuLaunchKernel` 执行
|
||||
|
||||
整个流水线的端到端路径:`pd_op.relu + pd_op.add` → GroupOp → Compute → AST IR → Schedule → LoweredFunc → CUDA source → PTX → CUfunction → `cuLaunchKernel`。
|
||||
@@ -0,0 +1,189 @@
|
||||
# PIR 控制流设计
|
||||
|
||||
PIR 通过 Region 嵌套实现结构化控制流,避免传统 CFG 中的 phi 节点和复杂跳转。
|
||||
|
||||
## Block 与 Region 基础
|
||||
|
||||
### Block
|
||||
|
||||
```cpp
|
||||
class Block {
|
||||
std::list<Operation *> ops_; // Operation 链表
|
||||
std::vector<BlockArgument> args_; // Block 参数(类似 MLIR 的 BlockArgument)
|
||||
Region *parent_region_; // 所属 Region
|
||||
};
|
||||
```
|
||||
|
||||
- Block 内的 Operation 按顺序排列
|
||||
- 最后一个 Operation 必须是 **terminator**(如 `cf.yield`)
|
||||
- `BlockArgument` 是 Block 的输入 Value,由外层 Operation 定义
|
||||
|
||||
### Region
|
||||
|
||||
```cpp
|
||||
class Region {
|
||||
std::vector<Block *> blocks_;
|
||||
Operation *parent_op_; // 所属 Operation
|
||||
};
|
||||
```
|
||||
|
||||
Region 是 Block 的有序容器。作用域规则:Region 内部定义的 Value **不能**被外部引用,但内部可以**捕获**外部 Value(类似闭包语义)。
|
||||
|
||||
## 控制流 Op 分布
|
||||
|
||||
控制流相关 Op 分布在两个 Dialect 中:
|
||||
|
||||
| Op 名称 | 所属 Dialect | 用途 |
|
||||
|---------|-------------|------|
|
||||
| `pd_op.if` | PaddleDialect | 条件分支 |
|
||||
| `pd_op.while` | PaddleDialect | 循环 |
|
||||
| `cf.has_elements` | PaddleDialect(定义在 control_flow_op.h) | 判断 Stack 是否有元素(反向 while 条件) |
|
||||
| `pd_op.assert` | PaddleDialect | 断言 |
|
||||
| `cf.yield` | ControlFlowDialect | Region 通用终止符,返回值给外层 Operation |
|
||||
| `cf.stack_create` | ControlFlowDialect | 创建 Stack(含 inlet/outlet 两端) |
|
||||
| `cf.tuple_push` | ControlFlowDialect | 向 Stack 的 inlet 端压入值 |
|
||||
| `cf.tuple_pop` | ControlFlowDialect | 从 Stack 的 outlet 端弹出值 |
|
||||
|
||||
## IfOp:条件分支
|
||||
|
||||
```
|
||||
%result = pd_op.if(%condition) {
|
||||
// Region[0]: true_region (then branch)
|
||||
%a = pd_op.relu(%x)
|
||||
cf.yield(%a)
|
||||
} else {
|
||||
// Region[1]: false_region (else branch)
|
||||
%b = pd_op.tanh(%x)
|
||||
cf.yield(%b)
|
||||
}
|
||||
```
|
||||
|
||||
### IfOp 结构
|
||||
|
||||
- **输入**:1 个 bool 类型的 condition Value
|
||||
- **Region 数量**:固定 2 个
|
||||
- Region[0]:`true_region`(then 分支)
|
||||
- Region[1]:`false_region`(else 分支)
|
||||
- **输出**:`cf.yield` 返回的值,两个分支的返回类型必须一致
|
||||
- **terminator**:每个分支的最后一个 Op 必须是 `cf.yield`
|
||||
|
||||
### 源码定义
|
||||
|
||||
```
|
||||
paddle/fluid/pir/dialect/operator/ir/control_flow_op.h — IfOp
|
||||
├── cond() → 获取条件 Value
|
||||
├── true_region() → Region[0]
|
||||
├── false_region() → Region[1]
|
||||
├── true_block() → Region[0] 的 Block
|
||||
└── false_block() → Region[1] 的 Block
|
||||
```
|
||||
|
||||
## WhileOp:循环
|
||||
|
||||
```
|
||||
// 语义等价于:
|
||||
// outputs = inputs
|
||||
// while(cond) {
|
||||
// cond, outputs = body(outputs)
|
||||
// }
|
||||
|
||||
%results = pd_op.while(%cond, %init_val) {
|
||||
// Region[0]: body
|
||||
^bb(%iter_arg):
|
||||
%new_val = pd_op.add(%iter_arg, %step)
|
||||
%new_cond = pd_op.less_than(%new_val, %limit)
|
||||
cf.yield(%new_cond, %new_val) // 第一个返回值更新 cond,其余更新 loop_vars
|
||||
}
|
||||
```
|
||||
|
||||
### WhileOp 结构
|
||||
|
||||
- **输入**:cond Value + loop_vars(循环初始值)
|
||||
- **Region 数量**:固定 1 个
|
||||
- Region[0]:body(循环体)
|
||||
- **body BlockArgument**:与 loop_vars 一一对应
|
||||
- **body terminator**:`cf.yield(new_cond, new_values...)`
|
||||
- 第一个返回值更新循环条件
|
||||
- 其余返回值更新 loop_vars,成为下一次迭代的 BlockArgument
|
||||
- 当 cond 为 false 时退出循环,最后的 new_values 成为 WhileOp 的输出
|
||||
|
||||
### 数据流循环
|
||||
|
||||
```
|
||||
cond, init_vals → WhileOp
|
||||
└── body Region
|
||||
├── BlockArgs = loop_vars
|
||||
├── ... 计算 ...
|
||||
└── cf.yield(new_cond, new_vals)
|
||||
│
|
||||
├── new_cond=true → 回到 body(new_vals → BlockArgs)
|
||||
└── new_cond=false → 退出(new_vals → WhileOp outputs)
|
||||
```
|
||||
|
||||
## 反向支持:Stack 机制
|
||||
|
||||
控制流的反向求导面临一个核心问题:前向执行中的局部变量(如循环体内的中间 Tensor)在反向时可能需要使用,但由于 Region 作用域限制,反向 Region 无法直接访问前向 Region 的 Value。
|
||||
|
||||
PIR 使用 **Stack 机制**(基于 `cf.stack_create` / `cf.tuple_push` / `cf.tuple_pop`)解决此问题。
|
||||
|
||||
### Stack 创建
|
||||
|
||||
```
|
||||
(%stack, %inlet, %outlet) = cf.stack_create()
|
||||
```
|
||||
|
||||
`cf.stack_create` 创建一个 Stack 容器,返回三个值:
|
||||
- `%stack`:Stack 引用(用于 `cf.has_elements` 查询)
|
||||
- `%inlet`:入口端(用于 `cf.tuple_push` 压入)
|
||||
- `%outlet`:出口端(用于 `cf.tuple_pop` 弹出)
|
||||
|
||||
### 三步构造过程
|
||||
|
||||
#### Step 1:修改前向——Push 中间变量
|
||||
|
||||
在前向控制流中插入 `cf.tuple_push` 操作,将反向需要的中间变量压入 Stack:
|
||||
|
||||
```
|
||||
// 前向 WhileOp body(修改后)
|
||||
^bb(%x):
|
||||
%y = pd_op.relu(%x)
|
||||
cf.tuple_push(%inlet, %x) // 保存 x 供反向使用
|
||||
cf.tuple_push(%inlet, %y) // 保存 y 供反向使用
|
||||
cf.yield(%new_cond, %y)
|
||||
```
|
||||
|
||||
#### Step 2:构造反向——Pop 中间变量
|
||||
|
||||
反向控制流中通过 `cf.tuple_pop` 按 LIFO 顺序取出前向保存的变量:
|
||||
|
||||
```
|
||||
// 反向 WhileOp body
|
||||
^bb(%dy):
|
||||
%y = cf.tuple_pop(%outlet) // 后入先出:先 pop y
|
||||
%x = cf.tuple_pop(%outlet) // 再 pop x
|
||||
%dx = pd_op.relu_grad(%x, %y, %dy)
|
||||
cf.yield(%has_elements, %dx)
|
||||
```
|
||||
|
||||
反向 WhileOp 的循环条件通过 `cf.has_elements(%stack)` 判断 Stack 是否还有元素。
|
||||
|
||||
#### Step 3:剪枝——移除未使用的 Op
|
||||
|
||||
反向图构建完成后,执行 DCE(Dead Code Elimination)Pass,移除前向中不被反向使用的 `tuple_push` 以及对应的 `stack_create`,减少不必要的内存开销。
|
||||
|
||||
### Stack 机制的优势
|
||||
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
| 作用域安全 | Stack 在控制流 Op 外部创建,对所有子 Region 可见 |
|
||||
| LIFO 语义 | 天然匹配循环反向的逆序访问模式 |
|
||||
| 可剪枝 | 未使用的 Stack 可在编译期移除 |
|
||||
| 统一处理 | IfOp 和 WhileOp 使用相同的 Stack 机制 |
|
||||
|
||||
## 关键源码路径
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `paddle/fluid/pir/dialect/operator/ir/control_flow_op.h` | IfOp、WhileOp、HasElementsOp、AssertOp 定义 |
|
||||
| `paddle/pir/include/dialect/control_flow/ir/cf_op.h` | YieldOp、StackCreateOp、TuplePushOp、TuplePopOp 定义 |
|
||||
| `paddle/pir/include/dialect/control_flow/ir/cf_type.h` | StackType 类型定义 |
|
||||
@@ -0,0 +1,130 @@
|
||||
# PIR 执行器(PirInterpreter)
|
||||
|
||||
## 概览
|
||||
|
||||
PIR 执行器负责将编译好的 `pir::Program`(经过 Kernel 选择、Pass 优化后的 kernel-level IR)翻译为可执行的 Instruction 序列,通过依赖分析和多 stream 异步调度实现高效执行。
|
||||
|
||||
核心流程:`StandaloneExecutor` → `InterpreterCore` → `PirInterpreter`
|
||||
|
||||
## 入口:StandaloneExecutor
|
||||
|
||||
```
|
||||
StandaloneExecutor(place, plan)
|
||||
│
|
||||
├─ 遍历 Plan 中的每个 Job
|
||||
│ ├─ PdOpLowerToKernelPass(pd_op → pd_kernel/onednn_kernel)
|
||||
│ ├─ InplacePass(可选)
|
||||
│ └─ 创建 InterpreterCore → 内部持有 PirInterpreter
|
||||
│
|
||||
└─ Run(feed_names, feed_tensors)
|
||||
└─ 按 Job 顺序依次调用 InterpreterCore::Run()
|
||||
```
|
||||
|
||||
每个 Job 对应一段需要执行的 Program。多数简单场景只有一个 Job,pipeline 并行等场景会有多个。
|
||||
|
||||
## PirInterpreter 执行流程
|
||||
|
||||
PirInterpreter 首次 `Run()` 时执行 Build 阶段(结果缓存,后续 Run 跳过),然后进入 Scheduling 阶段。
|
||||
|
||||
### Build 阶段
|
||||
|
||||
#### Step 1: BuildInstruction — 构建 Instruction 列表
|
||||
|
||||
遍历 `pir::Block` 中的每个 Operation,根据其所属 Dialect 创建对应的 Instruction:
|
||||
|
||||
| Dialect | Operation | Instruction |
|
||||
|---------|-----------|-------------|
|
||||
| `builtin` | `CombineOp` | `BuiltinCombineInstruction` |
|
||||
| `cf` | `TuplePushOp` / `TuplePopOp` / `YieldOp` | 对应的控制流 Instruction |
|
||||
| `pd_op` | `IfOp` | `IfInstruction`(含 true/false 两个子 PirInterpreter) |
|
||||
| `pd_op` | `WhileOp` | `WhileInstruction`(含 body 子 PirInterpreter) |
|
||||
| `pd_op` | `PyLayerOp` | `PyLayerInstruction` |
|
||||
| `pd_op` | `HasElementsOp` / `AssertOp` / `SelectInput/OutputOp` | 各自对应的 Instruction |
|
||||
| `pd_kernel` | 普通算子 | `PhiKernelInstruction` |
|
||||
| `pd_kernel` | 旧算子 | `LegacyKernelInstruction` |
|
||||
| `onednn_kernel` | OneDNN 算子 | `OneDNNPhiKernelInstruction` 等 |
|
||||
| `cinn_runtime` | `jit_kernel` | `CinnJitInstruction` |
|
||||
| `custom_kernel` | 自定义算子 | `CustomKernelInstruction` |
|
||||
| `py_func` | Python 函数 | `PythonFunctionInstruction` |
|
||||
|
||||
控制流 Op(IfOp / WhileOp / PyLayerOp)会递归创建子 PirInterpreter 处理内部 Block。
|
||||
|
||||
#### Step 2: BuildInstructionDependences — 构建依赖 DAG
|
||||
|
||||
基于数据依赖(RAW/WAR/WAW)分析 Instruction 间的执行顺序,构建有向无环图(DAG)。传递性边被消除以减少冗余同步。
|
||||
|
||||
每条依赖边根据两端 Instruction 的 KernelType 分为:
|
||||
- **SameThread**:同类算子(如 GPU→GPU),放入同一线程的 ready queue
|
||||
- **DifferentThread**:异类算子(如 GPU→CPU),通过线程池 AddTask 跨线程调度
|
||||
|
||||
每个 Instruction 记录 `dependency_count`(入度),为 0 时可被调度执行。
|
||||
|
||||
#### Step 3: Stream 调度分析
|
||||
|
||||
`PirStreamAnalyzer::AnalyseAllEventInfo` 对 DAG 中的每条跨 stream 边分类:
|
||||
|
||||
| 类型 | 含义 | 同步方式 |
|
||||
|------|------|---------|
|
||||
| `kDirectRun` | 同一 stream 上的连续算子 | 无需同步(stream 内天然有序) |
|
||||
| `kEventRun` | 不同 stream 之间的数据依赖 | `cudaEventRecord` + `cudaEventWait` |
|
||||
|
||||
每个 Instruction 在执行前会 `WaitEvent`(等待上游的跨 stream 事件),执行后 `RecordEvent`(通知下游)。
|
||||
|
||||
#### Step 4: Variable 引用计数
|
||||
|
||||
计算每个非 persistable Variable 的引用计数(被后续 Instruction 使用的次数)。引用计数归零时,GC 回收其内存。
|
||||
|
||||
### Scheduling 阶段
|
||||
|
||||
每次 `Run()` 进入异步调度循环:
|
||||
|
||||
```
|
||||
RunInstructionBaseAsync:
|
||||
│
|
||||
├─ 初始化:dep_count=0 的 Instruction 推入 SchedulingQueue(优先级队列)
|
||||
│
|
||||
└─ while queue 非空:
|
||||
├─ Pop 优先级最高的 Instruction
|
||||
├─ RunInstructionBase:WaitEvent → 执行 kernel → RecordEvent
|
||||
├─ RunNextInstructions:
|
||||
│ ├─ 遍历 DifferentThread 下游 → dep_count-1,为 0 则 AddTask 到线程池
|
||||
│ └─ 遍历 SameThread 下游 → dep_count-1,为 0 则推入本线程 queue
|
||||
└─ GC:ref_count-1,为 0 则回收 Variable 内存
|
||||
```
|
||||
|
||||
线程池驱动多个无依赖的 Instruction 并行派发。GPU 算子在 CUDA stream 上异步执行,线程池仅负责 kernel launch。
|
||||
|
||||
## GC(垃圾回收)
|
||||
|
||||
| GC 实现 | 使用场景 |
|
||||
|---------|---------|
|
||||
| `EventGarbageCollector` | GPU 模式默认,基于 CUDA event 判断何时安全释放 |
|
||||
| `FastGarbageCollector` | CPU 模式,直接释放 |
|
||||
| `AsyncFastGarbageCollector` | 异步快速释放 |
|
||||
| `NoEventGarbageCollector` | 无 event 模式 |
|
||||
|
||||
WhileOp 还支持 **early GC**:在循环体内部,如果一个 Variable 的动态引用计数降为 1 且不被循环体后续使用,可以提前回收。
|
||||
|
||||
## CINN Kernel 执行
|
||||
|
||||
CINN 编译产物通过 `CinnJitInstruction` 执行:
|
||||
1. 从 `CINNKernelInfo` 获取 `fn_ptr`(编译好的 CUDA kernel 函数指针)
|
||||
2. 通过 `symbol_args_map` 收集输入输出 device pointer
|
||||
3. 调用 `cuLaunchKernel` 执行
|
||||
|
||||
## 关键源码路径
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| Python Executor 入口 | `python/paddle/base/executor.py` |
|
||||
| StandaloneExecutor | `paddle/fluid/framework/new_executor/standalone_executor.cc` |
|
||||
| InterpreterCore 统一入口 | `paddle/fluid/framework/new_executor/interpretercore.cc` |
|
||||
| PirInterpreter | `paddle/fluid/framework/new_executor/pir_interpreter.cc` |
|
||||
| Instruction 基类 | `paddle/fluid/framework/new_executor/instruction/instruction_base.h` |
|
||||
| PhiKernelInstruction | `paddle/fluid/framework/new_executor/instruction/phi_kernel_instruction.cc` |
|
||||
| CinnJitInstruction | `paddle/fluid/framework/new_executor/instruction/cinn_jit_instruction.cc` |
|
||||
| 控制流 Instruction | `paddle/fluid/framework/new_executor/instruction/control_flow/` |
|
||||
| PirStreamAnalyzer | `paddle/fluid/framework/new_executor/interpreter/stream_analyzer.cc` |
|
||||
| 依赖分析 | `paddle/fluid/framework/new_executor/interpreter/dependency_builder.cc` |
|
||||
| GC 实现 | `paddle/fluid/framework/new_executor/garbage_collector/` |
|
||||
| Scope(变量容器) | `paddle/fluid/framework/scope.cc` |
|
||||
@@ -0,0 +1,190 @@
|
||||
# PIR 类型系统与可扩展组件
|
||||
|
||||
## 动机:统一三套断裂的类型系统
|
||||
|
||||
Paddle 旧体系存在三套相互独立的类型系统——`framework::proto::VarType`(静态图)、`DataType/DataLayout`(PHI 算子库)、以及推理阶段的类型表示。它们之间通过大量 `switch-case` 硬编码转换,既难以维护也无法扩展。PIR 参考 MLIR 设计理念,用一套统一的类型系统替代三者,核心目标:
|
||||
|
||||
1. **可扩展**:新增类型无需修改核心框架代码
|
||||
2. **高性能**:类型相等性通过指针比较完成,O(1) 复杂度
|
||||
3. **模块化**:类型归属于 Dialect,不同 Dialect 独立注册
|
||||
|
||||
## 类型系统核心类
|
||||
|
||||
### TypeID:类型的唯一标识
|
||||
|
||||
```cpp
|
||||
class TypeID {
|
||||
const StorageUniquer::TypeIDAllocator *storage_; // 静态变量指针
|
||||
};
|
||||
```
|
||||
|
||||
每种类型在编译期通过 `TypeIDAllocator::Get<T>()` 获得一个唯一的 `TypeID`。实现技巧:利用 C++ 模板函数内的 `static` 局部变量地址天然唯一——不同类型实例化不同的函数,地址自然不同。
|
||||
|
||||
### AbstractType:类型的元信息
|
||||
|
||||
```cpp
|
||||
struct AbstractType {
|
||||
TypeID type_id_;
|
||||
Dialect &dialect_; // 所属 Dialect
|
||||
InterfaceMap interface_map_; // 该类型实现的 Interface 集合
|
||||
HasTraitFunction has_trait_; // Trait 查询函数
|
||||
};
|
||||
```
|
||||
|
||||
`AbstractType` 在 `IRContext` 中按 `TypeID` 注册一次,是类型的"类描述符"。
|
||||
|
||||
### TypeStorage:类型实例的存储
|
||||
|
||||
```cpp
|
||||
class TypeStorage : public StorageManager::StorageBase {
|
||||
AbstractType *abstract_type_;
|
||||
};
|
||||
```
|
||||
|
||||
无参数类型(如 `Float32Type`)全局只有一个 `TypeStorage` 实例;带参数类型(如 `DenseTensorType`)按参数值 hash 唯一化存储(uniquing),相同参数返回同一指针。
|
||||
|
||||
### Type:面向用户的轻量包装
|
||||
|
||||
```cpp
|
||||
class Type {
|
||||
TypeStorage *storage_{nullptr};
|
||||
};
|
||||
```
|
||||
|
||||
`Type` 是值语义的轻量对象,仅包装一个指向 `TypeStorage` 的指针。两个 Type 相等 <==> 指针相等。用户通过 `Type::isa<T>()` 和 `Type::dyn_cast<T>()` 做类型判断和转换。
|
||||
|
||||
### TypeBase 模板:定义具体类型
|
||||
|
||||
```cpp
|
||||
template <typename ConcreteT, typename BaseT, typename StorageT>
|
||||
class TypeBase : public BaseT {
|
||||
// ConcreteT: 具体类型类 (如 DenseTensorType)
|
||||
// BaseT: 基类 (通常是 Type)
|
||||
// StorageT: 存储类 (如 DenseTensorTypeStorage)
|
||||
};
|
||||
```
|
||||
|
||||
## 参数化类型示例:DenseTensorType
|
||||
|
||||
```cpp
|
||||
struct DenseTensorTypeStorage : public TypeStorage {
|
||||
using KeyTy = std::tuple<Type, DDim, DataLayout, LoD, size_t>;
|
||||
|
||||
static std::size_t hashFunc(const KeyTy &key) { ... }
|
||||
static DenseTensorTypeStorage *construct(IRContext *ctx, const KeyTy &key) { ... }
|
||||
bool operator==(const KeyTy &key) const { ... }
|
||||
|
||||
Type dtype_;
|
||||
DDim dims_;
|
||||
DataLayout layout_;
|
||||
LoD lod_;
|
||||
size_t offset_;
|
||||
};
|
||||
```
|
||||
|
||||
获取或创建实例:
|
||||
|
||||
```cpp
|
||||
auto dt = DenseTensorType::get(ctx, dtype, dims, layout, lod, offset);
|
||||
```
|
||||
|
||||
`IRContext` 内部通过 `StorageManager` 管理所有 `TypeStorage`,以 hash 表做 uniquing——如果已存在相同参数的实例直接返回指针,否则 `construct()` 创建并缓存。
|
||||
|
||||
## 类型使用方式
|
||||
|
||||
```cpp
|
||||
Type t = some_value.type();
|
||||
|
||||
// 类型判断
|
||||
if (t.isa<DenseTensorType>()) { ... }
|
||||
|
||||
// 类型转换(失败返回 nullptr 语义的空 Type)
|
||||
if (auto dt = t.dyn_cast<DenseTensorType>()) {
|
||||
auto dims = dt.dims();
|
||||
}
|
||||
|
||||
// 相等性
|
||||
if (t1 == t2) { ... } // 指针比较,O(1)
|
||||
```
|
||||
|
||||
## Attribute 系统
|
||||
|
||||
Attribute 与 Type 共享相同的 uniquing 基础设施,区别在于语义:Type 描述 Value 的类型,Attribute 描述 Operation 的常量属性。
|
||||
|
||||
### AttributeStorage
|
||||
|
||||
结构与 `TypeStorage` 对称:`AbstractAttribute` + `AttributeStorage` + `Attribute` 包装。
|
||||
|
||||
### DictionaryAttribute
|
||||
|
||||
PIR 中每个 `Operation` 的属性集合用 `DictionaryAttribute` 存储:
|
||||
|
||||
```cpp
|
||||
class DictionaryAttributeStorage : public AttributeStorage {
|
||||
std::vector<NamedAttribute> data_; // 按 key 排序的 (StrAttribute, Attribute) 对
|
||||
};
|
||||
```
|
||||
|
||||
查找时使用**二分搜索**,插入时保持有序。`NamedAttribute` 是 `std::pair<StrAttribute, Attribute>`。
|
||||
|
||||
## 可扩展组件:Trait 与 Interface
|
||||
|
||||
### Trait:静态标记
|
||||
|
||||
Trait 是无状态的编译期标记,用于表示 Operation 或 Type 的某种静态属性:
|
||||
|
||||
```cpp
|
||||
// 定义
|
||||
template <typename ConcreteOp>
|
||||
class ReadOnlyTrait : public OpTraitBase<ConcreteOp, ReadOnlyTrait> {};
|
||||
|
||||
// 查询
|
||||
if (op->HasTrait<ReadOnlyTrait>()) { ... }
|
||||
```
|
||||
|
||||
常见 Trait:`InplaceTrait`、`SideEffectTrait`、`SameOperandsAndResultTypeTrait`。
|
||||
|
||||
### Interface:动态分派
|
||||
|
||||
Interface 采用 **concept-model** 模式实现多态,避免虚函数表的开销:
|
||||
|
||||
```cpp
|
||||
// Concept(纯虚接口)
|
||||
struct InferShapeInterface::Concept {
|
||||
void (*infer_shape)(Operation *);
|
||||
};
|
||||
|
||||
// Model(具体实现)
|
||||
template <typename ConcreteOp>
|
||||
struct InferShapeInterface::Model : Concept {
|
||||
static void infer_shape(Operation *op) {
|
||||
ConcreteOp::InferShape(op);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
`OpInfo` 内部持有 `InterfaceMap`(按 `TypeID` 索引的 concept 指针数组),调用时通过 `TypeID` 查找到对应 `Concept*`,再调用函数指针——一次间接跳转,无虚表开销。
|
||||
|
||||
## Dialect:模块化容器
|
||||
|
||||
```cpp
|
||||
class Dialect {
|
||||
std::string name_;
|
||||
TypeID dialect_id_;
|
||||
IRContext *context_;
|
||||
};
|
||||
```
|
||||
|
||||
每个 Dialect 是 Type、Attribute、Op 定义的**注册容器**,通过 `IRContext::RegisterDialect<T>()` 加载。
|
||||
|
||||
### 核心 Dialect
|
||||
|
||||
| Dialect | 职责 | 典型内容 |
|
||||
|---------|------|---------|
|
||||
| `BuiltinDialect` | PIR 内置基础类型 | `Float32Type`, `Int64Type`, `VectorType`, `DenseTensorType` |
|
||||
| `PaddleDialect` | Paddle 算子定义 | `pd_op.matmul`, `pd_op.relu`, `pd_op.conv2d` 等 |
|
||||
| `CinnDialect` | CINN 编译器专用 | `cinn_op.group`, `cinn_op.yield`, `cinn_op.generate_shape` |
|
||||
| `ControlFlowDialect` | 控制流辅助 | `cf.yield`, `cf.stack_create`, `cf.tuple_push`, `cf.tuple_pop` |
|
||||
| `PaddleDialect`(控制流部分)| 控制流算子 | `pd_op.if`, `pd_op.while` |
|
||||
|
||||
Dialect 的模块化设计使得第三方可以定义自己的 Dialect 并注册到 `IRContext`,无需修改 PIR 核心代码。
|
||||
@@ -0,0 +1,183 @@
|
||||
# PIR Program 与模型结构
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. **严格 SSA**:每个 Value 有且仅有一个定义点(def-site),所有使用点(use-site)通过 use-chain 链接
|
||||
2. **Pimpl 模式**:用户侧 `Value`/`OpResult`/`OpOperand` 只是轻量句柄,实际数据存于 `*Impl` 类
|
||||
3. **三层架构**:面向用户的 API 层 → Pimpl 实现层 → 连续内存布局层
|
||||
|
||||
## Value 系统
|
||||
|
||||
### ValueImpl:SSA Value 的基础
|
||||
|
||||
```cpp
|
||||
class ValueImpl {
|
||||
Type type_; // 值的类型
|
||||
OpOperandImpl *first_user_; // use-list 链表头
|
||||
};
|
||||
```
|
||||
|
||||
每个 `ValueImpl` 维护一个侵入式链表,串联所有使用该 Value 的 `OpOperandImpl`。
|
||||
|
||||
### OpResultImpl:Operation 的输出
|
||||
|
||||
Operation 的输出结果分为两种存储方式:
|
||||
|
||||
- **Inline Result**(index 0-5):`OpInlineResultImpl` 直接存储在 Operation 前方的连续内存中,将 result index 编码在对象自身(利用低位 bit)
|
||||
- **Out-of-line Result**(index >= 6):`OpOutOfLineResultImpl` 存储在更前方的内存区域,持有显式的 `result_index_` 字段
|
||||
|
||||
```cpp
|
||||
class OpInlineResultImpl : public ValueImpl {
|
||||
// index 编码在 ValueImpl 前方的内存标记中
|
||||
// 通过地址偏移可反向定位到所属 Operation
|
||||
};
|
||||
|
||||
class OpOutOfLineResultImpl : public ValueImpl {
|
||||
uint32_t result_index_;
|
||||
};
|
||||
```
|
||||
|
||||
这种设计的关键优势:给定一个 `OpResult`,可以通过地址运算直接找到所属 `Operation`,无需额外指针。
|
||||
|
||||
### OpOperandImpl:Operation 的输入
|
||||
|
||||
```cpp
|
||||
class OpOperandImpl {
|
||||
ValueImpl *source_; // 指向被使用的 Value
|
||||
OpOperandImpl *next_user_; // use-list 中的下一个使用者
|
||||
OpOperandImpl **back_addr_; // 指向前一个节点的 next_user_ 指针(双向链表的"反向指针")
|
||||
Operation *owner_; // 所属 Operation
|
||||
};
|
||||
```
|
||||
|
||||
四个字段构成侵入式双向链表:
|
||||
|
||||
- `source_` → 指向定义点的 `ValueImpl`
|
||||
- `next_user_` + `back_addr_` → 链表的前后链接
|
||||
- `owner_` → 可快速回溯到使用该 Value 的 Operation
|
||||
|
||||
**遍历 use-chain**:从 `ValueImpl::first_user_` 出发,沿 `next_user_` 遍历所有使用者,每个使用者通过 `owner_` 获取所属 Operation。
|
||||
|
||||
## Operation 内存布局
|
||||
|
||||
Operation 采用连续内存分配,所有关联数据在一次 `malloc` 中完成:
|
||||
|
||||
```
|
||||
低地址 ──────────────────────────────────────────── 高地址
|
||||
[OpOutOfLineResults | OpInlineResults | Operation | OpOperands]
|
||||
↑ this 指针
|
||||
```
|
||||
|
||||
- `Operation` 的 `this` 指针位于中间
|
||||
- 向低地址方向:先是 InlineResults (最多6个),再是 OutOfLineResults
|
||||
- 向高地址方向:紧跟 OpOperands 数组
|
||||
|
||||
### Operation 核心字段
|
||||
|
||||
```cpp
|
||||
class Operation {
|
||||
DictionaryAttribute attrs_; // 属性字典(sorted pairs, binary search)
|
||||
OpInfo info_; // 指向 OpInfoImpl 的指针
|
||||
uint32_t num_results_; // 输出数量
|
||||
uint32_t num_operands_; // 输入数量
|
||||
uint32_t num_regions_; // Region 数量
|
||||
Block *parent_block_; // 所属 Block
|
||||
Region *regions_; // Region 数组(动态分配)
|
||||
};
|
||||
```
|
||||
|
||||
### OpInfo 与 OpInfoImpl
|
||||
|
||||
```cpp
|
||||
class OpInfoImpl {
|
||||
InterfaceMap interface_map_; // concept-model 多态
|
||||
HasTraitFunction has_trait_;
|
||||
VerifyFunction verify_;
|
||||
std::vector<InterfaceValue> interface_set_;
|
||||
};
|
||||
```
|
||||
|
||||
`OpInfo` 是 `OpInfoImpl*` 的轻量包装。`InterfaceMap` 内部按 `TypeID` 排序,查找 Interface 实现时用二分搜索定位 `Concept*`,再通过函数指针调用——这就是 **concept-model 多态** 的核心机制,替代 C++ 虚函数。
|
||||
|
||||
## 权重与参数管理
|
||||
|
||||
PIR Program 通过 `ParameterMap`(`unordered_map<string, shared_ptr<Parameter>>`)管理模型权重:
|
||||
|
||||
```
|
||||
Program
|
||||
├── computation graph (ModuleOp → Block → Operations)
|
||||
└── parameters_: {"linear.weight" → Parameter*, "linear.bias" → Parameter*, ...}
|
||||
```
|
||||
|
||||
两个专用 Op 桥接计算图与权重:
|
||||
|
||||
- **`builtin.parameter("linear.weight")`** → 从参数表读取,产生一个 `Value`
|
||||
- **`builtin.set_parameter(value, "linear.weight")`** → 将计算结果写回参数表
|
||||
|
||||
这种设计将权重存储与计算图解耦,便于序列化和分布式场景下的参数分片。
|
||||
|
||||
## 模型嵌套结构
|
||||
|
||||
```
|
||||
Program
|
||||
└── 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) → %3
|
||||
│ │ └── cf.yield(%3)
|
||||
│ └── Region[1] (else)
|
||||
│ └── Block[0]
|
||||
│ ├── pd_op.tanh(%1) → %4
|
||||
│ └── cf.yield(%4)
|
||||
└── builtin.set_parameter(%2, "out")
|
||||
```
|
||||
|
||||
嵌套规则:`Operation` → `Region` → `Block` → `Operation`,支持任意深度。Region 约束 Value 的作用域——内部 Region 可使用外部 Value(capture),但外部不能使用内部 Value。
|
||||
|
||||
## Alias/Inplace 机制
|
||||
|
||||
PIR 通过 **view 语义** 处理 Tensor 别名和原地操作:
|
||||
|
||||
- `v_tensor` 类型:表示"view tensor",与原始 Tensor 共享底层存储
|
||||
- `InplaceTrait`:标记原地操作的 Op(如 `pd_op.relu_`)
|
||||
- View Ops:`reshape`、`slice`、`transpose` 等产生 `v_tensor`,不拷贝数据
|
||||
|
||||
编译器在做 buffer 分配和内存优化时,需要追踪 view 关系以避免错误的内存复用。
|
||||
|
||||
## ProgramTranslator:旧 IR 到 PIR 的翻译
|
||||
|
||||
`ProgramTranslator` 负责将旧的 `ProgramDesc`(protobuf 描述的静态图)翻译为 `pir::Program`:
|
||||
|
||||
### 翻译流程
|
||||
|
||||
```
|
||||
ProgramDesc (旧 IR)
|
||||
│
|
||||
├─ 遍历每个 Block 中的 OpDesc
|
||||
│ │
|
||||
│ ├─ OpTranslator::Translate(op_desc)
|
||||
│ │ ├── 查找特化翻译器 (special handlers)
|
||||
│ │ │ 例如: while → WhileOp, conditional_block → IfOp
|
||||
│ │ └── 回退通用翻译器 (general handler)
|
||||
│ │ 根据 OpDesc 属性构造对应的 pir::Operation
|
||||
│ │
|
||||
│ └─ 维护 VarName → pir::Value 映射表
|
||||
│
|
||||
└─ 处理 sub_block 递归翻译(控制流 Op)
|
||||
```
|
||||
|
||||
### OpTranslator 策略
|
||||
|
||||
- **通用处理器**:按 OpDesc 的 inputs/outputs/attrs 一一映射,适用于大部分算术算子
|
||||
- **特化处理器**:处理语义差异较大的 Op,如:
|
||||
- `while` → `pd_op.while`(需要构造 Region 和 BlockArgument)
|
||||
- `fetch` → `builtin.set_parameter`
|
||||
- `feed` → `builtin.parameter`
|
||||
- `conditional_block` → `pd_op.if`
|
||||
|
||||
特化处理器通过注册表 `OpTranslator::special_handlers_` 管理,翻译时优先查找特化处理器,找不到则走通用路径。
|
||||
@@ -0,0 +1,159 @@
|
||||
# PaddleSOT(Symbolic Opcode Translator)设计详解
|
||||
|
||||
## 背景与动机
|
||||
|
||||
Paddle 的动转静(dy2st)最初基于 **AST Transformer**:将 Python 源码解析为 AST,通过语法树变换生成静态图代码。这种方式存在根本性局限:
|
||||
|
||||
1. **numpy/Tensor 互操作**:AST 层面无法区分 `x[0]` 是 numpy 索引还是 Tensor 索引
|
||||
2. **控制流边界**:嵌套函数、闭包、装饰器等场景难以正确转换
|
||||
3. **动态 shape**:`-1` 等动态形状信息在 AST 层面无法推断
|
||||
4. **第三方库**:调用 numpy、scipy 等库的代码无法直接转换
|
||||
|
||||
PaddleSOT 采用 **字节码级别** 的方案:不分析源码,而是在 Python VM 执行字节码时进行拦截和模拟,精确追踪每个操作的语义。
|
||||
|
||||
## PEP 523:自定义帧求值
|
||||
|
||||
Python 3.6+ 通过 PEP 523 提供了自定义帧求值的能力:
|
||||
|
||||
```c
|
||||
// Python 解释器状态中的钩子
|
||||
PyInterpreterState.eval_frame = custom_eval_frame_func;
|
||||
```
|
||||
|
||||
当 Python 执行每一帧(函数调用)时,会调用 `eval_frame` 函数。PaddleSOT 在此注入自己的逻辑:
|
||||
|
||||
1. **检查 Cache**:该帧是否已有编译结果?Guard 条件是否满足?
|
||||
2. **命中**:直接执行缓存的 StaticFunction
|
||||
3. **未命中**:启动 OpcodeExecutor 模拟执行
|
||||
|
||||
## OpcodeExecutor:字节码模拟执行
|
||||
|
||||
OpcodeExecutor 是 SOT 的核心,它 **模拟 Python VM 的字节码执行**,但不真正执行计算,而是:
|
||||
|
||||
### Variable 体系
|
||||
|
||||
将 Python 对象包装为 Variable,在模拟层面追踪:
|
||||
|
||||
| Variable 类型 | 包装对象 | 说明 |
|
||||
|--------------|---------|------|
|
||||
| `TensorVariable` | `paddle.Tensor` | 核心,记录到 FunctionGraph |
|
||||
| `ConstantVariable` | `int`, `float`, `str`, `None` | 常量直接内联 |
|
||||
| `ContainerVariable` | `list`, `dict`, `tuple` | 递归追踪容器中的元素 |
|
||||
| `CallableVariable` | 函数 / 方法 | 模拟函数调用行为 |
|
||||
| `ModuleVariable` | `nn.Layer` | 追踪模块的子层和参数 |
|
||||
|
||||
### Tracker 系统
|
||||
|
||||
每个 Variable 持有一个 **Tracker**,记录其来源(provenance)。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。从叶节点回溯到根节点,即可生成一条检查链,验证运行时输入是否满足编译假设。
|
||||
|
||||
### FunctionGraph 与 StatementIR
|
||||
|
||||
OpcodeExecutor 在模拟执行过程中,将 Tensor 相关操作记录到 **FunctionGraph** 中。FunctionGraph 最终输出 **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 | `self.linear(x)` |
|
||||
|
||||
StatementIR 最终被转换为 **StaticFunction**(静态图可执行单元),缓存供后续复用。
|
||||
|
||||
## OpcodeInlineExecutor:跨函数子图融合
|
||||
|
||||
当 OpcodeExecutor 遇到函数调用时,会创建 **OpcodeInlineExecutor** 进入被调用函数内部模拟执行。这使得 SOT 能够:
|
||||
|
||||
- 跨函数边界追踪 Tensor 操作
|
||||
- 将多个函数的操作融合到同一个子图中
|
||||
- 避免不必要的子图切分
|
||||
|
||||
## Sub-graph Fallback 场景
|
||||
|
||||
当 OpcodeExecutor 遇到无法模拟的操作时,会触发 **sub-graph fallback**:将当前已收集的子图编译执行,无法模拟的部分交给 Python 原生执行,随后开始新的子图收集。
|
||||
|
||||
| 缩写 | 全称 | 场景 |
|
||||
|------|------|------|
|
||||
| **DDCF** | Data-Dependent Control Flow | 控制流条件依赖 Tensor 值(如 `if x.sum() > 0`) |
|
||||
| **UNSPS** | Unsupported Simulation | 无法模拟的 Python 操作(如某些 C 扩展) |
|
||||
| **CDBL** | Custom Blacklist | 用户或框架标记的不转换函数 |
|
||||
| **UNIMP** | Unimplemented Opcode | 尚未实现模拟的字节码指令 |
|
||||
|
||||
Fallback 是 SOT 的安全兜底机制:**任何无法处理的情况都不会导致报错**,而是退化为部分子图编译 + 部分 Python 执行。
|
||||
|
||||
## Guard 与 Cache
|
||||
|
||||
### Guard 定义
|
||||
|
||||
Guard 是一个 `Callable[[FrameType], bool]`,判断当前帧的输入是否满足编译时的假设。
|
||||
|
||||
```python
|
||||
# 概念示例
|
||||
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
|
||||
```
|
||||
|
||||
### Guard 生成
|
||||
|
||||
每个 Variable 的 Tracker 链自动生成 sub-guard:
|
||||
|
||||
1. 回溯 Tracker DAG 到根节点(函数参数)
|
||||
2. 每一步生成一个检查条件(类型检查、shape 检查、值检查等)
|
||||
3. 所有 sub-guard 通过 **AND** 组合成完整 Guard
|
||||
|
||||
### Cache 机制
|
||||
|
||||
每个帧维护一个 `(Guard, StaticFunction)` 列表:
|
||||
|
||||
```
|
||||
frame_cache = [
|
||||
(guard_1, compiled_fn_1),
|
||||
(guard_2, compiled_fn_2),
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
执行时依次检查 Guard,首个满足的即命中缓存,直接执行对应的 StaticFunction。
|
||||
|
||||
## SideEffect 模块
|
||||
|
||||
Python 代码可能修改全局变量、修改可变对象(list.append 等)。SOT 的 **SideEffect** 模块负责:
|
||||
|
||||
1. **记录**:在模拟执行过程中,记录所有对全局变量和可变对象的修改
|
||||
2. **回放**:在生成的 StaticFunction 执行后,按记录顺序回放这些副作用
|
||||
|
||||
这确保了动转静的语义等价性:编译后的代码和原始 Python 代码产生相同的副作用。
|
||||
|
||||
## 使用方式
|
||||
|
||||
```python
|
||||
import paddle
|
||||
|
||||
@paddle.jit.to_static # 默认 full_graph=False,启用 SOT 模式
|
||||
def train_step(net, x, label):
|
||||
pred = net(x)
|
||||
loss = paddle.nn.functional.cross_entropy(pred, label)
|
||||
loss.backward()
|
||||
return loss
|
||||
|
||||
# full_graph=False(默认):SOT 模式(字节码级别转换 + 自动 fallback)
|
||||
# full_graph=True:传统 AST Transformer(要求整图可转)
|
||||
```
|
||||
|
||||
**关键路径**:
|
||||
- eval_frame 入口:`python/paddle/jit/sot/opcode_translator/eval_frame_callback.py`
|
||||
- OpcodeExecutor:`python/paddle/jit/sot/opcode_translator/executor/opcode_executor.py`
|
||||
- Variable 体系:`python/paddle/jit/sot/opcode_translator/executor/variables/`
|
||||
- Tracker:`python/paddle/jit/sot/opcode_translator/executor/tracker.py`
|
||||
- Guard:`python/paddle/jit/sot/opcode_translator/executor/guard.py`
|
||||
- FunctionGraph:`python/paddle/jit/sot/opcode_translator/executor/function_graph.py`
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
name: paddle-design-distributed
|
||||
description: "Use when working with Paddle's distributed training system: understanding parallelism strategies (DP, ZeRO, TP, PP, SP), semi-automatic parallel with ProcessMesh + shard_tensor, SPMD inference rules, pipeline scheduling, or auto_parallel Engine."
|
||||
---
|
||||
|
||||
# Paddle 分布式训练
|
||||
|
||||
## 分布式范式速查
|
||||
|
||||
| 范式 | 核心思想 | 通信原语 |
|
||||
|------|---------|---------|
|
||||
| **Data Parallel** | 复制模型,切分数据,AllReduce 梯度 | AllReduce |
|
||||
| **Group Sharded (ZeRO)** | Stage1 切 optimizer / Stage2 + 切 grad / Stage3 + 切 weight | Broadcast, ReduceScatter, AllGather |
|
||||
| **Model Parallel (Tensor)** | Column Parallel 切权重列 / Row Parallel 切权重行 | AllReduce / AllGather |
|
||||
| **Pipeline Parallel** | F-then-B / 1F1B 交错前反向 | Send / Recv (P2P) |
|
||||
| **Sequence Parallel** | 沿 sequence 维度切分 LayerNorm/Dropout | AllGather / ReduceScatter |
|
||||
|
||||
## 三种编程范式
|
||||
|
||||
| 范式 | 入口 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| **手动并行** | `fleet.meta_parallel` | 灵活但代码量大,适合深度定制 |
|
||||
| **半自动动态图** | `ProcessMesh` + `shard_tensor` | 用户标注切分方式,框架自动推导通信,兼具易用性和灵活性 |
|
||||
| **半自动静态图** | `auto_parallel.Engine` | 基于 PIR 做全局优化,追求极致性能 |
|
||||
|
||||
### 半自动动态图示例
|
||||
|
||||
```python
|
||||
import paddle.distributed as dist
|
||||
mesh = dist.ProcessMesh([0, 1, 2, 3], dim_names=["x"])
|
||||
x = dist.shard_tensor(x, mesh, [dist.Shard(0)]) # 沿 dim 0 切分
|
||||
```
|
||||
|
||||
## SPMD 推导规则
|
||||
|
||||
半自动并行的核心:用户只标注部分 Tensor 的切分方式(Placement),框架自动推导每个算子的输入输出应如何切分,必要时插入通信算子。
|
||||
|
||||
### 基于 Einsum 的计算类规则
|
||||
|
||||
1. **推导 Einsum 表示**:`matmul(X[M,K], Y[K,N]) -> Z[M,N]` → `mk,kn->mn`
|
||||
2. **合并输入 dims_mapping**:同一 Einsum 轴的切分必须一致,冲突时 reshard
|
||||
3. **推导输出 dims_mapping**:根据合并后的轴切分信息映射到输出
|
||||
|
||||
### 形状变换类规则
|
||||
|
||||
使用 DimTrans 系统描述维度映射:InputDim / Flatten / Split / Singleton。
|
||||
|
||||
## Pipeline 调度
|
||||
|
||||
| 调度策略 | 特点 |
|
||||
|---------|------|
|
||||
| **F-then-B** | 所有前向完毕再反向,简单但显存占用大 |
|
||||
| **1F1B** | warm-up → steady(前反交替)→ cool-down,显存减少约 37.5% |
|
||||
|
||||
## 什么场景看什么文件
|
||||
|
||||
| 场景 | 参考文档 |
|
||||
|------|---------|
|
||||
| 分布式策略原理(DP/Sharded/MP/PP/SP) | [references/distributed-primer.md](references/distributed-primer.md) |
|
||||
| SPMD 推导规则与 Pipeline 调度 | [references/spmd-rules.md](references/spmd-rules.md) |
|
||||
|
||||
## 源码入口
|
||||
|
||||
| 模块 | 路径 |
|
||||
|------|------|
|
||||
| 分布式总目录 | `python/paddle/distributed/` |
|
||||
| ProcessMesh / shard_tensor API | `python/paddle/distributed/auto_parallel/` |
|
||||
| auto_parallel Engine | `python/paddle/distributed/auto_parallel/high_level_api.py` |
|
||||
| fully_shard(ZeRO-like) | `python/paddle/distributed/auto_parallel/fully_shard.py` |
|
||||
| SPMD 推导规则 C++ | `paddle/phi/infermeta/spmd_rules/` |
|
||||
| SPMD 规则注册 | `paddle/phi/infermeta/spmd_rules/rules.h` |
|
||||
| Pipeline 调度 Pass | `python/paddle/distributed/passes/pipeline_scheduler_pass/` |
|
||||
| 分布式策略配置 | `python/paddle/distributed/auto_parallel/strategy.py` |
|
||||
| SPMD 规则测试 | `test/auto_parallel/spmd_rules/` |
|
||||
@@ -0,0 +1,150 @@
|
||||
# 分布式训练策略详解
|
||||
|
||||
## 核心原则:等价性
|
||||
|
||||
分布式训练的基本目标:**多卡训练的数学结果与单卡训练完全等价**。所有并行策略的设计都围绕这一等价性展开——通过切分计算和通信来还原单卡的语义。
|
||||
|
||||
## 集合通信原语
|
||||
|
||||
分布式训练依赖 NCCL 提供的集合通信原语:
|
||||
|
||||
| 原语 | 语义 | 典型用途 |
|
||||
|------|------|---------|
|
||||
| **Broadcast** | 一个进程的数据广播给所有进程 | 参数初始化同步 |
|
||||
| **AllGather** | 每个进程收集所有进程的数据 | ZeRO Stage3 前向前收集完整权重 |
|
||||
| **AllReduce** | 所有进程归约后广播结果 | DP 梯度同步 |
|
||||
| **Reduce** | 所有进程归约到一个进程 | 聚合 loss |
|
||||
| **ReduceScatter** | 归约后将结果切分分发 | ZeRO Stage2 梯度同步 |
|
||||
|
||||
**关键恒等式**:`AllReduce = ReduceScatter + AllGather`。理解这一点对分析 ZeRO 和 Sequence Parallel 的通信量至关重要。
|
||||
|
||||
## 三种编程范式
|
||||
|
||||
### 1. 手动并行 (`fleet.meta_parallel`)
|
||||
|
||||
开发者显式指定切分方式,手动插入通信算子。灵活但代码量大、易出错。
|
||||
|
||||
```python
|
||||
import paddle.distributed.fleet as fleet
|
||||
fleet.init(is_collective=True)
|
||||
strategy = fleet.DistributedStrategy()
|
||||
strategy.tensor_parallel = True
|
||||
strategy.tensor_parallel_configs = {"tensor_parallel_degree": 2}
|
||||
```
|
||||
|
||||
### 2. 半自动动态图 (`ProcessMesh` + `shard_tensor`)
|
||||
|
||||
用户标注 Tensor 的切分方式,框架自动推导通信。兼具易用性和灵活性。
|
||||
|
||||
```python
|
||||
import paddle.distributed as dist
|
||||
mesh = dist.ProcessMesh([0, 1, 2, 3], dim_names=["x"])
|
||||
x = dist.shard_tensor(x, mesh, [dist.Shard(0)]) # 沿 dim 0 切分
|
||||
```
|
||||
|
||||
### 3. 半自动静态图 (`auto_parallel.Engine`)
|
||||
|
||||
基于静态图 IR,框架做全局优化(算子切分、通信插入、调度优化)。适合追求极致性能的场景。
|
||||
|
||||
```python
|
||||
from paddle.distributed.auto_parallel import Engine
|
||||
engine = Engine(model, loss, optimizer, strategy=strategy)
|
||||
engine.fit(train_dataset)
|
||||
```
|
||||
|
||||
## Data Parallel(数据并行)
|
||||
|
||||
**思路**:每张卡持有完整模型副本,训练数据按 batch 维度切分。
|
||||
|
||||
**流程**:
|
||||
1. 每张卡用不同的 mini-batch 做前向 + 反向
|
||||
2. 梯度通过 **AllReduce** 同步(求平均)
|
||||
3. 每张卡用相同的平均梯度更新参数
|
||||
|
||||
**通信量**:每次迭代 AllReduce 全部梯度,通信量 = 2 * model_size(Ring AllReduce 下)。
|
||||
|
||||
**局限**:模型必须完整放入单卡显存。
|
||||
|
||||
## Group Sharded(ZeRO 系列)
|
||||
|
||||
Group Sharded 是 ZeRO(Zero Redundancy Optimizer)在 Paddle 中的实现,渐进式减少显存冗余。
|
||||
|
||||
### Stage 1:切分优化器状态
|
||||
|
||||
- 每张卡只维护 1/N 的优化器状态(如 Adam 的 m, v)
|
||||
- 梯度仍然 AllReduce
|
||||
- 参数更新后 **Broadcast** 更新的参数分片
|
||||
|
||||
**显存节省**:优化器状态占总显存的大头(Adam 为参数量的 2 倍),Stage 1 将其降为 1/N。
|
||||
|
||||
### Stage 2:+ 切分梯度
|
||||
|
||||
- 梯度不再 AllReduce,而是 **ReduceScatter**(每张卡只保留自己负责的那部分梯度)
|
||||
- 进一步减少梯度的显存占用
|
||||
|
||||
### Stage 3:+ 切分权重
|
||||
|
||||
- 参数也按卡切分,每张卡只存 1/N 的参数
|
||||
- 前向/反向计算前通过 **AllGather** 收集完整参数
|
||||
- 计算完成后释放非本卡参数
|
||||
|
||||
**额外通信**:相比 DP,Stage 3 增加了前向 + 反向各一次 AllGather,通信量约增加 50%,但显存占用可降至接近 1/N。
|
||||
|
||||
## Model Parallel(模型并行 / 张量并行)
|
||||
|
||||
将单个算子的权重矩阵切分到多卡。以线性层 `Y = XW` 为例:
|
||||
|
||||
### Column Parallel(列切分)
|
||||
|
||||
将权重 W 按列切分为 [W1, W2],分布在 2 张卡上:
|
||||
- 卡 0 计算 Y1 = X @ W1
|
||||
- 卡 1 计算 Y2 = X @ W2
|
||||
- 输出 Y = [Y1, Y2](无需通信,或后续做 AllGather)
|
||||
|
||||
### Row Parallel(行切分)
|
||||
|
||||
将权重 W 按行切分,输入 X 也相应切分:
|
||||
- 卡 0 计算 Y1 = X1 @ W1
|
||||
- 卡 1 计算 Y2 = X2 @ W2
|
||||
- 输出 Y = Y1 + Y2(需要 **AllReduce**)
|
||||
|
||||
**Transformer 中的典型组合**:MLP 的第一个线性层用 Column Parallel,第二个用 Row Parallel,首尾各一次 AllReduce(或 f/g 共轭算子对消前向/反向各一次 AllReduce)。
|
||||
|
||||
## Pipeline Parallel(流水线并行)
|
||||
|
||||
将模型按层分为多个 stage,分配到不同卡上。
|
||||
|
||||
### Naive 方式
|
||||
|
||||
一次只有一张卡在计算,其余空闲。GPU 利用率 = 1/N,不实用。
|
||||
|
||||
### F-then-B(先前向后反向)
|
||||
|
||||
将 mini-batch 拆分为多个 micro-batch:
|
||||
1. 先依次执行所有 micro-batch 的前向
|
||||
2. 再依次执行所有 micro-batch 的反向
|
||||
|
||||
**bubble 比例**:(num_stages - 1) / num_microbatches。需要同时保存所有 micro-batch 的激活值,**显存占用大**。
|
||||
|
||||
### 1F1B(One Forward One Backward)
|
||||
|
||||
交错执行前向和反向:
|
||||
1. warm-up 阶段:依次填充流水线(只做前向)
|
||||
2. steady 阶段:每做一次前向,紧接着做一次反向
|
||||
3. cool-down 阶段:依次排空流水线(只做反向)
|
||||
|
||||
**优势**:稳态阶段只需保存 num_stages 个 micro-batch 的激活值,相比 F-then-B **显存减少约 37.5%**(4 stages 时)。bubble 比例与 F-then-B 相同。
|
||||
|
||||
## Sequence Parallel(序列并行)
|
||||
|
||||
Tensor Parallel 的扩展,专门针对 Transformer 架构中 **不在 Tensor Parallel 范围内** 的算子(LayerNorm、Dropout)。
|
||||
|
||||
**思路**:
|
||||
- Tensor Parallel 区域:权重按列/行切分
|
||||
- 非 Tensor Parallel 区域(LayerNorm, Dropout):沿 **sequence 维度** 切分激活值
|
||||
|
||||
**通信转换**:
|
||||
- 原 Tensor Parallel 需要 AllReduce → 替换为 ReduceScatter(进入 SP 区域)+ AllGather(离开 SP 区域)
|
||||
- 通信量不变(AllReduce = ReduceScatter + AllGather),但 SP 区域的激活值显存降为 1/N
|
||||
|
||||
**收益**:在不增加通信量的前提下,减少了 LayerNorm/Dropout 区域的激活值显存占用。
|
||||
@@ -0,0 +1,134 @@
|
||||
# SPMD 推导规则与 Pipeline 调度
|
||||
|
||||
## 概述
|
||||
|
||||
半自动并行的核心问题:用户只标注部分 Tensor 的切分方式(Placement),框架需要 **自动推导** 每个算子的输入输出应如何切分,并在必要时插入通信算子。这套推导机制称为 SPMD(Single Program Multiple Data)Inference Rules。
|
||||
|
||||
## 基本概念
|
||||
|
||||
### ProcessMesh
|
||||
|
||||
进程拓扑,描述参与并行计算的进程组织方式:
|
||||
|
||||
```python
|
||||
# 4 个进程组成一维 mesh
|
||||
mesh = dist.ProcessMesh([0, 1, 2, 3], dim_names=["x"])
|
||||
# 4 个进程组成 2x2 mesh
|
||||
mesh = dist.ProcessMesh([[0, 1], [2, 3]], dim_names=["x", "y"])
|
||||
```
|
||||
|
||||
### dims_mapping
|
||||
|
||||
描述 Tensor 各维度与 ProcessMesh 维度的对应关系:
|
||||
|
||||
- `dims_mapping[i] = j` 表示 Tensor 的第 i 维沿 ProcessMesh 的第 j 维切分
|
||||
- `dims_mapping[i] = -1` 表示 Tensor 的第 i 维 **不切分(Replicated)**
|
||||
|
||||
示例:shape=[B, S, H] 的 Tensor,dims_mapping=[0, -1, 1] 表示 batch 维沿 mesh 的 x 轴切分,hidden 维沿 mesh 的 y 轴切分,sequence 维不切分。
|
||||
|
||||
## 计算类规则(Matmul, Elementwise 等)
|
||||
|
||||
基于 **Einsum Notation** 推导,分三步:
|
||||
|
||||
### 步骤 1:推导 Einsum 表示
|
||||
|
||||
根据算子的计算语义写出 Einsum notation。例如:
|
||||
|
||||
- `matmul(X[M,K], Y[K,N]) -> Z[M,N]`:Einsum = `mk,kn->mn`
|
||||
- `elementwise_add(X[M,N], Y[M,N]) -> Z[M,N]`:Einsum = `mn,mn->mn`
|
||||
- `matmul(X[B,M,K], Y[B,K,N]) -> Z[B,M,N]`:Einsum = `bmk,bkn->bmn`
|
||||
|
||||
### 步骤 2:合并输入 dims_mapping
|
||||
|
||||
调用 `ShardingMergeForTensors()` 将所有输入 Tensor 的 dims_mapping 按 Einsum 轴合并:
|
||||
|
||||
- 同一 Einsum 轴对应的 dims_mapping 值必须一致(或其中一个为 -1)
|
||||
- 冲突时:若两个输入对同一轴有不同的切分维度,需要 **reshard**(插入通信算子使切分一致)
|
||||
|
||||
### 步骤 3:推导输出 dims_mapping
|
||||
|
||||
调用 `GetDimsMappingForAxes()` 根据合并后的轴切分信息,映射到输出 Tensor 的各维度。
|
||||
|
||||
**示例**:`matmul(X[M,K], Y[K,N])` 在 2D mesh 上
|
||||
|
||||
- X 的 dims_mapping = [0, -1](M 轴沿 mesh dim 0 切分)
|
||||
- Y 的 dims_mapping = [-1, 1](N 轴沿 mesh dim 1 切分)
|
||||
- 合并后:m→0, k→-1, n→1
|
||||
- 输出 Z 的 dims_mapping = [0, 1](M 沿 mesh dim 0,N 沿 mesh dim 1)
|
||||
|
||||
## 形状变换类规则(Reshape, Squeeze 等)
|
||||
|
||||
形状变换不涉及计算,但输入输出的 shape 不同,需要用 **DimTrans** 系统描述维度映射关系。
|
||||
|
||||
### DimTrans 类型
|
||||
|
||||
| 类型 | 含义 | 示例 |
|
||||
|------|------|------|
|
||||
| **InputDim(i)** | 输出维度直接对应输入的第 i 维 | reshape [6,12] → [6,12] |
|
||||
| **Flatten(dims)** | 输出维度由输入的多个维度合并而来 | reshape [2,3,4] → [6,4]:dim0 = Flatten([InputDim(0), InputDim(1)]) |
|
||||
| **Split(input_dim, sizes, idx)** | 输出维度由输入某维度拆分而来 | reshape [6,4] → [2,3,4]:dim0 = Split(InputDim(0), [2,3], 0) |
|
||||
| **Singleton** | 输出维度大小为 1,不对应任何输入维度 | unsqueeze |
|
||||
|
||||
**切分规则**:Flatten 时,只有最内层维度可以保留切分;Split 时,切分维度可以映射到对应的拆分片段。
|
||||
|
||||
## 开发与注册
|
||||
|
||||
### 接口文件
|
||||
|
||||
每个算子的 SPMD 规则实现在:
|
||||
```
|
||||
paddle/phi/infermeta/spmd_rules/{op_name}.h
|
||||
paddle/phi/infermeta/spmd_rules/{op_name}.cc
|
||||
```
|
||||
|
||||
需要实现两个函数:
|
||||
- `SpmdInfo {Op}InferSpmd(const DistMetaTensor& x, ...)`:前向推导
|
||||
- `SpmdInfo {Op}InferSpmdReverse(const DistMetaTensor& x, ..., const DistMetaTensor& out)`:反向推导(从输出推导输入)
|
||||
|
||||
### 注册
|
||||
|
||||
在 `paddle/phi/infermeta/spmd_rules/rules.h` 中使用宏注册:
|
||||
|
||||
```cpp
|
||||
PD_REGISTER_SPMD_RULE(
|
||||
matmul,
|
||||
PD_INFER_SPMD(phi::distributed::MatmulInferSpmd),
|
||||
PD_INFER_SPMD(phi::distributed::MatmulInferSpmdReverse));
|
||||
```
|
||||
|
||||
### 测试
|
||||
|
||||
测试位于 `test/auto_parallel/spmd_rules/`,使用 Python 调用验证推导结果。
|
||||
|
||||
## Pipeline 调度
|
||||
|
||||
Pipeline Parallel 将模型按层切分为多个 stage,每个 stage 分配到不同设备。调度策略决定 micro-batch 的执行顺序。
|
||||
|
||||
### F-then-B 调度
|
||||
|
||||
Job list 形如:`[F0, F1, F2, F3, B3, B2, B1, B0]`
|
||||
|
||||
所有前向执行完毕后再执行反向。简单但显存占用大(需保存所有 micro-batch 的激活值)。
|
||||
|
||||
### 1F1B 调度
|
||||
|
||||
Job list 形如:`[F0, F1, F2, F3, B0, F4, B1, F5, B2, ..., B_last]`
|
||||
|
||||
warm-up 阶段填充流水线,steady 阶段前向/反向交替执行。
|
||||
|
||||
### 程序切分
|
||||
|
||||
Pipeline Parallel 需要将完整程序切分为子程序:
|
||||
|
||||
| 子程序 | 内容 |
|
||||
|--------|------|
|
||||
| **LR** | 学习率调度 |
|
||||
| **FORWARD** | 前向计算(按 stage 切分) |
|
||||
| **BACKWARD** | 反向计算(按 stage 切分) |
|
||||
| **OPT** | 参数更新(优化器 step) |
|
||||
|
||||
调度器根据 job list 按顺序执行子程序,通过 Send/Recv 实现 stage 间的激活值和梯度传递。
|
||||
|
||||
相关代码路径:
|
||||
- 调度 pass:`python/paddle/distributed/passes/pipeline_scheduler_pass/`
|
||||
- Job 定义:`python/paddle/distributed/auto_parallel/strategy.py`
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
name: paddle-eager-graph
|
||||
description: "Use when navigating Paddle eager-mode (dynamic graph) source code, tracing forward/backward execution, debugging autograd issues, understanding PyLayer, or investigating complex-valued gradient computation. Covers Python API to C++ kernel call chain, backward graph topology sort, and inplace version tracking."
|
||||
---
|
||||
|
||||
# Paddle 动态图(Eager Mode)导航索引
|
||||
|
||||
Paddle 动态图**边执行边建图**:前向执行时构建反向图,调用 `backward()` 时按拓扑序执行反向图。
|
||||
|
||||
## 前向调用链路
|
||||
|
||||
```
|
||||
Python paddle.add(x, y)
|
||||
│
|
||||
▼
|
||||
① ops_api.cc ─ Python-C 映射,GetTensorFromArgs 提取 Tensor
|
||||
▼
|
||||
② eager_op_function.cc ─ 参数解析 / Dist Tensor / 释放 GIL / backend 选择
|
||||
▼
|
||||
③ dygraph_functions.cc ─ AMP / Type Promotion / 创建 GradNode / 构建反向图
|
||||
▼
|
||||
④ api.cc ─ KernelKey 构造 / Kernel 选择 / PrepareData / InferMeta
|
||||
▼
|
||||
⑤ PHI Kernel 执行
|
||||
```
|
||||
|
||||
## 关键文件表
|
||||
|
||||
| 层级 | 代码路径 | 代码生成器 |
|
||||
|------|---------|-----------|
|
||||
| ① Python-C 映射 | `paddle/fluid/pybind/ops_api.cc` | `ops_api_gen.py` |
|
||||
| ② 动态图 C++ 接口 | `paddle/fluid/pybind/eager_op_function.cc` | `python_c_gen.py` |
|
||||
| ③ 自动微分函数 | `paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.cc` | `eager_gen.py` |
|
||||
| ④ PHI 算子库接口 | `paddle/phi/api/lib/api.cc` | `api_gen.py` |
|
||||
|
||||
## 反向关键数据结构
|
||||
|
||||
| 数据结构 | 一句话描述 |
|
||||
|---------|-----------|
|
||||
| **AutogradMeta** | Tensor 持有的反向元信息:梯度、来源 GradNode、slot/rank 位置 |
|
||||
| **GradNodeBase** | 反向节点基类,纯虚 `operator()` 执行反向计算 |
|
||||
| **GradSlotMeta** | 描述 GradNode 某个 slot 的 meta 信息与出边 Edge |
|
||||
| **Edge** | 指向后继 GradNode 的边,含 `in_slot_id_` 和 `in_rank_` |
|
||||
| **TensorWrapper** | GradNode 中保存前向 Tensor 的包装器,含 inplace 版本快照 |
|
||||
| **GradTensorHolder** | 反向执行期间临时存放与聚合梯度的二维 buffer |
|
||||
|
||||
## 调试场景速查
|
||||
|
||||
| 调试场景 | 阅读哪个参考文档 |
|
||||
|---------|----------------|
|
||||
| 前向调用链路 / Kernel 选择问题 | [forward-call-chain.md](references/forward-call-chain.md) |
|
||||
| 反向梯度不正确 / 拓扑排序问题 | [backward-execution.md](references/backward-execution.md) |
|
||||
| 数据结构成员 / 内存泄漏排查 | [autograd-data-structs.md](references/autograd-data-structs.md) |
|
||||
| 自定义反向 PyLayer | [pylayer.md](references/pylayer.md) |
|
||||
| 复数梯度 / Wirtinger 导数 | [complex-autograd.md](references/complex-autograd.md) |
|
||||
| Inplace 操作 / 版本追踪 | [inplace.md](references/inplace.md) |
|
||||
|
||||
## 社区资料(L3 层)
|
||||
|
||||
- [PFCC 动态图源码阅读](https://github.com/PaddlePaddle/community/tree/master/pfcc/paddle-code-reading/Dygraph)
|
||||
@@ -0,0 +1,186 @@
|
||||
# 自动微分数据结构详解
|
||||
|
||||
本文档完整列出 Paddle 动态图自动微分系统中所有核心数据结构的成员和作用,并描述它们之间的数据流关系。
|
||||
|
||||
## 数据流总览
|
||||
|
||||
```
|
||||
phi::Tensor
|
||||
└─ autograd_meta_ (AutogradMeta)
|
||||
├─ grad_ ← 存放该 Tensor 的梯度
|
||||
└─ grad_node_ → GradNodeBase (如 AddGradNode)
|
||||
├─ bwd_in_meta_ [vector<GradSlotMeta>] ← 输入 slot 元信息
|
||||
├─ bwd_out_meta_ [vector<GradSlotMeta>] ← 输出 slot 元信息
|
||||
│ └─ adj_edge_ (Edge)
|
||||
│ └─ grad_node_ → 后继 GradNodeBase
|
||||
├─ TensorWrapper (保存前向 Tensor)
|
||||
└─ operator() ← 执行反向计算
|
||||
|
||||
执行阶段:
|
||||
GradTensorHolder.buffer_[slot][rank] → 聚合梯度 → 传入 operator()
|
||||
```
|
||||
|
||||
## phi::Tensor
|
||||
|
||||
**文件**:`paddle/phi/api/include/tensor.h`
|
||||
|
||||
Paddle 的统一 Tensor 接口,所有 Python 端 `paddle.Tensor` 底层对应一个 `phi::Tensor`。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `impl_` | `std::shared_ptr<phi::TensorBase>` | 底层存储实现(`DenseTensor`、`SparseCsrTensor` 等) |
|
||||
| `autograd_meta_` | `std::unique_ptr<AbstractAutogradMeta>` | 自动微分元信息,动态图模式下为 `AutogradMeta` |
|
||||
| `name_` | `std::string` | Tensor 名称,调试用 |
|
||||
|
||||
**关键方法**:
|
||||
- `set_autograd_meta()` / `mutable_autograd_meta()` — 设置/获取自动微分信息
|
||||
- `defined()` — 检查 `impl_` 是否有效
|
||||
- `initialized()` — 检查底层存储是否已分配
|
||||
|
||||
## AbstractAutogradMeta
|
||||
|
||||
**文件**:`paddle/phi/api/include/tensor.h`
|
||||
|
||||
纯虚基类,仅定义接口,使 `phi::Tensor` 不依赖具体的自动微分实现。
|
||||
|
||||
```cpp
|
||||
class AbstractAutogradMeta {
|
||||
public:
|
||||
virtual ~AbstractAutogradMeta() = default;
|
||||
};
|
||||
```
|
||||
|
||||
## AutogradMeta
|
||||
|
||||
**文件**:`paddle/fluid/eager/autograd_meta.h`
|
||||
|
||||
继承自 `AbstractAutogradMeta`,包含 Tensor 参与自动微分所需的全部信息。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `grad_` | `paddle::Tensor` | 该 Tensor 的梯度,`backward()` 后通过 `.grad` 访问 |
|
||||
| `grad_node_` | `std::shared_ptr<GradNodeBase>` | 产生该 Tensor 的反向节点 |
|
||||
| `out_slot_id_` | `size_t` | 该 Tensor 在 `grad_node_` 输出中的 slot 索引 |
|
||||
| `out_rank_` | `size_t` | 该 Tensor 在 slot 内的 rank 索引 |
|
||||
| `stop_gradient_` | `bool` | 为 true 时不参与梯度计算(对应 Python `Tensor.stop_gradient`) |
|
||||
| `persistable_` | `bool` | 是否为持久化 Tensor(模型参数等) |
|
||||
| `retain_grads_` | `bool` | 为 true 时即使是非叶节点也保留梯度 |
|
||||
|
||||
**slot 和 rank 的含义**:一个算子可能有多个输出(slot),每个输出可能是 Tensor 列表(rank 区分列表内位置)。`out_slot_id_` 和 `out_rank_` 记录该 Tensor 是 GradNode 第几个输出 slot 的第几个 Tensor。
|
||||
|
||||
## GradNodeBase
|
||||
|
||||
**文件**:`paddle/fluid/eager/grad_node_info.h`
|
||||
|
||||
反向图中的节点基类,每个前向算子对应一个具体的 `GradNode` 子类(如 `AddGradNode`、`MatmulGradNode`)。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `bwd_in_meta_` | `std::vector<std::vector<GradSlotMeta>>` | 反向输入的 meta 信息(对应前向输出) |
|
||||
| `bwd_out_meta_` | `std::vector<std::vector<GradSlotMeta>>` | 反向输出的 meta 信息(对应前向输入),含 adj_edge_ |
|
||||
| `gradient_hooks_` | `std::map<int, GradientHookFunc>` | 注册的梯度 hook 函数 |
|
||||
| `default_attr_map_` | `paddle::framework::AttributeMap` | 前向算子的属性(如 axis、keepdim 等) |
|
||||
|
||||
**关键虚方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `operator()(vector<vector<Tensor>>&)` | **纯虚**。执行反向计算,输入为上游梯度,输出为下游梯度 |
|
||||
| `ClearTensorWrappers()` | 清理保存的前向 Tensor(`retain_graph=false` 时调用) |
|
||||
| `Copy()` | 复制节点(`GeneralGrad` 中使用) |
|
||||
|
||||
**注意 bwd_in/out 的命名方向**:
|
||||
- `bwd_in_meta_` 对应反向计算的**输入**(即前向算子的**输出**的梯度)
|
||||
- `bwd_out_meta_` 对应反向计算的**输出**(即前向算子的**输入**的梯度),其中的 `adj_edge_` 连接后继节点
|
||||
|
||||
## GradSlotMeta
|
||||
|
||||
**文件**:`paddle/fluid/eager/grad_node_info.h`
|
||||
|
||||
描述 GradNode 某个 slot 的元信息,同时通过 `adj_edge_` 建立反向图的边。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `stop_gradient_` | `bool` | 该 slot 是否停止梯度 |
|
||||
| `place_` | `phi::Place` | Tensor 所在设备 |
|
||||
| `meta_` | `phi::DenseTensorMeta` | 前向 Tensor 的 shape/dtype/layout 等 meta |
|
||||
| `adj_edge_` | `Edge` | 连接到后继 GradNode 的边 |
|
||||
|
||||
## Edge
|
||||
|
||||
**文件**:`paddle/fluid/eager/grad_node_info.h`
|
||||
|
||||
反向图中的有向边,从当前 GradNode 的某个输出 slot 指向后继 GradNode 的某个输入 slot。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `grad_node_` | `std::shared_ptr<GradNodeBase>` | 后继 GradNode |
|
||||
| `in_slot_id_` | `size_t` | 在后继 GradNode 中对应的输入 slot 索引 |
|
||||
| `in_rank_` | `size_t` | 在该 slot 内的 rank 索引 |
|
||||
|
||||
**Edge 的方向理解**:反向图中,梯度从 loss 流向叶节点。Edge 描述的是梯度的流向——从当前节点的输出连接到下一个节点的输入。
|
||||
|
||||
## TensorWrapper
|
||||
|
||||
**文件**:`paddle/fluid/eager/tensor_wrapper.h`
|
||||
|
||||
GradNode 中用于保存前向 Tensor 的包装器。反向计算通常需要前向的输入或输出值(如 `y = relu(x)` 的反向需要 `x`)。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `intermediate_tensor_` | `paddle::Tensor` | 保存的前向 Tensor(拼写沿用代码中的 intermediate) |
|
||||
| `no_need_buffer_` | `bool` | 为 true 时只保存 meta 信息,不保存数据(节省内存) |
|
||||
| `weak_grad_node_` | `std::weak_ptr<GradNodeBase>` | 弱引用前向 Tensor 的 GradNode,**防止循环引用** |
|
||||
| `inplace_version_snapshot_` | `uint32_t` | 保存时的 inplace 版本号,`recover()` 时校验是否被修改 |
|
||||
| `packed_value_` | `std::shared_ptr<void>` | pack hook 打包后的值(用于内存优化,如 offload 到 CPU) |
|
||||
| `unpack_hook_` | `std::shared_ptr<UnpackHookBase>` | 与 `packed_value_` 配合的 unpack 回调 |
|
||||
|
||||
**关键方法**:
|
||||
- `recover()` — 从 `intermediate_tensor_` 恢复出 `paddle::Tensor`,同时检查 inplace 版本一致性
|
||||
- 若 `packed_value_` 非空,通过 `unpack_hook_` 解包而非直接使用 `intermediate_tensor_`
|
||||
|
||||
**weak_ptr 防循环引用**:若 TensorWrapper 直接持有 `shared_ptr<GradNodeBase>`,会形成 `GradNode → TensorWrapper → Tensor → AutogradMeta → GradNode` 的循环引用,导致内存泄漏。使用 `weak_ptr` 打破循环。
|
||||
|
||||
## GradTensorHolder
|
||||
|
||||
**文件**:`paddle/fluid/eager/grad_tensor_holder.h`
|
||||
|
||||
反向执行阶段,每个待执行的 GradNode 都有一个对应的 `GradTensorHolder`,用于接收和聚合来自多条路径的上游梯度。
|
||||
|
||||
| 成员 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `buffer_` | `std::vector<std::vector<paddle::Tensor>>` | 二维 Tensor 容器,`buffer_[slot_id][rank]` |
|
||||
|
||||
**关键方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| `add(slot, rank, tensor)` | 梯度聚合:若 `buffer_[slot][rank]` 为空则赋值,否则执行 Tensor 加法累加 |
|
||||
| `Buffers()` | 返回 `buffer_` 引用,传入 `GradNode::operator()` |
|
||||
| `SetBufferSlotRankZeros(slot, rank)` | 将指定位置设为零 Tensor |
|
||||
|
||||
**聚合场景**:当一个 Tensor 被多个算子使用时(如 `y = x + x`),反向时两条路径的梯度需要累加到同一个 `GradTensorHolder` 中。
|
||||
|
||||
## 数据结构间的关系图
|
||||
|
||||
```
|
||||
phi::Tensor ──owns──→ AutogradMeta
|
||||
│
|
||||
┌────┘ grad_node_ (shared_ptr)
|
||||
▼
|
||||
GradNodeBase (如 AddGradNode)
|
||||
│
|
||||
┌─────────┼──────────┐
|
||||
▼ ▼ ▼
|
||||
bwd_in_meta_ bwd_out_meta_ TensorWrapper
|
||||
(输入meta) (输出meta) │
|
||||
│ └─ intermediate_tensor_
|
||||
▼ └─ weak_grad_node_ ──weak──→ GradNodeBase
|
||||
GradSlotMeta
|
||||
│
|
||||
└─ adj_edge_ (Edge)
|
||||
│
|
||||
└─ grad_node_ ──shared_ptr──→ 后继 GradNodeBase
|
||||
```
|
||||
|
||||
构建阶段创建上述结构,执行阶段 `GradTensorHolder` 沿边传递和聚合梯度。
|
||||
@@ -0,0 +1,189 @@
|
||||
# 反向执行流程详解
|
||||
|
||||
本文档详述 Paddle 动态图中 `loss.backward()` 的完整反向执行流程,包括准备阶段、BFS 拓扑排序执行阶段,以及 `paddle.grad()` 使用的 `GeneralGrad` 机制。
|
||||
|
||||
## 入口调用链
|
||||
|
||||
```
|
||||
Python: loss.backward()
|
||||
→ C++: Backward() # paddle/fluid/eager/backward.cc
|
||||
→ RunBackward(tensors, grad_tensors, retain_graph)
|
||||
```
|
||||
|
||||
`Backward()` 是对 `RunBackward()` 的简单封装,负责处理默认梯度(若未指定 `grad_tensors`,则初始化为全 1 Tensor)。
|
||||
|
||||
## 准备阶段
|
||||
|
||||
### 1. 提取起始 GradNode
|
||||
|
||||
```cpp
|
||||
// 从 loss tensor 中取出 AutogradMeta
|
||||
auto* autograd_meta = EagerUtils::nullable_autograd_meta(loss);
|
||||
// 获取起始 GradNode
|
||||
auto start_node = autograd_meta->GradNode();
|
||||
```
|
||||
|
||||
每个需要求梯度的 Tensor 的 `AutogradMeta` 中都持有一个 `grad_node_` 指针,指向产生该 Tensor 的反向节点。`loss` 的 `grad_node_` 就是反向图的起始节点。
|
||||
|
||||
### 2. 初始化 GradTensorHolder
|
||||
|
||||
```cpp
|
||||
// 为起始节点创建 GradTensorHolder
|
||||
node_input_buffers_dict[start_node.get()] =
|
||||
std::make_unique<GradTensorHolder>(start_node->InputMeta());
|
||||
|
||||
// 将初始梯度(默认 1.0)写入 buffer
|
||||
node_input_buffers_dict[start_node.get()]->add(
|
||||
slot_id, rank, grad_tensor);
|
||||
```
|
||||
|
||||
`GradTensorHolder` 的 `buffer_` 是一个二维向量 `vector<vector<Tensor>>`,第一维对应 slot,第二维对应该 slot 内的 rank。`add()` 方法实现梯度聚合——当多条路径汇聚到同一节点时,梯度会累加。
|
||||
|
||||
### 3. BFS 计算入度
|
||||
|
||||
```cpp
|
||||
std::unordered_map<GradNodeBase*, int> node_in_degree_map;
|
||||
std::deque<GradNodeBase*> queue;
|
||||
queue.push_back(start_node.get());
|
||||
|
||||
while (!queue.empty()) {
|
||||
auto* node = queue.front();
|
||||
queue.pop_front();
|
||||
for (auto& [slot_id, meta] : node->OutputMeta()) {
|
||||
auto& edge = meta.GetEdge();
|
||||
auto* next_node = edge.GetGradNode();
|
||||
if (next_node) {
|
||||
node_in_degree_map[next_node]++;
|
||||
if (node_in_degree_map[next_node] == 1) {
|
||||
queue.push_back(next_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
通过 BFS 遍历整个反向图,统计每个节点的入度(有多少条边指向该节点)。这是后续拓扑排序的基础。
|
||||
|
||||
## 执行阶段(BFS 拓扑排序)
|
||||
|
||||
### 核心循环伪代码
|
||||
|
||||
```
|
||||
queue = deque()
|
||||
queue.push_back(start_node) // 起始节点入度为 0
|
||||
|
||||
while queue 非空:
|
||||
node = queue.pop_front()
|
||||
|
||||
// 1. 取出该节点的输入梯度 buffer
|
||||
node_input_buffer = node_input_buffers_dict[node]
|
||||
|
||||
// 2. 执行反向计算
|
||||
// 调用 GradNode 的 operator(),传入上游梯度,返回下游梯度
|
||||
grad_output_tensors = node->operator()(node_input_buffer.Buffers())
|
||||
|
||||
// 3. 释放已用完的 input buffer,节省内存
|
||||
delete node_input_buffers_dict[node]
|
||||
|
||||
// 4. 将输出梯度传递给后继节点
|
||||
for each (slot_id, output_meta) in node->OutputMeta():
|
||||
edge = output_meta.adj_edge_
|
||||
next_node = edge.grad_node_
|
||||
|
||||
if next_node is nullptr:
|
||||
continue
|
||||
|
||||
// 为后继节点创建 GradTensorHolder(如果还没有的话)
|
||||
if next_node not in node_input_buffers_dict:
|
||||
node_input_buffers_dict[next_node] =
|
||||
new GradTensorHolder(next_node->InputMeta())
|
||||
|
||||
// 梯度聚合:将当前输出梯度加到后继节点的 buffer 中
|
||||
node_input_buffers_dict[next_node].add(
|
||||
edge.in_slot_id_,
|
||||
edge.in_rank_,
|
||||
grad_output_tensors[slot_id])
|
||||
|
||||
// 5. 入度减一
|
||||
node_in_degree_map[next_node] -= 1
|
||||
|
||||
// 6. 入度为 0 时入队
|
||||
if node_in_degree_map[next_node] == 0:
|
||||
if next_node is AccumulationNode:
|
||||
queue.push_front(next_node) // 叶节点优先
|
||||
else:
|
||||
queue.push_back(next_node)
|
||||
```
|
||||
|
||||
### 关键细节
|
||||
|
||||
- **拓扑序保证**:只有入度减为 0 的节点才入队,确保节点在所有上游梯度到齐后才执行。
|
||||
- **AccumulationNode 优先**:叶节点(参数 Tensor)对应的 `AccumulationNode` 使用 `push_front` 优先入队。这是因为叶节点执行后可以立即释放梯度 buffer,节省内存。
|
||||
- **梯度聚合**:`GradTensorHolder::add()` 内部检查 buffer 是否已有 Tensor,若有则执行 `paddle::experimental::add` 累加;若无则直接赋值。
|
||||
- **retain_graph**:若 `retain_graph=false`(默认),执行完反向后会清理 `TensorWrapper`,释放前向 Tensor 引用,防止内存泄漏。调用 `node->ClearTensorWrappers()`。
|
||||
- **Hooks**:执行节点前后可触发 gradient hooks(`node->ApplyGradientHooks()`),用于梯度裁剪、监控等。
|
||||
|
||||
## AccumulationNode(叶节点)
|
||||
|
||||
叶节点(如模型参数 `w`)不是由某个算子产生的,其 `GradNode` 是特殊的 `AccumulationNode`。
|
||||
|
||||
```cpp
|
||||
class AccumulationNode : public GradNodeBase {
|
||||
// operator() 实现:将传入的梯度累加到 tensor.grad 中
|
||||
paddle::Tensor* tensor_; // 指向原始叶 Tensor
|
||||
};
|
||||
```
|
||||
|
||||
`AccumulationNode::operator()` 将梯度写入叶 Tensor 的 `AutogradMeta::grad_` 中,这就是训练时 `w.grad` 的来源。
|
||||
|
||||
## GeneralGrad:paddle.grad() 的实现
|
||||
|
||||
`paddle.grad(outputs, inputs, grad_outputs)` 不同于 `backward()`——它只计算指定 `inputs` 的梯度,不累加到 `.grad` 属性中。
|
||||
|
||||
### 核心类:GeneralGrad
|
||||
|
||||
```cpp
|
||||
class GeneralGrad {
|
||||
// 单例模式
|
||||
static GeneralGrad& Instance();
|
||||
|
||||
void PreparedForGeneralGrad(...);
|
||||
void GetGraphInfoBetweenTargets(...);
|
||||
std::vector<paddle::Tensor> GetResults(...);
|
||||
};
|
||||
```
|
||||
|
||||
### 执行流程
|
||||
|
||||
#### 1. CopyGradNode
|
||||
|
||||
对起始节点创建一个 `CopyGradNode` 副本,避免修改原始反向图。
|
||||
|
||||
#### 2. PreparedForGeneralGrad
|
||||
|
||||
标记目标输入 Tensor 对应的 `GradNode`,以便在执行过程中识别。
|
||||
|
||||
#### 3. GetGraphInfoBetweenTargets
|
||||
|
||||
从 outputs 对应的 GradNode 开始 BFS,找到 outputs 到 inputs 之间的所有节点,裁剪不需要的分支:
|
||||
- 只保留从 outputs 可达且最终能到达 inputs 的节点
|
||||
- 对不在路径上的节点,将其入度设为 0(跳过执行)
|
||||
|
||||
#### 4. RegisterFetchGradHook
|
||||
|
||||
在目标 inputs 对应的 `AccumulationNode` 上注册 hook,在梯度到达时捕获梯度值,而不是写入 `.grad` 属性。
|
||||
|
||||
#### 5. 执行
|
||||
|
||||
复用与 `backward()` 相同的 BFS 拓扑排序循环,但只遍历裁剪后的子图。
|
||||
|
||||
#### 6. GetResults
|
||||
|
||||
从注册的 hook 中收集捕获的梯度,按 `inputs` 的顺序返回。
|
||||
|
||||
## 调试提示
|
||||
|
||||
- **梯度为 None**:检查对应 Tensor 的 `stop_gradient` 是否为 True,或该 Tensor 是否在反向图路径上。
|
||||
- **梯度数值错误**:在 `GradNode::operator()` 中打断点,检查输入梯度和输出梯度。
|
||||
- **内存泄漏**:检查 `retain_graph` 是否被误设为 True,或 `TensorWrapper` 是否正确释放。
|
||||
- **拓扑序异常**:打印 `node_in_degree_map`,检查入度计算是否正确。
|
||||
@@ -0,0 +1,145 @@
|
||||
# 复数自动微分与 Wirtinger 导数
|
||||
|
||||
本文档说明 Paddle 中复数 Tensor 的自动微分原理,基于 Wirtinger Calculus(维尔廷格微积分),解释框架如何处理非全纯(non-holomorphic)函数的梯度。
|
||||
|
||||
## 问题背景
|
||||
|
||||
深度学习中的 loss 函数是**实值**的(输出为 R),但中间计算可能涉及复数(C)。例如傅里叶变换、复数注意力机制等。
|
||||
|
||||
**核心困难**:常见的 loss 函数是 C→R 映射(如 `|z|^2`),不满足柯西-黎曼方程,因此不是全纯函数(holomorphic),传统复变微积分的导数定义不适用。
|
||||
|
||||
## Wirtinger Calculus 基础
|
||||
|
||||
### 核心思想
|
||||
|
||||
将复数 z = a + bi 及其共轭 z* = a - bi 视为**两个独立变量**,定义两个偏导数:
|
||||
|
||||
| 名称 | 定义 | 符号 |
|
||||
|------|------|------|
|
||||
| Wirtinger 导数 | ∂f/∂z = (1/2)(∂f/∂a - i·∂f/∂b) | 对 z 的偏导 |
|
||||
| 共轭 Wirtinger 导数 | ∂f/∂z* = (1/2)(∂f/∂a + i·∂f/∂b) | 对 z* 的偏导 |
|
||||
|
||||
其中 a = Re(z),b = Im(z)。
|
||||
|
||||
### 关键性质
|
||||
|
||||
- 若 f 是全纯函数,则 ∂f/∂z* = 0,∂f/∂z 就是传统的复数导数
|
||||
- 若 f 是反全纯函数(anti-holomorphic),则 ∂f/∂z = 0
|
||||
- 对一般的可微函数,两个偏导数都非零
|
||||
|
||||
### 与实数梯度的关系
|
||||
|
||||
对实值函数 L: C→R,实数梯度为:
|
||||
|
||||
```
|
||||
∂L/∂a = 2·Re(∂L/∂z*) = 2·Re(∂L/∂z)
|
||||
∂L/∂b = 2·Im(∂L/∂z*) = -2·Im(∂L/∂z)
|
||||
```
|
||||
|
||||
## 梯度下降中的应用
|
||||
|
||||
### 优化公式
|
||||
|
||||
对复数参数 z 的梯度下降更新规则:
|
||||
|
||||
```
|
||||
z_{n+1} = z_n - 2·α · (∂L/∂z*)
|
||||
```
|
||||
|
||||
其中 α 是学习率。因子 2 来源于 Wirtinger 导数的定义(含 1/2 系数)。
|
||||
|
||||
**等价形式**:也可以写为 `z_{n+1} = z_n - α · ∇_z L`,其中 ∇_z L = 2·(∂L/∂z*)。
|
||||
|
||||
### 为什么用 ∂L/∂z* 而非 ∂L/∂z?
|
||||
|
||||
对实值 loss L,∂L/∂z* 给出的方向是**最速下降方向**。直觉上,∂L/∂z* 编码了实部和虚部的梯度信息,使得沿其负方向移动能最快减小 L。
|
||||
|
||||
## 链式法则
|
||||
|
||||
设复合函数 L = L(s(z)),其中 s: C→C,L: C→R。链式法则为:
|
||||
|
||||
```
|
||||
∂L/∂z* = (∂L/∂s)* · (∂s/∂z*) + (∂L/∂s) · (∂s/∂z)*
|
||||
|
||||
等价地:
|
||||
∂L/∂z* = conj(output_grad) · (∂s/∂z*) + output_grad · conj(∂s/∂z)
|
||||
```
|
||||
|
||||
其中 `output_grad = ∂L/∂s`,是上游传来的梯度。
|
||||
|
||||
**注意**:这比实数链式法则复杂——需要同时用到 output_grad 及其共轭,以及 s 对 z 和 z* 的偏导数。
|
||||
|
||||
## 各框架约定
|
||||
|
||||
不同深度学习框架在自动微分中计算的 Wirtinger 导数不同:
|
||||
|
||||
| 框架 | 反向传播计算的量 | 说明 |
|
||||
|------|----------------|------|
|
||||
| **PyTorch** | ∂L/∂z* (共轭 Wirtinger 导数) | `.grad` 存储的是 ∂L/∂z*,直接用于梯度下降 |
|
||||
| **TensorFlow** | ∂L/∂z* (共轭 Wirtinger 导数) | 与 PyTorch 一致 |
|
||||
| **JAX** | ∂L/∂z (Wirtinger 导数) | 需取共轭后才能用于梯度下降 |
|
||||
| **Paddle** | ∂L/∂z* (共轭 Wirtinger 导数) | 与 PyTorch/TF 一致 |
|
||||
|
||||
**Paddle 的选择**:计算 ∂L/∂z*,与 PyTorch 保持一致。`.grad` 中存储的值可直接用于优化器更新。
|
||||
|
||||
## 特殊情况简化
|
||||
|
||||
### C→R 函数(如 loss 函数)
|
||||
|
||||
当 s: C→R(输出为实数),有 ∂L/∂s 为实数,因此 `conj(output_grad) = output_grad`。链式法则简化为:
|
||||
|
||||
```
|
||||
∂L/∂z* = output_grad · [(∂s/∂z*) + conj(∂s/∂z)]
|
||||
= output_grad · ∂s/∂a (其中 a = Re(z))
|
||||
```
|
||||
|
||||
**实际含义**:对 C→R 函数,共轭 Wirtinger 导数退化为对实部的普通偏导数乘以 output_grad,与实数情况类似。
|
||||
|
||||
### R→C 函数
|
||||
|
||||
当 s: R→C(输入为实数),z = z*,两个 Wirtinger 导数合并:
|
||||
|
||||
```
|
||||
∂L/∂z* = conj(output_grad) · (∂s/∂z*) + output_grad · conj(∂s/∂z)
|
||||
```
|
||||
|
||||
由于输入为实数,最终需要取实部:
|
||||
|
||||
```
|
||||
∂L/∂x = 2·Re(∂L/∂z*) = 2·Re[conj(output_grad) · (∂s/∂x)/2 + output_grad · conj((∂s/∂x)/2)]
|
||||
= 2·Re[output_grad · conj(∂s/∂x)] (简化后)
|
||||
```
|
||||
|
||||
### C→C 全纯函数
|
||||
|
||||
当 s 是全纯函数时,∂s/∂z* = 0,链式法则简化为:
|
||||
|
||||
```
|
||||
∂L/∂z* = output_grad · conj(∂s/∂z)
|
||||
```
|
||||
|
||||
这与实数反向传播形式一致——只需要传统导数的共轭。
|
||||
|
||||
## Paddle 中的实现
|
||||
|
||||
在 Paddle 的反向 Kernel 实现中,对涉及复数的算子,反向公式需遵循上述链式法则。具体体现为:
|
||||
|
||||
1. **grad kernel 接收的 `out_grad`**:是 ∂L/∂s*(上游传来的共轭 Wirtinger 导数)
|
||||
2. **grad kernel 计算并返回**:∂L/∂z*(本层的共轭 Wirtinger 导数)
|
||||
3. **对复数乘法等算子**:需要显式使用 `conj()` 操作
|
||||
|
||||
### 示例:复数乘法的反向
|
||||
|
||||
前向:`s = x * y`(逐元素复数乘法,全纯)
|
||||
|
||||
反向(计算 ∂L/∂x* 和 ∂L/∂y*):
|
||||
```
|
||||
∂L/∂x* = out_grad · conj(y) (因为 ∂s/∂x = y,全纯)
|
||||
∂L/∂y* = out_grad · conj(x) (因为 ∂s/∂y = x,全纯)
|
||||
```
|
||||
|
||||
## 调试提示
|
||||
|
||||
- **梯度校验**:使用 `paddle.autograd.gradcheck` 时,复数 Tensor 的有限差分需要在实部和虚部两个方向分别扰动
|
||||
- **梯度共轭问题**:如果梯度的虚部符号反了,检查是否混淆了 ∂L/∂z 和 ∂L/∂z*
|
||||
- **与 PyTorch 对比**:Paddle 与 PyTorch 约定一致,可直接对比 `.grad` 数值
|
||||
@@ -0,0 +1,200 @@
|
||||
# 前向调用链路详解
|
||||
|
||||
本文档详细说明 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` |
|
||||
|
||||
## 层① ops_api.cc — Python-C 映射
|
||||
|
||||
**文件**:`paddle/fluid/pybind/ops_api.cc`
|
||||
|
||||
**入口函数签名**:
|
||||
```cpp
|
||||
static PyObject *add(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
```
|
||||
|
||||
**核心职责**:
|
||||
1. 作为 Python 与 C++ 之间的桥梁,注册到 Python 模块的 method table 中
|
||||
2. 调用 `GetTensorFromArgs` 从 `PyObject*` 中提取 `paddle::Tensor`
|
||||
3. 判断当前运行模式:静态图(PIR)还是动态图(Eager)
|
||||
4. 动态图模式下转发到层②的 `eager_api_add`
|
||||
|
||||
**`GetTensorFromArgs` 的作用**:
|
||||
- 接收 `PyObject*` 参数和位置索引
|
||||
- 检查参数类型是否为 Tensor(支持 `DenseTensor`、`DistTensor` 等)
|
||||
- 提取底层 C++ `paddle::Tensor` 引用并返回
|
||||
- 处理可选参数(`paddle::optional<Tensor>`)的情况
|
||||
|
||||
**关键特征**:该层代码由 `ops_api_gen.py` 根据算子 YAML 定义自动生成,开发者一般无需手动修改。
|
||||
|
||||
## 层② eager_op_function.cc — 动态图 C++ 接口
|
||||
|
||||
**文件**:`paddle/fluid/pybind/eager_op_function.cc`
|
||||
|
||||
**入口函数签名**:
|
||||
```cpp
|
||||
static PyObject *eager_api_add(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
```
|
||||
|
||||
**执行流程**:
|
||||
|
||||
1. **参数解析**:从 `args`/`kwargs` 中解析出所有输入 Tensor 和 Attribute。使用 `CastPyArg2xxx` 系列函数进行类型转换。
|
||||
|
||||
2. **Dist Tensor 转换**:若处于分布式模式,将普通 Tensor 转化为 `DistTensor`,附加分布式 placement 信息。
|
||||
|
||||
3. **自定义前处理**:部分算子有特殊的前处理逻辑(如参数校验、默认值填充)。
|
||||
|
||||
4. **GIL 释放与执行**:
|
||||
```cpp
|
||||
{
|
||||
eager_gil_scoped_release guard;
|
||||
// 选择 backend,调用层③
|
||||
out = add_ad_func(x, y);
|
||||
}
|
||||
```
|
||||
释放 Python GIL 后进入纯 C++ 执行路径,执行完毕后自动重新获取 GIL。
|
||||
|
||||
5. **Backend 选择**:根据输入 Tensor 所在的设备(CPU/GPU/XPU 等)选择合适的后端。
|
||||
|
||||
6. **返回结果**:将 C++ `paddle::Tensor` 包装为 `PyObject*` 返回给 Python。
|
||||
|
||||
## 层③ dygraph_functions.cc — 自动微分函数
|
||||
|
||||
**文件**:`paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.cc`
|
||||
|
||||
**入口函数签名**:
|
||||
```cpp
|
||||
paddle::Tensor add_ad_func(const paddle::Tensor& x, const paddle::Tensor& y)
|
||||
```
|
||||
|
||||
**这是构建反向图的核心层**,执行流程如下:
|
||||
|
||||
### 3.1 AMP 与 Type Promotion
|
||||
|
||||
- 若启用 AMP(自动混合精度),将输入 Tensor 的 dtype 转换为目标精度(如 float16/bfloat16)
|
||||
- 若算子支持 Type Promotion,对不同 dtype 的输入进行类型提升
|
||||
|
||||
### 3.2 获取输入 AutogradMeta
|
||||
|
||||
```cpp
|
||||
auto p_autograd_x = egr::EagerUtils::nullable_autograd_meta(x);
|
||||
auto p_autograd_y = egr::EagerUtils::nullable_autograd_meta(y);
|
||||
```
|
||||
|
||||
### 3.3 判断是否需要构建反向图
|
||||
|
||||
```cpp
|
||||
bool trace_backward = egr::Controller::Instance().HasGrad();
|
||||
bool require_any_grad = egr::EagerUtils::ComputeRequireGrad(
|
||||
trace_backward, p_autograd_x, p_autograd_y);
|
||||
```
|
||||
只有当全局梯度开启且至少有一个输入需要梯度时,才构建反向图。
|
||||
|
||||
### 3.4 调用层④算子库 API
|
||||
|
||||
```cpp
|
||||
auto api_result = paddle::experimental::add(x, y);
|
||||
```
|
||||
|
||||
### 3.5 构建反向图(核心步骤)
|
||||
|
||||
若 `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`。
|
||||
|
||||
## 层④ api.cc — PHI 算子库接口
|
||||
|
||||
**文件**:`paddle/phi/api/lib/api.cc`
|
||||
|
||||
**入口函数签名**:
|
||||
```cpp
|
||||
Tensor paddle::experimental::add(const Tensor& x, const Tensor& y)
|
||||
```
|
||||
|
||||
**执行流程**:
|
||||
|
||||
### 4.1 构造 KernelKey
|
||||
|
||||
```cpp
|
||||
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---|
|
||||
```
|
||||
|
||||
### 4.2 选择 Kernel
|
||||
|
||||
```cpp
|
||||
auto kernel_result = KernelFactory::Instance().SelectKernelOrThrowError(
|
||||
"add", kernel_key);
|
||||
```
|
||||
KernelFactory 内部维护两级 map:`api_name -> {KernelKey -> Kernel}`。若找不到精确匹配的 Layout,回退到 `ALL_LAYOUT`。
|
||||
|
||||
### 4.3 PrepareData
|
||||
|
||||
将输入 Tensor 转换到目标 backend/dtype/layout:
|
||||
- DataType 转换(如 float64 -> float32)
|
||||
- DataLayout 转换(如 NHWC -> NCHW)
|
||||
- Place 搬运(如 CPU -> GPU)
|
||||
- Contiguous 化(非连续内存 -> 连续内存)
|
||||
|
||||
### 4.4 InferMeta
|
||||
|
||||
推导输出 Tensor 的 shape、dtype、layout 等元信息,分配输出内存。
|
||||
|
||||
### 4.5 Kernel 执行
|
||||
|
||||
```cpp
|
||||
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 执行
|
||||
|
||||
最终执行注册在 PHI 算子库中的具体 Kernel 函数。Kernel 按 `{算子名, Backend, DataType, DataLayout}` 注册,通过宏 `PD_REGISTER_KERNEL` 完成注册。
|
||||
|
||||
Kernel 函数直接操作 `DenseTensor`(或 `SelectedRowsTensor` 等),执行底层数学计算。GPU Kernel 会调用 CUDA/HIP kernel launch。
|
||||
|
||||
## 调试提示
|
||||
|
||||
- **层①报错**:通常是参数个数/类型不匹配,检查 Python 调用参数。
|
||||
- **层②报错**:关注 GIL 释放/获取时序、Dist Tensor 转换逻辑。
|
||||
- **层③报错**:反向图构建问题,检查 `SetTensorWrapper`/`SetGradOutMeta`/`SetHistory` 是否正确。
|
||||
- **层④报错**:Kernel 未注册、数据类型不支持、PrepareData 转换失败。
|
||||
- **层⑤报错**:Kernel 内部计算错误,需深入 PHI Kernel 实现。
|
||||
@@ -0,0 +1,113 @@
|
||||
# Inplace 操作与版本追踪
|
||||
|
||||
本文档说明 Paddle 中 Inplace 操作的实现机制、API 约定、叶 Tensor 约束以及版本追踪系统。
|
||||
|
||||
## 三种操作类型
|
||||
|
||||
| 类型 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **Normal** | 创建新 Tensor 存放结果 | `y = paddle.add(x, other)` |
|
||||
| **Inplace** | 结果直接写入输入 Tensor 的内存 | `x.add_(other)` |
|
||||
| **View** | 与原 Tensor 共享内存,shape 可能不同 | `y = x.reshape(...)` |
|
||||
|
||||
## Inplace 操作的优势
|
||||
|
||||
- **减少内存占用**:不分配新的存储空间,原地修改
|
||||
- **避免分配开销**:省去内存分配和释放的时间
|
||||
- **适用场景**:参数更新(`param.add_(grad)`)、激活函数原地替换等
|
||||
|
||||
## API 约定
|
||||
|
||||
Paddle 的 Inplace 操作遵循**下划线后缀**约定:
|
||||
|
||||
| 普通版本 | Inplace 版本 |
|
||||
|---------|-------------|
|
||||
| `paddle.add(x, y)` | `paddle.add_(x, y)` 或 `x.add_(y)` |
|
||||
| `paddle.scale(x, s)` | `x.scale_(s)` |
|
||||
| `paddle.relu(x)` | `paddle.nn.functional.relu_(x)` |
|
||||
| `paddle.zero_like(x)` | `x.zero_()` |
|
||||
|
||||
Inplace 方法返回修改后的自身 Tensor(方便链式调用),但底层内存已被原地修改。
|
||||
|
||||
## 叶 Tensor 约束
|
||||
|
||||
**规则:不能对需要梯度的叶 Tensor 执行 inplace 操作。**
|
||||
|
||||
```python
|
||||
x = paddle.randn([3, 4])
|
||||
x.stop_gradient = False # x 是叶 Tensor,需要梯度
|
||||
|
||||
x.add_(1.0) # RuntimeError! 不允许
|
||||
```
|
||||
|
||||
**原因**:叶 Tensor 被 `TensorWrapper` 保存用于反向计算。如果原地修改了叶 Tensor 的值,反向计算时读到的就是被修改后的错误值,导致梯度错误。
|
||||
|
||||
**非叶 Tensor 可以 inplace**:
|
||||
```python
|
||||
x = paddle.randn([3, 4])
|
||||
x.stop_gradient = False
|
||||
y = x * 2 # y 是非叶 Tensor
|
||||
y.add_(1.0) # 允许,但会触发版本检查
|
||||
```
|
||||
|
||||
## 版本追踪机制
|
||||
|
||||
为了检测 inplace 修改带来的数据一致性问题,Paddle 使用**版本号**(inplace version)追踪 Tensor 的修改历史。
|
||||
|
||||
### 核心组件
|
||||
|
||||
```
|
||||
Tensor
|
||||
└─ impl_ (TensorBase)
|
||||
└─ inplace_version_counter_ ← 每次 inplace 操作 +1
|
||||
|
||||
TensorWrapper(保存前向 Tensor 用于反向)
|
||||
└─ inplace_version_snapshot_ ← 保存时记录版本号
|
||||
```
|
||||
|
||||
### 工作流程
|
||||
|
||||
1. **保存时快照**:`TensorWrapper` 构造时,记录当前 Tensor 的 `inplace_version` 到 `inplace_version_snapshot_`。
|
||||
|
||||
2. **Inplace 操作递增版本号**:
|
||||
```cpp
|
||||
// 每个 inplace 操作(如 add_)在执行后调用
|
||||
tensor.bump_inplace_version();
|
||||
// 内部:inplace_version_counter_++
|
||||
```
|
||||
|
||||
3. **反向恢复时校验**:`TensorWrapper::recover()` 被调用时(反向计算需要该 Tensor),比较当前版本与快照:
|
||||
```cpp
|
||||
void TensorWrapper::recover() {
|
||||
if (tensor.current_inplace_version() != inplace_version_snapshot_) {
|
||||
PADDLE_THROW(
|
||||
"Tensor has been modified by inplace operation. "
|
||||
"Its version is %d but expected %d.",
|
||||
tensor.current_inplace_version(),
|
||||
inplace_version_snapshot_);
|
||||
}
|
||||
// 版本一致,安全返回 Tensor
|
||||
}
|
||||
```
|
||||
|
||||
4. **版本不一致时报错**:抛出异常,提示用户某个 Tensor 在前向保存后被 inplace 修改,反向计算不安全。
|
||||
|
||||
### 示例
|
||||
|
||||
```python
|
||||
x = paddle.randn([3, 4])
|
||||
x.stop_gradient = False
|
||||
y = x * 2 # y 的 TensorWrapper 保存了 x,版本快照 = 0
|
||||
x.add_(1.0) # x.inplace_version = 1(但 x 是叶 Tensor,实际会报错)
|
||||
|
||||
# 若绕过叶 Tensor 检查:
|
||||
# y.backward() 时 TensorWrapper.recover() 发现版本 1 != 快照 0,报错
|
||||
```
|
||||
|
||||
## 调试提示
|
||||
|
||||
| 错误信息 | 原因 | 解决方案 |
|
||||
|---------|------|---------|
|
||||
| `Leaf Tensor that requires grad has been used in an inplace operation` | 对需要梯度的叶 Tensor 做了 inplace | 改用 normal 版本,或先 `.detach()` |
|
||||
| `Tensor version mismatch` | Tensor 在前向保存后被 inplace 修改 | 找到修改该 Tensor 的 inplace 操作,改为 normal 版本 |
|
||||
| 梯度数值不正确 | 可能有未检测到的 inplace 修改 | 检查所有带 `_` 后缀的操作 |
|
||||
@@ -0,0 +1,168 @@
|
||||
# PyLayer:Python 端自定义反向
|
||||
|
||||
本文档介绍 Paddle 的 `PyLayer` 机制,允许用户在 Python 端自定义前向和反向计算,同时无缝接入动态图的自动微分系统。
|
||||
|
||||
## 基本用法
|
||||
|
||||
```python
|
||||
import paddle
|
||||
from paddle.autograd import PyLayer
|
||||
|
||||
class SquaredReLU(PyLayer):
|
||||
@staticmethod
|
||||
def forward(ctx, x):
|
||||
y = paddle.nn.functional.relu(x)
|
||||
ctx.save_for_backward(y)
|
||||
return y * y
|
||||
|
||||
@staticmethod
|
||||
def backward(ctx, dy):
|
||||
y, = ctx.saved_tensor()
|
||||
return dy * 2 * y
|
||||
|
||||
x = paddle.randn([3, 4], dtype='float32')
|
||||
x.stop_gradient = False
|
||||
y = SquaredReLU.apply(x)
|
||||
y.backward()
|
||||
print(x.grad)
|
||||
```
|
||||
|
||||
## PyLayer 规则
|
||||
|
||||
1. **`forward` 和 `backward` 必须是 `@staticmethod`**
|
||||
2. **第一个参数是 `PyLayerContext`(即 `ctx`)**:提供 `save_for_backward()` 和 `saved_tensor()` 方法
|
||||
3. **`backward` 的非 ctx 参数 = `forward` 的输出个数**:每个 `forward` 输出对应一个上游梯度
|
||||
4. **`backward` 的返回值个数 = `forward` 的输入 Tensor 个数**:每个前向输入 Tensor 需要一个对应的下游梯度
|
||||
5. **通过 `ctx.save_for_backward()` 传递 Tensor 给反向**:不要用闭包捕获 Tensor,否则可能导致内存泄漏
|
||||
6. **通过 `ClassName.apply(args...)` 调用**:不要直接调用 `forward`
|
||||
7. **`backward` 中不需要梯度的返回值可以返回 `None`**
|
||||
|
||||
## 多输入多输出示例
|
||||
|
||||
```python
|
||||
class MultiIO(PyLayer):
|
||||
@staticmethod
|
||||
def forward(ctx, x, y, alpha):
|
||||
# alpha 是非 Tensor 参数,不需要返回梯度
|
||||
ctx.save_for_backward(x, y)
|
||||
ctx.alpha = alpha
|
||||
out1 = alpha * x + y
|
||||
out2 = x * y
|
||||
return out1, out2
|
||||
|
||||
@staticmethod
|
||||
def backward(ctx, d_out1, d_out2):
|
||||
x, y = ctx.saved_tensor()
|
||||
# 返回顺序对应 forward 的 (x, y, alpha)
|
||||
# alpha 是非 Tensor,返回 None
|
||||
dx = ctx.alpha * d_out1 + d_out2 * y
|
||||
dy = d_out1 + d_out2 * x
|
||||
return dx, dy, None
|
||||
```
|
||||
|
||||
## 前向实现详解
|
||||
|
||||
**入口**:`SquaredReLU.apply(x)` 在 C++ 层最终调用 `PyLayerApply`。
|
||||
|
||||
### 步骤 1:解析参数,收集 AutogradMeta
|
||||
|
||||
```cpp
|
||||
// 遍历所有输入参数,识别其中的 Tensor
|
||||
// 获取每个 Tensor 的 AutogradMeta
|
||||
auto autograd_metas = EagerUtils::nullable_autograd_meta(input_tensors);
|
||||
bool require_any_grad = EagerUtils::ComputeRequireGrad(
|
||||
trace_backward, autograd_metas...);
|
||||
```
|
||||
|
||||
与普通算子的 `ad_func` 类似,首先判断是否需要构建反向图。
|
||||
|
||||
### 步骤 2:关闭自动建图,执行 Python forward
|
||||
|
||||
```cpp
|
||||
{
|
||||
AutoGradGuard guard(false); // 临时关闭自动微分
|
||||
// 调用用户定义的 Python forward 函数
|
||||
py_outputs = PyObject_Call(forward_fn, py_args, nullptr);
|
||||
}
|
||||
// guard 析构时自动恢复
|
||||
```
|
||||
|
||||
**为什么要关闭自动建图?** `forward` 内部可能调用 `paddle.relu()` 等算子,这些算子会自动构建反向图。但 PyLayer 有自己的 `backward`,不需要框架再为内部算子建图。关闭后,内部算子只做前向计算。
|
||||
|
||||
### 步骤 3:创建 GradNodePyLayer
|
||||
|
||||
```cpp
|
||||
auto grad_node = std::make_shared<GradNodePyLayer>(
|
||||
py_layer_ctx, backward_fn, output_count, input_count);
|
||||
```
|
||||
|
||||
`GradNodePyLayer` 是 `GradNodeBase` 的子类,持有:
|
||||
- `py_layer_ctx_`:Python 的 `PyLayerContext` 对象(包含 `save_for_backward` 保存的 Tensor)
|
||||
- `backward_fn_`:用户定义的 Python `backward` 函数
|
||||
|
||||
### 步骤 4:建立反向图连接
|
||||
|
||||
```cpp
|
||||
// 连接到后继 GradNode(输入 Tensor 的 GradNode)
|
||||
grad_node->SetGradOutMeta(input_tensors, slot_ids);
|
||||
|
||||
// 将 GradNodePyLayer 写入输出 Tensor 的 AutogradMeta
|
||||
EagerUtils::SetHistory(output_autograd_metas, grad_node);
|
||||
|
||||
// 设置输入 meta
|
||||
grad_node->SetGradInMeta(output_tensors, slot_ids);
|
||||
```
|
||||
|
||||
这与普通算子的反向图构建完全一致——区别仅在于 `GradNode` 的 `operator()` 实现不同。
|
||||
|
||||
## 反向实现详解
|
||||
|
||||
当反向执行到 `GradNodePyLayer` 时,调用其 `operator()`:
|
||||
|
||||
### 步骤 1:将 C++ 梯度转为 Python 对象
|
||||
|
||||
```cpp
|
||||
// grad_inputs: vector<vector<Tensor>> — 来自上游的梯度
|
||||
// 逐个转换为 Python paddle.Tensor
|
||||
PyObject* py_grad_inputs = ToPyObject(grad_inputs);
|
||||
```
|
||||
|
||||
### 步骤 2:调用 Python backward
|
||||
|
||||
```cpp
|
||||
// 调用用户定义的 backward 函数
|
||||
PyObject* py_grad_outputs = PyObject_Call(
|
||||
backward_fn_, py_args_with_ctx, nullptr);
|
||||
// py_args_with_ctx = (ctx, *py_grad_inputs)
|
||||
```
|
||||
|
||||
此时用户的 `backward` 方法被执行,在 Python 端完成反向计算。
|
||||
|
||||
### 步骤 3:将 Python 结果转回 C++
|
||||
|
||||
```cpp
|
||||
// 将 Python 返回的梯度 Tensor 转换回 C++ paddle::Tensor
|
||||
auto grad_outputs = ToTensors(py_grad_outputs);
|
||||
// 返回给反向图执行逻辑继续传播
|
||||
return grad_outputs;
|
||||
```
|
||||
|
||||
## 常见问题与调试
|
||||
|
||||
| 问题 | 原因与解决 |
|
||||
|------|-----------|
|
||||
| `backward` 返回值个数不匹配 | `backward` 返回的 Tensor 数量必须等于 `forward` 的输入 Tensor 数量(非 Tensor 参数用 None) |
|
||||
| `forward` 内部算子的梯度丢失 | 正常行为——`forward` 内部自动建图被关闭,梯度由用户的 `backward` 负责 |
|
||||
| `ctx.saved_tensor()` 返回空 | 检查是否在 `forward` 中调用了 `ctx.save_for_backward()` |
|
||||
| 内存泄漏 | 避免在 `backward` 中引用外部大 Tensor;使用 `ctx.save_for_backward` 而非闭包 |
|
||||
| `apply()` 未被调用 | 直接调用 `forward()` 不会构建反向图,必须通过 `apply()` |
|
||||
|
||||
## 与普通算子的对比
|
||||
|
||||
| 维度 | 普通算子 | PyLayer |
|
||||
|------|---------|---------|
|
||||
| 反向实现 | C++ `GradNode::operator()` | Python `backward()` |
|
||||
| 反向图节点 | 自动生成的 `XxxGradNode` | `GradNodePyLayer` |
|
||||
| 前向建图 | 自动 | 关闭(由用户 backward 接管) |
|
||||
| 性能 | 高(纯 C++) | 较低(Python 回调开销) |
|
||||
| 灵活性 | 需修改 C++ 代码 | 纯 Python 实现 |
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: paddle-phi-kernel
|
||||
description: "Use when working with Paddle's PHI kernel system: registering new kernels, debugging kernel selection/dispatch, understanding code auto-generation from YAML, or implementing operator decomposition via the combination mechanism."
|
||||
---
|
||||
|
||||
# PHI Kernel 体系总览
|
||||
|
||||
## Kernel 两级 map 结构
|
||||
|
||||
PHI kernel 在 `KernelFactory` 单例中以两级 `flat_hash_map` 存储:
|
||||
|
||||
```
|
||||
api_name (string) → KernelKeyMap
|
||||
├── KernelKey_1 → Kernel_1
|
||||
├── KernelKey_2 → Kernel_2
|
||||
└── ...
|
||||
```
|
||||
|
||||
- 第一级:算子名称(如 `"add"`, `"matmul"`)→ `KernelKeyMap`
|
||||
- 第二级:`KernelKey` → `Kernel` 对象(包含函数指针、参数元信息)
|
||||
|
||||
## KernelKey 哈希结构
|
||||
|
||||
`KernelKey` 由 Backend、DataLayout、DataType 三要素组成,哈希编码为 32-bit 整数:
|
||||
|
||||
```
|
||||
bit: 31 ─────── 20 | 19 ─── 12 | 11 ── 8 | 7 ── 0
|
||||
Extended DataType Layout Backend
|
||||
```
|
||||
|
||||
- `Backend`(bit 0-7): CPU / GPU / GPUDNN / XPU / OneDNN 等
|
||||
- `DataLayout`(bit 8-11): NCHW / NHWC / ANY 等
|
||||
- `DataType`(bit 12-19): FLOAT32 / FLOAT16 / BFLOAT16 / INT64 等
|
||||
- `Extended`(bit 20-31): 保留位,用于未来扩展
|
||||
|
||||
## 代码生成管线概览
|
||||
|
||||
PHI 体系通过 YAML 驱动代码生成,覆盖三个子系统:
|
||||
|
||||
| 子系统 | 生成器 | 产出物 |
|
||||
|--------|--------|--------|
|
||||
| C++ API 层 | `api_gen.py` | `paddle/phi/api/lib/api.cc` |
|
||||
| 动态图函数层 | `eager_gen.py` | `dygraph_functions.cc`, `nodes.cc` |
|
||||
| Python-C 映射层 | `python_c_gen.py` | `eager_op_function.cc` |
|
||||
|
||||
输入 YAML:`ops.yaml`, `backward.yaml`, `fused_ops.yaml`, `sparse_ops.yaml`, `op_compat.yaml`
|
||||
|
||||
## 组合算子机制
|
||||
|
||||
将 1061 个原生算子分解为约 200 个基础算子(primitive operators),降低分布式 / 编译器 / 新硬件适配成本。
|
||||
|
||||
- **前向分解**:`DecompInterface` → `call_decomp_rule()` → `composite.h` 实现
|
||||
- **反向分解**(VJP):`VjpInterface` / `DecompVjpInterface` → `call_decomp_vjp()` → `details.h` 实现
|
||||
- **CustomVJP**:为 sigmoid、log_softmax 等数值敏感算子提供手写反向
|
||||
|
||||
## 什么场景看什么文件
|
||||
|
||||
| 场景 | 参考文档 |
|
||||
|------|----------|
|
||||
| 注册新 kernel / 理解宏展开 | [references/kernel-registration.md](references/kernel-registration.md) |
|
||||
| 调试 kernel 选择 / 分派失败 | [references/kernel-selection.md](references/kernel-selection.md) |
|
||||
| 理解 YAML → 代码生成流程 | [references/codegen-pipeline.md](references/codegen-pipeline.md) |
|
||||
| 开发组合算子 / VJP | [references/combination-mechanism.md](references/combination-mechanism.md) |
|
||||
|
||||
## 社区源码链接(L3)
|
||||
|
||||
- PHI kernels 根目录: `paddle/phi/kernels/`
|
||||
- Kernel 注册宏: `paddle/phi/core/kernel_registry.h`
|
||||
- KernelFactory: `paddle/phi/core/kernel_factory.h`, `kernel_factory.cc`
|
||||
- YAML 定义: `paddle/phi/ops/yaml/ops.yaml`, `backward.yaml`
|
||||
- 代码生成脚本: `paddle/phi/api/generator/` — `api_gen.py`, `backward_api_gen.py`, `tensor_operants_gen.py`
|
||||
- 组合算子前向: `paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h`
|
||||
- 组合算子反向: `paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h`
|
||||
@@ -0,0 +1,190 @@
|
||||
# 代码自动生成管线详解
|
||||
|
||||
## 概述
|
||||
|
||||
Paddle PHI 体系采用 YAML 驱动的代码生成方式,从算子定义文件自动生成 C++ API、动态图函数、Python-C 绑定等多层代码。这一设计使得新增算子只需编写 YAML 描述和 kernel 实现,中间的粘合代码全部自动生成。
|
||||
|
||||
## YAML 定义文件
|
||||
|
||||
所有算子元信息以 YAML 格式维护,位于 `paddle/phi/ops/yaml/` 目录下:
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `ops.yaml` | 前向算子定义(输入、输出、属性、kernel 映射、infer_meta) |
|
||||
| `backward.yaml` | 反向算子定义 |
|
||||
| `fused_ops.yaml` | 融合算子(如 fused_attention、fused_feedforward) |
|
||||
| `sparse_ops.yaml` | 稀疏算子(SparseCoo / SparseCsr) |
|
||||
| `op_compat.yaml` | 新旧算子名称 / 参数名映射,保证兼容性 |
|
||||
| `op_version.yaml` | 算子版本管理,记录不兼容变更 |
|
||||
|
||||
### ops.yaml 单条记录示例
|
||||
|
||||
```yaml
|
||||
- op: add
|
||||
args: (Tensor x, Tensor y)
|
||||
output: Tensor(out)
|
||||
infer_meta:
|
||||
func: ElementwiseInferMeta
|
||||
kernel:
|
||||
func: add
|
||||
data_type: x
|
||||
backward: add_grad
|
||||
```
|
||||
|
||||
各字段含义:
|
||||
- `op`:算子名称
|
||||
- `args`:输入和属性声明(用括号包裹,逗号分隔)
|
||||
- `output`:输出声明
|
||||
- `infer_meta.func`:形状推导函数名(对应 `paddle/phi/infermeta/` 下的 C++ 函数)
|
||||
- `kernel.func`:PHI kernel 函数名
|
||||
- `kernel.data_type`:kernel DataType 推断来源(此处取输入 `x` 的 dtype)
|
||||
- `backward`:关联的反向算子名
|
||||
|
||||
## 代码生成体系(两套并行)
|
||||
|
||||
当前 Paddle 有两套代码生成管线并行工作:**PHI API 层**和 **PIR Op 层**。
|
||||
|
||||
### PHI API 层(paddle/phi/api/)
|
||||
|
||||
生成器脚本位于 `paddle/phi/api/generator/`,产出 C++ API 函数:
|
||||
|
||||
| 生成器脚本 | 产出文件 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `api_gen.py` | `paddle/phi/api/lib/api.cc` | 前向 C++ API |
|
||||
| `backward_api_gen.py` | `paddle/phi/api/lib/backward_api.cc` | 反向 C++ API |
|
||||
| `intermediate_api_gen.py` | `paddle/phi/api/lib/dygraph_api.{h,cc}` | 动态图中间 API |
|
||||
| `sparse_api_gen.py` | `paddle/phi/api/lib/sparse_api.cc` | 稀疏前向 API |
|
||||
| `sparse_bw_api_gen.py` | `paddle/phi/api/lib/sparse_bw_api.cc` | 稀疏反向 API |
|
||||
| `tensor_operants_gen.py` | `paddle/phi/api/lib/tensor_api.cc`, `tensor_operants.h` | Tensor 运算符重载 |
|
||||
|
||||
**生成内容**:每个算子对应一个 C++ 函数,内部包含完整的 kernel 选择 + 数据准备 + kernel 调用逻辑:
|
||||
|
||||
```cpp
|
||||
// 自动生成的 paddle::experimental::add()
|
||||
Tensor add(const Tensor& x, const Tensor& y) {
|
||||
// 1. ParseKernelKeyByInputArgs → KernelKey
|
||||
// 2. SelectKernelOrThrowError → Kernel
|
||||
// 3. PrepareData(TransDataPlace/Type/Layout)
|
||||
// 4. InferMeta(形状推导)
|
||||
// 5. kernel_fn(dev_ctx, x, y, out)
|
||||
return out;
|
||||
}
|
||||
```
|
||||
|
||||
### PIR Op 层(paddle/fluid/pir/dialect/op_generator/)
|
||||
|
||||
生成 PIR 算子定义和 Python-C 绑定:
|
||||
|
||||
| 生成器脚本 | 产出文件 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `api_gen.py` | PIR Op C++ API | PIR 算子接口 |
|
||||
| `python_c_gen.py` | Python-C 绑定 | PIR 算子的 Python 调用入口 |
|
||||
| `ops_api_gen.py` | `paddle/fluid/pybind/ops_api.cc` | Python 层算子分发 |
|
||||
|
||||
### 动态图函数层
|
||||
|
||||
**生成器**:`paddle/fluid/eager/auto_code_generator/generator/eager_gen.py`
|
||||
|
||||
**输入**:与 PHI API 层相同的 YAML 文件
|
||||
|
||||
**产出**:
|
||||
- `paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.cc`
|
||||
- `paddle/fluid/eager/api/generated/eager_generated/backwards/nodes.cc`(反向 Node 类)
|
||||
|
||||
**生成内容**:
|
||||
- 前向函数:调用 C++ API 层 + 构建反向计算图(创建 GradNode、保存前向 Tensor)
|
||||
- 反向 Node 类:继承 `egr::GradNodeBase`,实现 `operator()()` 调用反向 C++ API
|
||||
|
||||
### Python-C 绑定层(动态图)
|
||||
|
||||
**生成器**:`paddle/fluid/eager/auto_code_generator/generator/python_c_gen.py`
|
||||
|
||||
**输入**:同上 YAML + 动态图函数签名
|
||||
|
||||
**产出**:
|
||||
- `paddle/fluid/pybind/eager_op_function.cc`
|
||||
|
||||
**生成内容**:将动态图函数包装为 Python 可调用对象,处理:
|
||||
- Python 对象到 C++ Tensor 的转换
|
||||
- 属性类型解析(int / float / list / string)
|
||||
- 关键字参数和默认值
|
||||
- 错误消息和类型检查
|
||||
|
||||
## 静态图 CodeGen
|
||||
|
||||
静态图使用 Jinja2 模板引擎,脚本位于 `paddle/fluid/operators/generator/`:
|
||||
|
||||
| 脚本 | 功能 |
|
||||
|------|------|
|
||||
| `parse_op.py` | 解析 YAML 为内部 OpDef 数据结构 |
|
||||
| `cross_validate.py` | 校验 ops.yaml 与 op_compat.yaml 一致性 |
|
||||
| `generate_op.py` | 从 Jinja 模板生成 `generated_op*.cc` |
|
||||
| `generate_static_op.py` | 生成静态图 Op |
|
||||
|
||||
模板文件位于 `paddle/fluid/operators/generator/templates/`,包含:
|
||||
- `op.c.j2`:OpMaker、InferShape、GetExpectedKernelType
|
||||
- `ks.c.j2`:Kernel 签名
|
||||
- `operator_utils.c.j2`:算子工具函数
|
||||
|
||||
生成的文件位于 `paddle/fluid/operators/` 目录下(如 `generated_op1.cc`...`generated_op4.cc`、`generated_static_op.cc`),注册到 fluid 的 `OpRegistry` 中。
|
||||
|
||||
## CMake 构建集成
|
||||
|
||||
代码生成在 CMake configure 或 build 阶段触发,使用以下 CMake 命令:
|
||||
|
||||
### execute_process(configure 阶段)
|
||||
|
||||
```cmake
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${API_GEN_PY}
|
||||
--api_yaml_path ${OPS_YAML}
|
||||
--api_header_path ${API_HEADER}
|
||||
--api_source_path ${API_SOURCE}
|
||||
)
|
||||
```
|
||||
|
||||
在 `cmake ..` 时立即执行,适用于生成文件不频繁变化的场景。
|
||||
|
||||
### add_custom_command + add_custom_target(build 阶段)
|
||||
|
||||
```cmake
|
||||
add_custom_command(
|
||||
OUTPUT ${API_SOURCE}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${API_GEN_PY} ...
|
||||
DEPENDS ${OPS_YAML} ${API_GEN_PY}
|
||||
)
|
||||
add_custom_target(api_gen ALL DEPENDS ${API_SOURCE})
|
||||
```
|
||||
|
||||
在 `make` 时按依赖关系触发,只有 YAML 或生成器脚本修改后才重新生成。
|
||||
|
||||
### copy_if_different
|
||||
|
||||
```cmake
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TMP_FILE} ${FINAL_FILE}
|
||||
)
|
||||
```
|
||||
|
||||
先生成到临时文件,再与目标文件比较。内容相同则不覆盖,避免触发不必要的重编译。
|
||||
|
||||
## 关键文件路径汇总
|
||||
|
||||
| 层级 | 生成器脚本 | 产出目录 |
|
||||
|------|-----------|---------|
|
||||
| PHI C++ API | `paddle/phi/api/generator/api_gen.py` | `paddle/phi/api/lib/` |
|
||||
| PHI 中间 API | `paddle/phi/api/generator/intermediate_api_gen.py` | `paddle/phi/api/lib/` |
|
||||
| 动态图函数 | `paddle/fluid/eager/auto_code_generator/generator/eager_gen.py` | `paddle/fluid/eager/api/generated/` |
|
||||
| Python-C(动态图)| `paddle/fluid/eager/auto_code_generator/generator/python_c_gen.py` | `paddle/fluid/pybind/` |
|
||||
| PIR Op API | `paddle/fluid/pir/dialect/op_generator/api_gen.py` | PIR Op 定义 |
|
||||
| PIR ops_api | `paddle/fluid/pir/dialect/op_generator/ops_api_gen.py` | `paddle/fluid/pybind/` |
|
||||
| 静态图 | `paddle/fluid/operators/generator/generate_op.py` | `paddle/fluid/operators/` |
|
||||
| YAML 定义 | — | `paddle/phi/ops/yaml/` |
|
||||
|
||||
## 调试与开发建议
|
||||
|
||||
1. **修改 YAML 后重新生成**:完整 `make` 即可触发,代码生成通过 CMake 依赖自动处理
|
||||
2. **查看生成结果**:到 `build/` 目录下对应路径查看 `.cc` 文件
|
||||
3. **调试生成器**:直接用 Python 运行生成器脚本,添加 `--help` 查看参数
|
||||
4. **新增算子**:只需在 `ops.yaml` + `backward.yaml` 添加条目,编写 kernel 和 infer_meta,其余全部自动生成
|
||||
5. **兼容旧算子**:在 `op_compat.yaml` 中添加新旧名称映射
|
||||
@@ -0,0 +1,213 @@
|
||||
# 组合算子(Operator Combination / Decomposition)机制
|
||||
|
||||
## 问题背景
|
||||
|
||||
Paddle 原生算子库包含约 1061 个算子。每当需要适配新场景(分布式自动并行、编译器优化、新硬件接入),都需要对这些算子逐一适配,成本极高:
|
||||
|
||||
- **分布式**:每个算子需要编写切分推导规则(SPMDRule)
|
||||
- **编译器(CINN)**:每个算子需要编写 lowering 实现
|
||||
- **新硬件**:每个算子需要编写 kernel
|
||||
|
||||
## 解决方案:基础算子集
|
||||
|
||||
定义约 200 个基础算子(primitive operators),将其余原生算子分解(decompose)为基础算子的组合。适配工作只需覆盖基础算子集即可。
|
||||
|
||||
基础算子集的选取原则:
|
||||
- 语义原子性:不能再分解为更简单的操作
|
||||
- 计算完备性:能组合表达所有原生算子
|
||||
- 性能可接受:组合后的性能损失在可控范围内
|
||||
|
||||
## 前向分解:DecompInterface
|
||||
|
||||
### 接口定义
|
||||
|
||||
前向分解通过 PIR Interface 机制实现。每个可分解的算子实现 `DecompInterface`:
|
||||
|
||||
```cpp
|
||||
// paddle/fluid/pir/dialect/operator/interface/decomp.h
|
||||
class DecompInterface : public pir::OpInterfaceBase<DecompInterface> {
|
||||
// concept-model 多态,由 Op 注册时自动绑定
|
||||
};
|
||||
```
|
||||
|
||||
### 分解规则实现
|
||||
|
||||
分解规则的实现位于 `paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h`:
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
std::tuple<Tensor, Tensor, Tensor> layer_norm_decomp(
|
||||
const Tensor& x,
|
||||
const paddle::optional<Tensor>& scale,
|
||||
const paddle::optional<Tensor>& bias,
|
||||
float epsilon,
|
||||
int begin_norm_axis) {
|
||||
// 使用基础算子表达:
|
||||
auto mean = paddle::mean(x, reduce_axes, true);
|
||||
auto diff = x - mean;
|
||||
auto variance = paddle::mean(diff * diff, reduce_axes, true);
|
||||
auto rsqrt_var = paddle::rsqrt(variance + epsilon);
|
||||
auto out = diff * rsqrt_var;
|
||||
if (scale) out = out * scale.get();
|
||||
if (bias) out = out + bias.get();
|
||||
return {out, mean, variance};
|
||||
}
|
||||
```
|
||||
|
||||
### 调用入口
|
||||
|
||||
`call_decomp_rule()` 位于 `paddle/fluid/primitive/base/decomp_trans.cc`,作为统一分发入口:
|
||||
|
||||
```cpp
|
||||
std::vector<std::vector<pir::Value>> call_decomp_rule(pir::Operation* op) {
|
||||
paddle::dialect::DecompInterface decomp_interface =
|
||||
op->dyn_cast<paddle::dialect::DecompInterface>();
|
||||
// 通过 concept-model 多态调用对应 Op 的分解实现
|
||||
return decomp_interface.Decomp(op);
|
||||
}
|
||||
```
|
||||
|
||||
分解判断函数 `has_decomp_rule()` 检查 Op 是否注册了 `DecompInterface`。
|
||||
|
||||
## 反向分解:VjpInterface / DecompVjpInterface
|
||||
|
||||
### 概述
|
||||
|
||||
VJP(Vector-Jacobian Product)是反向传播的数学本质。组合算子体系为反向传播提供两层分解机制:
|
||||
|
||||
- **VjpInterface**:定义在 `paddle/fluid/pir/dialect/operator/interface/vjp.h`,提供反向计算规则
|
||||
- **DecompVjpInterface**:定义在 `paddle/fluid/pir/dialect/operator/interface/decomp_vjp.h`,提供反向的组合算子分解
|
||||
|
||||
### 实现
|
||||
|
||||
VJP 规则分为自动生成和手写两部分:
|
||||
|
||||
- **自动生成**:`${PADDLE_BINARY_DIR}/paddle/fluid/primitive/vjp_interface/generated/generated_vjp.cc`(构建时由 `codegen/decomp_vjp_gen.py` 生成)
|
||||
- **手写**:`paddle/fluid/primitive/vjp_interface/manual/manual_vjp.cc`
|
||||
|
||||
反向分解规则实现位于 `paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h`:
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
std::vector<std::vector<Tensor>> add_vjp(
|
||||
const Tensor& x,
|
||||
const Tensor& y,
|
||||
const Tensor& out_grad,
|
||||
int axis) {
|
||||
// add 的反向:grad_x = out_grad, grad_y = out_grad
|
||||
// 需要处理广播情况
|
||||
auto grad_x = reduce_as(out_grad, x);
|
||||
auto grad_y = reduce_as(out_grad, y);
|
||||
return {{grad_x}, {grad_y}};
|
||||
}
|
||||
```
|
||||
|
||||
### 调用入口
|
||||
|
||||
`call_decomp_vjp()` 同样位于 `paddle/fluid/primitive/base/decomp_trans.cc`,通过 `DecompVjpInterface` 分派。
|
||||
|
||||
统一入口头文件:`paddle/fluid/primitive/vjp_interface/vjp.h`。
|
||||
|
||||
## CustomVJP:数值稳定性特殊处理
|
||||
|
||||
某些算子的数学分解虽然正确,但在数值上不稳定。例如:
|
||||
|
||||
- **sigmoid 反向**:数学上 `grad = out_grad * sigmoid(x) * (1 - sigmoid(x))`,但直接用基础算子组合会丢失精度。CustomVJP 直接使用前向输出 `out`,计算 `grad = out_grad * out * (1 - out)`,避免重复计算 sigmoid。
|
||||
- **log_softmax 反向**:类似地,利用前向已计算的中间结果提升数值稳定性。
|
||||
|
||||
CustomVJP 的注册方式与普通 VJP 相同,但实现中会利用前向输出作为中间量,而非重新从输入计算。
|
||||
|
||||
## 开发工作流
|
||||
|
||||
### 新增前向分解
|
||||
|
||||
1. 在 `paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h` 中实现分解模板函数
|
||||
2. 确保对应 Op 注册了 `DecompInterface`(通过 YAML 配置 `composite` 字段或手写接口注册)
|
||||
3. 编写单元测试验证精度
|
||||
|
||||
### 新增反向分解(VJP)
|
||||
|
||||
1. 在 `paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h` 中实现 VJP 模板函数
|
||||
2. 如果是自动生成的算子,确保 YAML 中配置了 `composite` 字段
|
||||
3. 手写 VJP 需要在 `paddle/fluid/primitive/vjp_interface/manual/manual_vjp.cc` 中添加
|
||||
4. 编写测试验证梯度正确性
|
||||
|
||||
### 测试
|
||||
|
||||
```bash
|
||||
# 单算子精度测试
|
||||
python test/legacy_test/test_activation_op.py TestSigmoid
|
||||
|
||||
# 组合算子 VJP 专项测试
|
||||
python test/prim/prim/vjp/eager/test_comp_eager_sigmoid_grad.py
|
||||
```
|
||||
|
||||
## 动态 Shape 支持
|
||||
|
||||
组合算子在编译器场景下可能遇到动态 shape(编译期 shape 未知)。关键函数:
|
||||
|
||||
### has_dynamic_shape
|
||||
|
||||
```cpp
|
||||
bool has_dynamic_shape(const std::vector<int64_t>& shape) {
|
||||
return std::any_of(shape.begin(), shape.end(),
|
||||
[](int64_t s) { return s < 0; });
|
||||
}
|
||||
```
|
||||
|
||||
检查 shape 中是否包含负数维度(-1 表示动态维度)。
|
||||
|
||||
### backend::reshape 的 Tensor 重载
|
||||
|
||||
当 shape 是动态的,不能用 `std::vector<int64_t>` 传递 shape,而是用 `Tensor` 类型:
|
||||
|
||||
```cpp
|
||||
// 静态 shape
|
||||
auto out = paddle::reshape(x, {batch_size, seq_len, hidden_size});
|
||||
|
||||
// 动态 shape
|
||||
auto shape_tensor = paddle::shape(x); // 返回 Tensor
|
||||
auto out = paddle::backend::reshape(x, shape_tensor);
|
||||
```
|
||||
|
||||
开发组合算子时,需要检查输入是否有动态 shape,并选择合适的 API 版本。
|
||||
|
||||
## 调试方法
|
||||
|
||||
### 前向分解调试
|
||||
|
||||
```bash
|
||||
GLOG_vmodule=op_decomp=4 python test.py
|
||||
```
|
||||
|
||||
输出信息包含:被分解的算子名、分解产生的基础算子序列、中间 Tensor shape。
|
||||
|
||||
### 反向分解(VJP)调试
|
||||
|
||||
```bash
|
||||
GLOG_vmodule=generated_vjp=4 python test.py
|
||||
```
|
||||
|
||||
输出信息包含:VJP 调用链、梯度 Tensor 的 shape 和 dtype。
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **分解后精度下降**:检查是否需要 CustomVJP,避免数值不稳定的组合
|
||||
2. **动态 shape 报错**:检查分解实现中是否使用了 `has_dynamic_shape` 分支
|
||||
3. **未注册的分解规则**:确认对应 Op 已注册 `DecompInterface`
|
||||
|
||||
## 关键文件路径汇总
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h` | 前向分解规则实现 |
|
||||
| `paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h` | VJP 反向分解实现 |
|
||||
| `paddle/fluid/primitive/base/decomp_trans.cc` | `call_decomp_rule` / `call_decomp_vjp` 入口 |
|
||||
| `paddle/fluid/pir/dialect/operator/interface/decomp.h` | DecompInterface 接口定义 |
|
||||
| `paddle/fluid/pir/dialect/operator/interface/decomp_vjp.h` | DecompVjpInterface 接口定义 |
|
||||
| `paddle/fluid/pir/dialect/operator/interface/vjp.h` | VjpInterface 接口定义 |
|
||||
| `paddle/fluid/primitive/vjp_interface/vjp.h` | VJP 统一入口头文件 |
|
||||
| `paddle/fluid/primitive/vjp_interface/manual/manual_vjp.cc` | 手写 VJP 实现 |
|
||||
| `paddle/fluid/primitive/primitive/primitive.h` | 基础算子集声明 |
|
||||
| `paddle/fluid/primitive/codegen/decomp_vjp_gen.py` | VJP 代码生成器 |
|
||||
| `test/prim/` | 组合算子测试目录 |
|
||||
@@ -0,0 +1,144 @@
|
||||
# PHI Kernel 注册机制详解
|
||||
|
||||
## 概述
|
||||
|
||||
PHI kernel 的注册完全通过宏完成,利用 C++ 静态初始化机制在 `main()` 之前将所有 kernel 注册到 `KernelFactory` 单例中。本文档详细展开宏的展开链路、核心类和关键设计。
|
||||
|
||||
## 宏展开链路
|
||||
|
||||
用户侧调用从 `PD_REGISTER_KERNEL` 开始,逐步展开:
|
||||
|
||||
```
|
||||
PD_REGISTER_KERNEL(add, GPU, ALL_LAYOUT, phi::AddKernel, float, double, ...)
|
||||
└── _PD_REGISTER_KERNEL(add, GPU, ALL_LAYOUT, phi::AddKernel, ARGS_DEF, {}, float, double, ...)
|
||||
├── PD_STATIC_ASSERT_GLOBAL_NAMESPACE(...) // 编译期断言:必须在全局命名空间
|
||||
├── _PD_REGISTER_2TA_KERNEL(...) // Two-Template-Argument 变体
|
||||
│ └── PD_KERNEL_REGISTRAR_INIT(...)
|
||||
│ ├── PD_NARGS(float, double, ...) // 计算变参数量
|
||||
│ └── _PD_KERNEL_REGISTRAR_INIT_N(N, ...) // 按 N 展开
|
||||
│ └── _PD_CREATE_REGISTRAR_OBJECT(add, GPU, ALL_LAYOUT,
|
||||
│ phi::AddKernel, float, ADD_kernel_reg_0, ...)
|
||||
└── 为每个 DataType 创建一个 KernelRegistrar 静态对象
|
||||
```
|
||||
|
||||
### 关键宏说明
|
||||
|
||||
**`PD_STATIC_ASSERT_GLOBAL_NAMESPACE`**:使用 `static_assert` 确保宏在全局命名空间调用,否则编译报错。这是因为注册依赖静态初始化,放在函数或命名空间内会导致顺序不确定或遗漏。
|
||||
|
||||
**`PD_NARGS`**:利用可变参数宏技巧计算传入的 DataType 数量,最大支持约 15 个类型。展开结果用于选择对应的 `_PD_KERNEL_REGISTRAR_INIT_N` 版本。
|
||||
|
||||
**`_PD_CREATE_REGISTRAR_OBJECT`**:核心创建步骤,为每个 DataType 生成一个 `static KernelRegistrar` 对象。变量名通过拼接算子名、序号和后缀保证全局唯一。
|
||||
|
||||
## KernelRegistrar 类
|
||||
|
||||
`KernelRegistrar` 是实际执行注册的工具类,位于 `paddle/phi/core/kernel_registry.h`。
|
||||
|
||||
### 构造函数
|
||||
|
||||
```cpp
|
||||
KernelRegistrar(const char* kernel_name_cstr,
|
||||
BackendType backend,
|
||||
DataLayout data_layout,
|
||||
DataType dtype,
|
||||
KernelArgsParseFn args_parse_fn,
|
||||
ArgsDefFn args_def_fn,
|
||||
KernelFn kernel_fn,
|
||||
void* variadic_kernel_fn);
|
||||
```
|
||||
|
||||
参数说明:
|
||||
- `kernel_name_cstr`:算子名称字符串
|
||||
- `backend`, `data_layout`, `dtype`:构成 `KernelKey` 的三要素
|
||||
- `args_parse_fn`:由 `KernelArgsParseFunctor` 生成的参数解析函数
|
||||
- `args_def_fn`:用户自定义参数属性回调(即宏中的 `{}` body)
|
||||
- `kernel_fn`:kernel 函数指针(经 PHI_KERNEL 包装后的统一签名)
|
||||
- `variadic_kernel_fn`:原始函数指针,用于变参 kernel
|
||||
|
||||
### ConstructKernel() 方法
|
||||
|
||||
构造函数内部调用 `ConstructKernel()`,完成以下步骤:
|
||||
|
||||
1. 通过 `KernelFactory::Instance().InsertKernel()` 将 kernel 写入两级 map
|
||||
2. 调用 `args_parse_fn` 解析模板参数,填充 `Kernel` 对象的 `args_def` 列表
|
||||
3. 调用用户提供的 `args_def_fn`(如果非空),允许用户修改参数的 Backend 属性
|
||||
4. 设置 `kernel_fn` 和 `variadic_kernel_fn`
|
||||
|
||||
## KernelFactory 单例
|
||||
|
||||
```cpp
|
||||
class KernelFactory {
|
||||
static KernelFactory& Instance();
|
||||
|
||||
// 两级存储
|
||||
using KernelKeyMap = paddle::flat_hash_map<KernelKey, Kernel, KernelKey::Hash>;
|
||||
paddle::flat_hash_map<std::string, KernelKeyMap> kernels_;
|
||||
|
||||
// 核心方法
|
||||
void InsertKernel(const std::string& name, const KernelKey& key, const Kernel& kernel);
|
||||
const Kernel& SelectKernelOrThrowError(const std::string& name, const KernelKey& key) const;
|
||||
const KernelKeyMap* GetKernelKeyMap(const std::string& name) const;
|
||||
};
|
||||
```
|
||||
|
||||
- `InsertKernel()`:写入时如果 key 已存在会打印 warning 但仍覆盖(后注册的优先)
|
||||
- `SelectKernelOrThrowError()`:查找失败时抛出详细的 `phi::enforce` 异常,包含可用 kernel 列表
|
||||
|
||||
## KernelArgsParseFunctor
|
||||
|
||||
```cpp
|
||||
template <typename KernelFunc>
|
||||
struct KernelArgsParseFunctor;
|
||||
|
||||
template <typename Return, typename... Args>
|
||||
struct KernelArgsParseFunctor<Return (*)(Args...)> {
|
||||
static void Parse(const KernelKey& key, Kernel* kernel) {
|
||||
// 对每个 Args... 通过 type_traits 判断:
|
||||
// - const DenseTensor& → InputArgDef
|
||||
// - DenseTensor* → OutputArgDef
|
||||
// - const Scalar& → AttributeArgDef
|
||||
// - DataType / Place / ... → AttributeArgDef
|
||||
// 依次追加到 kernel->args_def 中
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
该模板元编程机制使得注册时不需要手动声明参数列表——编译器从 kernel 函数签名自动提取。
|
||||
|
||||
## PHI_KERNEL 与 PHI_VARIADIC_KERNEL
|
||||
|
||||
```cpp
|
||||
#define PHI_KERNEL(kernel_fn) \
|
||||
::phi::KernelImpl<decltype(&kernel_fn), &kernel_fn>::Compute
|
||||
```
|
||||
|
||||
`KernelImpl` 将具有具体参数签名的 kernel 函数包装成统一的 `void(KernelContext*)` 签名。运行时从 `KernelContext` 中按顺序取出 input / output / attribute,再调用真正的 kernel 函数。
|
||||
|
||||
`PHI_VARIADIC_KERNEL` 用于参数数量不固定的 kernel(如 `concat`),其内部使用 `std::vector<const DenseTensor*>` 接收变长输入。
|
||||
|
||||
## 用户自定义注册 Hook
|
||||
|
||||
宏展开中的 `{}` 占位符(即 `args_def_fn`)允许用户在注册时修改参数属性:
|
||||
|
||||
```cpp
|
||||
PD_REGISTER_KERNEL(my_kernel, GPU, ALL_LAYOUT, phi::MyKernel, float) {
|
||||
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
```
|
||||
|
||||
常见用途:
|
||||
- `SetBackend(ALL_BACKEND)`:声明输入不需要 TransDataPlace(接受任意 backend)
|
||||
- `SetDataType(...)`:固定某个输出的数据类型,不跟随 kernel dtype
|
||||
- `SetDataLayout(...)`:强制某个输入 / 输出的 layout
|
||||
|
||||
## 关键源码路径
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `paddle/phi/core/kernel_registry.h` | 所有注册宏定义 + KernelRegistrar |
|
||||
| `paddle/phi/core/kernel_factory.h` | KernelFactory、KernelKey、Kernel 类 |
|
||||
| `paddle/phi/core/kernel_factory.cc` | KernelFactory 实现 |
|
||||
| `paddle/phi/core/kernel_context.h` | KernelContext,运行时参数容器 |
|
||||
| `paddle/phi/kernels/elementwise_add_kernel.h` | 典型 kernel 头文件示例 |
|
||||
| `paddle/phi/kernels/kps/elementwise_kernel.cu` | 典型 GPU kernel 实现 |
|
||||
| `paddle/phi/kernels/cpu/elementwise_add_kernel.cc` | 典型 CPU kernel 注册示例 |
|
||||
@@ -0,0 +1,162 @@
|
||||
# Kernel 选择与分派机制
|
||||
|
||||
## 概述
|
||||
|
||||
Kernel 选择是从 `KernelFactory` 的两级 map 中,根据当前运行时的 Backend、DataLayout、DataType(统称 BLD)三要素找到最匹配的 `Kernel` 对象。Paddle 中存在三种执行模式,各自有不同的选择路径。
|
||||
|
||||
## 核心概念:BLD 三要素
|
||||
|
||||
```
|
||||
KernelKey = { Backend, DataLayout, DataType }
|
||||
```
|
||||
|
||||
- **Backend**:计算设备,如 CPU、GPU、GPUDNN(cuDNN)、XPU、OneDNN
|
||||
- **DataLayout**:数据排布,如 NCHW、NHWC、ANY(不限)
|
||||
- **DataType**:数据类型,如 FLOAT32、FLOAT16、BFLOAT16、INT64
|
||||
|
||||
Kernel 选择的本质是:根据输入 Tensor 的实际属性和算子声明的偏好,确定一个 `KernelKey`,再从 `KernelFactory` 中查找对应的 `Kernel`。
|
||||
|
||||
## 新动态图(Eager Mode)选择流程
|
||||
|
||||
入口:`api.cc` 中自动生成的 C++ API 函数(由 `api_gen.py` 生成)。
|
||||
|
||||
### 步骤 1:ParseKernelKeyByInputArgs
|
||||
|
||||
遍历所有输入 Tensor,取出它们的 Backend、Layout、DataType。对多个输入按优先级规则合并:
|
||||
- Backend:GPU > CPU(有任意 GPU 输入则选 GPU)
|
||||
- DataType:取第一个非 None 输入的 dtype
|
||||
- Layout:取第一个非 ANY 的 layout
|
||||
|
||||
### 步骤 2:YAML kernel 声明覆盖
|
||||
|
||||
`ops.yaml` 中的 `kernel` 字段可指定 `data_type`,例如:
|
||||
|
||||
```yaml
|
||||
- op: cast
|
||||
kernel:
|
||||
func: cast
|
||||
data_type: x # 强制以输入 x 的 dtype 作为 kernel dtype
|
||||
```
|
||||
|
||||
如果 YAML 指定了 `data_type`,则覆盖步骤 1 推断的 DataType。同理 `backend` 字段可覆盖 Backend。
|
||||
|
||||
### 步骤 3:GetHighestPriorityKernelKey
|
||||
|
||||
在确定初始 `KernelKey` 后,检查 `KernelFactory` 中实际注册了哪些 key,按以下 6 步 fallback 策略逐步降级:
|
||||
|
||||
```
|
||||
1. GPUDNN + 指定 layout → 精确匹配 cuDNN kernel
|
||||
2. GPUDNN + ALL_LAYOUT → cuDNN kernel,放宽 layout
|
||||
3. kernel_backend + layout → 目标 backend 精确匹配
|
||||
4. kernel_backend + ALL_LAYOUT → 目标 backend,放宽 layout
|
||||
5. CPU + layout → fallback 到 CPU
|
||||
6. CPU + ALL_LAYOUT → CPU 最宽松匹配
|
||||
```
|
||||
|
||||
如果 6 步都失败,调用 `SelectKernelOrThrowError` 抛出异常,打印所有已注册的 kernel key,帮助调试。
|
||||
|
||||
### 步骤 4:PrepareData(数据转换)
|
||||
|
||||
选定 kernel 后,需要将输入 Tensor 的实际属性对齐到 `KernelKey` 和 `Kernel::args_def` 要求的属性。通过 `TransformFlag` 控制是否执行以下转换:
|
||||
|
||||
| 转换 | 函数 | 场景 |
|
||||
|------|------|------|
|
||||
| 跨设备搬运 | `TransDataPlace()` | 输入在 CPU 但 kernel 在 GPU |
|
||||
| 数据类型转换 | `TransDataType()` | 输入 FP16 但 kernel 要求 FP32 |
|
||||
| Layout 转换 | `TransDataLayout()` | 输入 NCHW 但 kernel 要求 NHWC |
|
||||
|
||||
如果 `Kernel::args_def` 中某个输入标记了 `Backend::ALL_BACKEND`(通过注册 hook 设置),则跳过 `TransDataPlace`,允许输入留在任意设备。
|
||||
|
||||
## 老动态图(Legacy Eager)选择流程
|
||||
|
||||
入口:`PreparedOp::Prepare()`,位于 `paddle/fluid/imperative/prepared_operator.cc`。
|
||||
|
||||
### 步骤 1:GetExpectedKernelType
|
||||
|
||||
每个 `OperatorWithKernel` 子类可重写 `GetExpectedKernelType()`,返回期望的 `OpKernelType`(包含 place、data_type、data_layout)。默认实现取第一个输入的 dtype 和当前执行 place。
|
||||
|
||||
### 步骤 2:PHI 优先于 Fluid
|
||||
|
||||
```cpp
|
||||
if (phi::KernelFactory::Instance().HasCompatiblePhiKernel(op_type)) {
|
||||
// 使用 PHI kernel
|
||||
} else {
|
||||
// fallback 到 fluid OpKernel
|
||||
}
|
||||
```
|
||||
|
||||
`HasCompatiblePhiKernel()` 检查算子名称是否在 PHI KernelFactory 中注册。如果同时存在 PHI kernel 和 fluid OpKernel,优先使用 PHI。
|
||||
|
||||
### 步骤 3:kernel_type_for_var
|
||||
|
||||
对于特殊算子(如 `fill_constant`),其 `GetKernelTypeForVar()` 可为不同输入变量返回不同的期望 kernel type,用于精细控制 PrepareData 行为。
|
||||
|
||||
## 静态图(Static Graph)选择流程
|
||||
|
||||
入口:`OperatorWithKernel::RunImpl()`,位于 `paddle/fluid/framework/operator.cc`。
|
||||
|
||||
### 核心流程
|
||||
|
||||
```
|
||||
RunImpl()
|
||||
├── InferShape() // 形状推导
|
||||
├── GetExpectedKernelType() // 获取期望 BLD
|
||||
├── HasCompatiblePhiKernel() // 检查 PHI kernel 是否存在
|
||||
│ ├── Yes → ChoosePhiKernel() // 构造 KernelKey,查找 PHI kernel
|
||||
│ └── No → ChooseFluidKernel() // fallback fluid
|
||||
├── HandleComplexGradToRealGrad() // 复数特殊处理
|
||||
├── PrepareData() // 数据转换
|
||||
└── Run phi kernel / fluid kernel
|
||||
```
|
||||
|
||||
### ChoosePhiKernel
|
||||
|
||||
将 fluid 的 `OpKernelType` 转换为 PHI 的 `KernelKey`:
|
||||
- `OpKernelType.place_` → `Backend`
|
||||
- `OpKernelType.data_layout_` → `DataLayout`
|
||||
- `OpKernelType.data_type_` → `DataType`
|
||||
|
||||
然后调用 `KernelFactory::Instance().SelectKernel(name, key)`。
|
||||
|
||||
## YAML 字段与老框架的映射关系
|
||||
|
||||
| 老框架(fluid) | YAML 对应字段 | 说明 |
|
||||
|------------------|---------------|------|
|
||||
| `OpMaker` 类 | `ops.yaml` 整体 | 算子定义(输入、输出、属性) |
|
||||
| `InferShape()` | `infer_meta.func` | 形状推导函数 |
|
||||
| `GetExpectedKernelType()` | `kernel.data_type` / `kernel.backend` | kernel 选择偏好 |
|
||||
| `GradOpMaker` | `backward.yaml` | 反向算子定义 |
|
||||
| `OpKernel::Compute()` | `kernel.func` | kernel 函数名 |
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 打印 kernel 选择过程
|
||||
|
||||
```bash
|
||||
GLOG_vmodule=phi_kernel_adaptor=4 python test.py
|
||||
```
|
||||
|
||||
### 查看所有已注册 kernel
|
||||
|
||||
```python
|
||||
import paddle
|
||||
paddle.framework._phi_kernel_factory().get_all_kernel_names()
|
||||
```
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **"Cannot find kernel for xxx"**:检查 kernel 是否对目标 Backend + DataType 注册
|
||||
2. **数据类型不匹配**:检查 `ops.yaml` 中 `kernel.data_type` 的配置
|
||||
3. **多余的 TransDataPlace**:检查注册 hook 是否设置了 `ALL_BACKEND`
|
||||
4. **Layout 转换开销大**:检查是否有 NHWC 专用 kernel,避免 NCHW ↔ NHWC 转换
|
||||
|
||||
## 关键源码路径
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `paddle/phi/api/lib/api_gen_utils.cc` | ParseKernelKeyByInputArgs 等工具 |
|
||||
| `paddle/phi/core/kernel_factory.cc` | SelectKernelOrThrowError 实现 |
|
||||
| `paddle/fluid/imperative/prepared_operator.cc` | PreparedOp::Prepare(老动态图) |
|
||||
| `paddle/fluid/framework/operator.cc` | OperatorWithKernel::RunImpl(静态图) |
|
||||
| `paddle/phi/core/kernel_utils.h` | TransformFlag、PrepareData 相关 |
|
||||
| `paddle/phi/ops/yaml/ops.yaml` | 算子 YAML 定义 |
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
name: paddle-op-dev
|
||||
description: PaddlePaddle (飞桨) C++ 算子开发指南。提供从 YAML 配置、InferMeta 函数、Kernel 实现、Python API 封装、单元测试到编译验证的完整算子开发流程指导。在以下场景使用此 skill:(1) 为 Paddle 框架新增 C++ 算子 (2) 修改或调试已有 Paddle 算子 (3) 编写算子的 YAML 配置、InferMeta、Kernel、Python API 或单元测试 (4) 理解 Paddle 算子开发架构和流程 (5) 编译 Paddle 并验证算子正确性
|
||||
---
|
||||
|
||||
# Paddle 算子开发
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
Python API (paddle.xxx)
|
||||
│
|
||||
▼ (YAML 自动生成的调度代码)
|
||||
算子 InferMeta ──→ 推导输出 shape/dtype
|
||||
│
|
||||
▼
|
||||
算子 Kernel ──→ 实际计算(CPU/GPU 分别实现)
|
||||
```
|
||||
|
||||
YAML 配置是连接 Python API 与底层 Kernel 的桥梁,框架编译时自动生成调度代码。
|
||||
|
||||
## 开发流程
|
||||
|
||||
新增算子 `xxx` 需完成以下 6 步:
|
||||
|
||||
### 步骤 1:YAML 算子定义
|
||||
|
||||
在 `paddle/phi/ops/yaml/ops.yaml` 和 `backward.yaml` 中配置前向和反向算子。
|
||||
|
||||
关键配置项:`op`(名称)、`args`(输入)、`output`(输出)、`infer_meta`(推导函数)、`kernel`(计算函数)、`backward`(反向算子)。
|
||||
|
||||
快速示例:
|
||||
```yaml
|
||||
# ops.yaml
|
||||
- op: trace
|
||||
args: (Tensor x, int offset = 0, int axis1 = 0, int axis2 = 1)
|
||||
output: Tensor(out)
|
||||
infer_meta:
|
||||
func: TraceInferMeta
|
||||
kernel:
|
||||
func: trace
|
||||
backward: trace_grad
|
||||
```
|
||||
|
||||
详细配置规则见 [references/yaml-config.md](references/yaml-config.md)。
|
||||
|
||||
### 步骤 2:InferMeta 函数
|
||||
|
||||
在 `paddle/phi/infermeta/` 下实现,按输入 Tensor 个数分文件(unary/binary/multiary)。
|
||||
|
||||
职责:推导输出 shape 和 dtype,检查输入合法性。
|
||||
|
||||
函数签名模式:
|
||||
```cpp
|
||||
void XxxInferMeta(const MetaTensor& x, int attr, MetaTensor* out) {
|
||||
// PADDLE_ENFORCE_XX 检查输入
|
||||
out->set_dims(...);
|
||||
out->set_dtype(x.dtype());
|
||||
}
|
||||
```
|
||||
|
||||
详细规则和示例见 [references/infermeta.md](references/infermeta.md)。
|
||||
|
||||
### 步骤 3:Kernel 实现
|
||||
|
||||
在 `paddle/phi/kernels/` 下实现。设备无关的放根目录,设备相关的分 `cpu/` 和 `gpu/` 子目录。
|
||||
|
||||
文件结构:
|
||||
- `xxx_kernel.h` — 前向声明
|
||||
- `cpu/xxx_kernel.cc` / `gpu/xxx_kernel.cu` — 设备实现
|
||||
- `xxx_grad_kernel.h` + 对应设备实现 — 反向
|
||||
|
||||
Kernel 函数模式:
|
||||
```cpp
|
||||
template <typename T, typename Context>
|
||||
void XxxKernel(const Context& dev_ctx, const DenseTensor& x,
|
||||
int attr, DenseTensor* out) {
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
// 计算逻辑
|
||||
}
|
||||
// 注册
|
||||
PD_REGISTER_KERNEL(xxx, CPU, ALL_LAYOUT, phi::XxxKernel, float, double) {}
|
||||
```
|
||||
|
||||
**参考 PyTorch 实现**:Paddle 算子的计算逻辑与 PyTorch (ATen) 往往相似。实现 Kernel 时可参考 PyTorch 对应算子的实现(位于 `aten/src/ATen/native/` 目录),理解核心算法后适配为 Paddle 的 API 风格(DenseTensor、dev_ctx 等)。注意不要直接复制代码,需根据 Paddle 框架规范进行适配。
|
||||
|
||||
详细规则和示例见 [references/kernel-dev.md](references/kernel-dev.md)。
|
||||
|
||||
### 步骤 4:Python API 封装
|
||||
|
||||
在 `python/paddle/` 对应子目录中实现 Python API。
|
||||
|
||||
关键要素:
|
||||
- 动态图:`_C_ops.xxx(args...)`
|
||||
- 静态图:`LayerHelper` + `append_op`
|
||||
- 完整的 docstring(含可运行的 Examples)
|
||||
|
||||
详细规则和示例见 [references/python-api.md](references/python-api.md)。
|
||||
|
||||
### 步骤 5:单元测试
|
||||
|
||||
在 `test/legacy_test/test_xxx_op.py` 中编写,继承 `OpTest`。
|
||||
|
||||
测试要点:
|
||||
- `setUp()` 设置 `op_type`、`python_api`、`inputs`、`attrs`、`outputs`
|
||||
- `test_check_output(check_pir=True)` 验证前向
|
||||
- `test_check_grad(['X'], 'Out', check_pir=True)` 验证反向
|
||||
- 多 Case 继承基类重写 `init_config()`
|
||||
|
||||
详细规则和示例见 [references/unit-test.md](references/unit-test.md)。
|
||||
|
||||
### 步骤 6:编译与验证
|
||||
|
||||
完成代码开发后,需要编译 Paddle 并运行测试来验证算子的正确性。
|
||||
|
||||
#### 6.1 增量编译
|
||||
|
||||
在 Paddle 的 `build` 目录下执行增量编译。新增算子通常只需重新编译 phi 相关目标,无需全量编译。
|
||||
|
||||
```bash
|
||||
cd build
|
||||
|
||||
# 增量编译(推荐使用 ninja,速度更快)
|
||||
ninja -j$(nproc)
|
||||
|
||||
# 或使用 make
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
如果只修改了 Kernel/InferMeta 等 C++ 文件,可以缩小编译范围:
|
||||
|
||||
```bash
|
||||
# 只编译 phi 库(覆盖 Kernel + InferMeta)
|
||||
ninja phi -j$(nproc)
|
||||
|
||||
# 编译完成后重新安装 Python 包
|
||||
pip install -e . --no-build-isolation
|
||||
# 或
|
||||
cd python && pip install -e .
|
||||
```
|
||||
|
||||
#### 6.2 运行单元测试
|
||||
|
||||
```bash
|
||||
# 方式 1:直接运行测试文件
|
||||
python test/legacy_test/test_xxx_op.py
|
||||
|
||||
# 方式 2:使用 pytest(支持更灵活的筛选)
|
||||
python -m pytest test/legacy_test/test_xxx_op.py -v
|
||||
|
||||
# 方式 3:通过 ctest 运行(在 build 目录下)
|
||||
cd build && ctest -R test_xxx_op -V
|
||||
```
|
||||
|
||||
#### 6.3 验证要点
|
||||
|
||||
- **前向正确性**:`test_check_output` 通过,算子输出与 NumPy 参考实现一致
|
||||
- **反向正确性**:`test_check_grad` 通过,梯度通过数值微分法校验
|
||||
- **PIR 模式**:确认 `check_pir=True` 下测试通过
|
||||
- **多设备验证**:有 GPU 环境时确认 CPU 和 GPU 结果一致
|
||||
|
||||
#### 6.4 GPU 算子调试
|
||||
|
||||
GPU 算子出现 CUDA 错误时,使用以下环境变量辅助定位:
|
||||
|
||||
```bash
|
||||
# 启用 CUDA 同步错误检查 + 系统内存分配器
|
||||
FLAGS_check_cuda_error=1 FLAGS_use_system_allocator=1 python test/legacy_test/test_xxx_op.py
|
||||
|
||||
# 强制 CUDA kernel 同步执行,定位出错的 kernel
|
||||
CUDA_LAUNCH_BLOCKING=1 python test/legacy_test/test_xxx_op.py
|
||||
```
|
||||
|
||||
常见问题:
|
||||
- `CUDA error(9)` — kernel 配置无效,检查 grid/block size 是否为 0(通常由空 Tensor 触发)
|
||||
- `CUDA error(700)` — 非法内存访问,检查数组越界或空指针
|
||||
- `CUDA error(2)` — 显存不足,减小测试数据规模或检查是否有显存泄漏
|
||||
|
||||
#### 6.5 常见编译错误排查
|
||||
|
||||
| 现象 | 排查方向 |
|
||||
|---|---|
|
||||
| 找不到 `XxxInferMeta` 符号 | 检查 InferMeta 函数是否在 `.h` 中声明、YAML 中函数名是否拼写一致 |
|
||||
| 找不到 `xxx` kernel | 检查 `PD_REGISTER_KERNEL` 注册名是否与 YAML `kernel:func` 一致 |
|
||||
| Python 端 `_C_ops.xxx` 不存在 | 确认 YAML 配置正确且已重新编译,`pip install -e .` 已执行 |
|
||||
| 参数数量不匹配 | 对照 YAML `args` 与 InferMeta/Kernel 函数签名的参数列表 |
|
||||
|
||||
## 文件清单速查
|
||||
|
||||
| 内容 | 文件位置 |
|
||||
|---|---|
|
||||
| 前向 YAML | `paddle/phi/ops/yaml/ops.yaml` |
|
||||
| 反向 YAML | `paddle/phi/ops/yaml/backward.yaml` |
|
||||
| InferMeta | `paddle/phi/infermeta/{unary,binary,multiary}.{h,cc}` |
|
||||
| Kernel 头文件 | `paddle/phi/kernels/xxx_kernel.h` |
|
||||
| CPU Kernel | `paddle/phi/kernels/cpu/xxx_kernel.cc` |
|
||||
| GPU Kernel | `paddle/phi/kernels/gpu/xxx_kernel.cu` |
|
||||
| Python API | `python/paddle/` 对应子目录 |
|
||||
| 单元测试 | `test/legacy_test/test_xxx_op.py` |
|
||||
|
||||
## 显存优化
|
||||
|
||||
- **inplace**:输出复用输入显存,YAML 中配置 `inplace: (x -> out)`
|
||||
- **no_need_buffer**:反向不需要前向变量的内存数据时配置,提前释放内存
|
||||
- **减少反向无关变量**:反向 args 中只包含实际需要的前向变量
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [官方文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/dev_guides/api_contributing_guides/new_cpp_op_cn.html)
|
||||
@@ -0,0 +1,139 @@
|
||||
# InferMeta 函数开发
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [开发规则](#开发规则)
|
||||
- [函数签名约定](#函数签名约定)
|
||||
- [常用 InferMeta 函数](#常用-infermeta-函数)
|
||||
- [TraceInferMeta 完整示例](#traceinfermeta-完整示例)
|
||||
|
||||
## 概述
|
||||
|
||||
InferMeta 函数在 Kernel 前执行,根据输入参数推断输出 Tensor 的 `shape` 和 `data type`,同时检查输入数据维度、类型等合法性。每个算子只需实现一个 InferMeta 函数(不区分硬件设备)。
|
||||
|
||||
## 开发规则
|
||||
|
||||
1. **命名**:`XxxInferMeta`
|
||||
2. **文件位置**:`paddle/phi/infermeta/` 目录,按输入 Tensor 个数分类:
|
||||
- `nullary.h/cc`:无输入 Tensor
|
||||
- `unary.h/cc`:单输入 Tensor
|
||||
- `binary.h/cc`:双输入 Tensor
|
||||
- `ternary.h/cc`:三输入 Tensor
|
||||
- `multiary.h/cc`:更多输入 Tensor
|
||||
3. **头文件声明**:在对应的 `.h` 文件中声明
|
||||
4. **输入合法性检查**:使用 `PADDLE_ENFORCE_XX` 宏
|
||||
5. **输出设置**:调用 `out->set_dims()` 和 `out->set_dtype()`
|
||||
|
||||
## 函数签名约定
|
||||
|
||||
```cpp
|
||||
void XxxInferMeta(
|
||||
const MetaTensor& input_tensor, // Tensor 输入用 const MetaTensor&
|
||||
int attr1, // 属性用对应 C++ 类型
|
||||
float attr2,
|
||||
MetaTensor* out // 输出用 MetaTensor* 指针
|
||||
);
|
||||
```
|
||||
|
||||
参数列表与 YAML 配置中的 `args` 对应:
|
||||
- `Tensor` -> `const MetaTensor&`
|
||||
- `Tensor[]` -> `const std::vector<const MetaTensor*>&`
|
||||
- `int`, `float`, `bool` 等 -> 直接使用对应 C++ 类型
|
||||
- `int[]` -> `const std::vector<int>&`
|
||||
- `IntArray` -> `const IntArray&`
|
||||
- `Scalar` -> `const Scalar&`
|
||||
- 输出 `Tensor` -> `MetaTensor*`
|
||||
- 输出 `Tensor[]` -> `std::vector<MetaTensor*>`
|
||||
|
||||
## 常用 InferMeta 函数
|
||||
|
||||
以下 InferMeta 函数可直接复用,无需重新实现:
|
||||
|
||||
| 函数名 | 说明 |
|
||||
|---|---|
|
||||
| `UnchangedInferMeta` | 输出与输入有相同 shape 和 dtype |
|
||||
| `UnchangedInferMetaCheckAxis` | 类似上面,额外检查 axis |
|
||||
| `GeneralUnaryGradInferMeta` | 通用一元反向算子 |
|
||||
| `GeneralBinaryGradInferMeta` | 通用二元反向算子 |
|
||||
|
||||
## PADDLE_ENFORCE 宏
|
||||
|
||||
```cpp
|
||||
// 常用检查宏
|
||||
PADDLE_ENFORCE_EQ(a, b, common::errors::InvalidArgument("..."));
|
||||
PADDLE_ENFORCE_NE(a, b, common::errors::InvalidArgument("..."));
|
||||
PADDLE_ENFORCE_GT(a, b, common::errors::InvalidArgument("..."));
|
||||
PADDLE_ENFORCE_GE(a, b, common::errors::InvalidArgument("..."));
|
||||
PADDLE_ENFORCE_LT(a, b, common::errors::OutOfRange("..."));
|
||||
PADDLE_ENFORCE_LE(a, b, common::errors::OutOfRange("..."));
|
||||
```
|
||||
|
||||
## TraceInferMeta 完整示例
|
||||
|
||||
文件:`paddle/phi/infermeta/unary.cc`
|
||||
|
||||
```cpp
|
||||
void TraceInferMeta(
|
||||
const MetaTensor& x,
|
||||
int offset,
|
||||
int axis1,
|
||||
int axis2,
|
||||
MetaTensor* out) {
|
||||
int dim1 = axis1;
|
||||
int dim2 = axis2;
|
||||
|
||||
auto x_dims = x.dims();
|
||||
|
||||
int dim1_ = dim1 < 0 ? x_dims.size() + dim1 : dim1;
|
||||
int dim2_ = dim2 < 0 ? x_dims.size() + dim2 : dim2;
|
||||
|
||||
// 检查输入维度 >= 2
|
||||
PADDLE_ENFORCE_GE(
|
||||
x_dims.size(), 2,
|
||||
common::errors::OutOfRange(
|
||||
"Input(x)'s dim is out of range (expected at least 2, but got %ld).",
|
||||
x_dims.size()));
|
||||
|
||||
// 检查 axis1 范围
|
||||
PADDLE_ENFORCE_LT(
|
||||
dim1_, x_dims.size(),
|
||||
common::errors::OutOfRange(
|
||||
"axis1 is out of range (expected to be in range of [%ld, %ld], but got %ld).",
|
||||
-(x_dims.size()), (x_dims.size() - 1), dim1));
|
||||
PADDLE_ENFORCE_GE(
|
||||
dim1_, 0,
|
||||
common::errors::OutOfRange(
|
||||
"axis1 is out of range (expected to be in range of [%ld, %ld], but got %ld).",
|
||||
-(x_dims.size()), (x_dims.size() - 1), dim1));
|
||||
|
||||
// 检查 axis2 范围
|
||||
PADDLE_ENFORCE_LT(
|
||||
dim2_, x_dims.size(),
|
||||
common::errors::OutOfRange(
|
||||
"axis2 is out of range (expected to be in range of [%ld, %ld], but got %ld).",
|
||||
-(x_dims.size()), (x_dims.size() - 1), dim2));
|
||||
PADDLE_ENFORCE_GE(
|
||||
dim2_, 0,
|
||||
common::errors::OutOfRange(
|
||||
"axis2 is out of range (expected to be in range of [%ld, %ld], but got %ld).",
|
||||
-(x_dims.size()), (x_dims.size() - 1), dim2));
|
||||
|
||||
// axis1 != axis2
|
||||
PADDLE_ENFORCE_NE(
|
||||
dim1_, dim2_,
|
||||
common::errors::InvalidArgument(
|
||||
"The dimensions should not be identical %d vs %d.", dim1, dim2));
|
||||
|
||||
// 推导输出维度
|
||||
auto sizes = common::vectorize(x_dims);
|
||||
if (x_dims.size() == 2) {
|
||||
sizes.clear();
|
||||
sizes.push_back(1);
|
||||
} else {
|
||||
sizes.erase(sizes.begin() + std::max(dim1_, dim2_));
|
||||
sizes.erase(sizes.begin() + std::min(dim1_, dim2_));
|
||||
}
|
||||
out->set_dims(common::make_ddim(sizes));
|
||||
out->set_dtype(x.dtype());
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,265 @@
|
||||
# 算子 Kernel 开发
|
||||
|
||||
## 目录
|
||||
- [目录结构](#目录结构)
|
||||
- [Kernel 函数签名](#kernel-函数签名)
|
||||
- [Kernel 注册](#kernel-注册)
|
||||
- [头文件示例](#头文件示例)
|
||||
- [CPU Kernel 示例](#cpu-kernel-示例)
|
||||
- [GPU Kernel 示例](#gpu-kernel-示例)
|
||||
- [反向 Kernel](#反向-kernel)
|
||||
- [开发注意事项](#开发注意事项)
|
||||
|
||||
## 目录结构
|
||||
|
||||
Kernel 在 `paddle/phi/kernels` 目录下开发。
|
||||
|
||||
### 设备无关的 Kernel(如 reshape)
|
||||
|
||||
```
|
||||
paddle/phi/kernels/
|
||||
├── xxx_kernel.h
|
||||
├── xxx_kernel.cc
|
||||
├── xxx_grad_kernel.h
|
||||
└── xxx_grad_kernel.cc
|
||||
```
|
||||
|
||||
### 设备相关、CPU & GPU 分别实现的 Kernel(如 trace)
|
||||
|
||||
```
|
||||
paddle/phi/kernels/
|
||||
├── xxx_kernel.h # 前向声明
|
||||
├── cpu/xxx_kernel.cc # CPU 前向实现
|
||||
├── gpu/xxx_kernel.cu # GPU 前向实现
|
||||
├── xxx_grad_kernel.h # 反向声明
|
||||
├── cpu/xxx_grad_kernel.cc # CPU 反向实现
|
||||
└── gpu/xxx_grad_kernel.cu # GPU 反向实现
|
||||
```
|
||||
|
||||
## Kernel 函数签名
|
||||
|
||||
```cpp
|
||||
template <typename T, typename Context>
|
||||
void XxxKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input, // Tensor 输入
|
||||
int attr1, // 属性输入
|
||||
DenseTensor* out); // 输出
|
||||
```
|
||||
|
||||
参数映射:
|
||||
- `Tensor` -> `const DenseTensor&`
|
||||
- `Tensor[]` -> `const std::vector<const DenseTensor*>&`
|
||||
- 属性类型直接使用对应 C++ 类型
|
||||
- 输出 `Tensor` -> `DenseTensor*`
|
||||
- 输出 `Tensor[]` -> `std::vector<DenseTensor*>`
|
||||
- 第一个参数始终为 `const Context& dev_ctx`
|
||||
|
||||
## Kernel 注册
|
||||
|
||||
使用 `PD_REGISTER_KERNEL` 宏注册 Kernel:
|
||||
|
||||
```cpp
|
||||
PD_REGISTER_KERNEL(
|
||||
kernel_name, // kernel 注册名,与 YAML 中 kernel:func 一致
|
||||
backend, // 后端:CPU, GPU 等
|
||||
layout, // 布局:ALL_LAYOUT
|
||||
kernel_fn, // kernel 函数
|
||||
data_types... // 支持的数据类型
|
||||
) {}
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```cpp
|
||||
// CPU 注册
|
||||
PD_REGISTER_KERNEL(
|
||||
trace, CPU, ALL_LAYOUT, phi::TraceKernel, float, double, int, int64_t, phi::dtype::complex<float>, phi::dtype::complex<double>
|
||||
) {}
|
||||
|
||||
// GPU 注册
|
||||
PD_REGISTER_KERNEL(
|
||||
trace, GPU, ALL_LAYOUT, phi::TraceKernel, float, double, int, int64_t, phi::dtype::complex<float>, phi::dtype::complex<double>
|
||||
) {}
|
||||
```
|
||||
|
||||
## 头文件示例
|
||||
|
||||
文件:`paddle/phi/kernels/trace_kernel.h`
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void TraceKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int offset,
|
||||
int axis1,
|
||||
int axis2,
|
||||
DenseTensor* out);
|
||||
|
||||
} // namespace phi
|
||||
```
|
||||
|
||||
## CPU Kernel 示例
|
||||
|
||||
文件:`paddle/phi/kernels/cpu/trace_kernel.cc`
|
||||
|
||||
```cpp
|
||||
#include "paddle/phi/kernels/trace_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/cpu/cpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
// 其他需要的头文件...
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void TraceKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int offset,
|
||||
int axis1,
|
||||
int axis2,
|
||||
DenseTensor* out) {
|
||||
// 分配输出内存
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
// 实现计算逻辑...
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
// 注册 CPU Kernel
|
||||
PD_REGISTER_KERNEL(
|
||||
trace, CPU, ALL_LAYOUT, phi::TraceKernel,
|
||||
float, double, int, int64_t,
|
||||
phi::dtype::complex<float>, phi::dtype::complex<double>
|
||||
) {}
|
||||
```
|
||||
|
||||
## GPU Kernel 示例
|
||||
|
||||
文件:`paddle/phi/kernels/gpu/trace_kernel.cu`
|
||||
|
||||
```cpp
|
||||
#include "paddle/phi/kernels/trace_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
// 其他需要的头文件...
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void TraceKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int offset,
|
||||
int axis1,
|
||||
int axis2,
|
||||
DenseTensor* out) {
|
||||
// 分配输出内存
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
// GPU 计算逻辑(CUDA kernel 调用等)...
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
// 注册 GPU Kernel
|
||||
PD_REGISTER_KERNEL(
|
||||
trace, GPU, ALL_LAYOUT, phi::TraceKernel,
|
||||
float, double, int, int64_t,
|
||||
phi::dtype::complex<float>, phi::dtype::complex<double>
|
||||
) {}
|
||||
```
|
||||
|
||||
## 反向 Kernel
|
||||
|
||||
### 头文件 `trace_grad_kernel.h`
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void TraceGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& out_grad,
|
||||
int offset,
|
||||
int axis1,
|
||||
int axis2,
|
||||
DenseTensor* x_grad);
|
||||
|
||||
} // namespace phi
|
||||
```
|
||||
|
||||
### 注册反向 Kernel
|
||||
|
||||
```cpp
|
||||
PD_REGISTER_KERNEL(
|
||||
trace_grad, CPU, ALL_LAYOUT, phi::TraceGradKernel,
|
||||
float, double, int, int64_t,
|
||||
phi::dtype::complex<float>, phi::dtype::complex<double>
|
||||
) {}
|
||||
```
|
||||
|
||||
## 参考 PyTorch 实现
|
||||
|
||||
Paddle 与 PyTorch 的算子在数学逻辑上往往一致,实现 Kernel 时可参考 PyTorch 的对应实现来加速开发。
|
||||
|
||||
### PyTorch 算子源码位置
|
||||
|
||||
| 类型 | PyTorch 路径 |
|
||||
|---|---|
|
||||
| CPU Kernel | `aten/src/ATen/native/xxx.cpp` |
|
||||
| GPU Kernel | `aten/src/ATen/native/cuda/xxx.cu` |
|
||||
| 算子注册 | `aten/src/ATen/native/native_functions.yaml` |
|
||||
| 数学工具 | `aten/src/ATen/native/Math.h` |
|
||||
|
||||
### 参考流程
|
||||
|
||||
1. 在 PyTorch 的 `native_functions.yaml` 中找到目标算子的声明
|
||||
2. 根据 `dispatch` 字段定位 CPU/GPU 实现文件
|
||||
3. 理解核心算法逻辑,尤其是边界处理和数值稳定性技巧
|
||||
4. 用 Paddle 的 API 风格重写(`DenseTensor`、`dev_ctx.template Alloc<T>(out)` 等)
|
||||
|
||||
### 适配差异对照
|
||||
|
||||
| PyTorch | Paddle |
|
||||
|---|---|
|
||||
| `at::Tensor` | `phi::DenseTensor` |
|
||||
| `tensor.data_ptr<T>()` | `tensor.data<T>()` |
|
||||
| `tensor.numel()` | `tensor.numel()` |
|
||||
| `tensor.dim()` | `tensor.dims().size()` |
|
||||
| `tensor.size(i)` | `tensor.dims()[i]` |
|
||||
| `tensor.stride(i)` | `tensor.strides()[i]` |
|
||||
| `TORCH_CHECK(...)` | `PADDLE_ENFORCE_XX(...)` |
|
||||
| `at::parallel_for` | `phi::funcs::ForRange` |
|
||||
| CUDA: `AT_DISPATCH_FLOATING_TYPES` | 通过 `PD_REGISTER_KERNEL` 模板参数指定 |
|
||||
|
||||
### 注意事项
|
||||
|
||||
- 不要直接复制 PyTorch 代码,需理解算法后用 Paddle 规范重写
|
||||
- 注意 license 合规,Paddle 使用 Apache 2.0,PyTorch 使用 BSD-style
|
||||
- PyTorch 的某些优化(如 vectorized kernel)可能需要用 Paddle 自身的工具函数替代
|
||||
- 反向 Kernel 的梯度计算公式可直接参考 PyTorch 的 `derivatives.yaml` 和对应 `_backward` 实现
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
1. **内存分配**:Kernel 中使用 `dev_ctx.template Alloc<T>(out)` 分配输出内存
|
||||
2. **命名规范**:
|
||||
- Kernel 函数:`XxxKernel`(大驼峰)
|
||||
- 反向 Kernel 函数:`XxxGradKernel`
|
||||
- 注册名与 YAML 中 `kernel:func` 一致(全小写+下划线)
|
||||
3. **头文件 include**:
|
||||
- CPU:`paddle/phi/backends/cpu/cpu_context.h`
|
||||
- GPU:`paddle/phi/backends/gpu/gpu_context.h`
|
||||
- 注册宏:`paddle/phi/core/kernel_registry.h`
|
||||
4. **常用数据类型**:`float`, `double`, `int`, `int64_t`, `phi::dtype::float16`, `phi::dtype::bfloat16`, `phi::dtype::complex<float>`, `phi::dtype::complex<double>`
|
||||
5. **复用 functor**:如果 CPU 和 GPU 共享部分逻辑,可在 `paddle/phi/kernels/funcs/` 中实现 functor
|
||||
@@ -0,0 +1,119 @@
|
||||
# Python API 封装
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [API 放置位置](#api-放置位置)
|
||||
- [API 实现规范](#api-实现规范)
|
||||
- [trace API 完整示例](#trace-api-完整示例)
|
||||
- [注册到公开接口](#注册到公开接口)
|
||||
|
||||
## 概述
|
||||
|
||||
Python API 是用户直接使用的接口(如 `paddle.trace()`),底层调用 C++ 算子。API 需要完成:参数检查与处理、调用底层 C++ 算子、编写规范的 docstring。
|
||||
|
||||
## API 放置位置
|
||||
|
||||
- 文件位置:`python/paddle/` 目录下的相应子目录
|
||||
- 遵循相似功能放在同一文件夹的原则
|
||||
- 例如 `trace` 属于数学运算,放在 `python/paddle/tensor/math.py`
|
||||
|
||||
## API 实现规范
|
||||
|
||||
### 函数签名
|
||||
|
||||
```python
|
||||
def xxx(input, param1, param2=default_value, name=None):
|
||||
```
|
||||
|
||||
### 必要内容
|
||||
|
||||
1. **参数检查**:验证参数类型和值的合法性
|
||||
2. **动态图/静态图兼容**:使用 `in_dynamic_or_pir_mode()` 判断
|
||||
3. **调用底层算子**:
|
||||
- 动态图:`_C_ops.xxx(args...)`
|
||||
- 静态图:创建 `LayerHelper`,使用 `helper.create_variable_for_type_inference()` 和 `helper.append_op()`
|
||||
4. **docstring**:包含功能描述、参数说明、返回值、代码示例
|
||||
|
||||
### 调用底层算子的方式
|
||||
|
||||
```python
|
||||
from paddle import _C_ops
|
||||
|
||||
# 动态图模式直接调用
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.op_name(args...)
|
||||
```
|
||||
|
||||
```python
|
||||
# 静态图模式
|
||||
helper = LayerHelper('op_name', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=input.dtype)
|
||||
helper.append_op(
|
||||
type='op_name',
|
||||
inputs={'X': input},
|
||||
outputs={'Out': out},
|
||||
attrs={'attr1': value1}
|
||||
)
|
||||
return out
|
||||
```
|
||||
|
||||
## trace API 完整示例
|
||||
|
||||
文件:`python/paddle/tensor/math.py`
|
||||
|
||||
```python
|
||||
def trace(x, offset=0, axis1=0, axis2=1, name=None):
|
||||
"""
|
||||
Computes the sum along diagonals of the input tensor x.
|
||||
|
||||
If ``x`` is 2D, returns the sum of diagonal.
|
||||
If ``x`` has larger dimensions, then returns an tensor of diagonals sum, diagonals be taken from
|
||||
the 2D planes specified by axis1 and axis2.
|
||||
|
||||
Args:
|
||||
x (Tensor): The input tensor x. Must be at least 2-dimensional. The input data type should be
|
||||
float32, float64, int32, int64.
|
||||
offset (int, optional): Which diagonals in input tensor x will be taken. Default: 0 (main diagonals).
|
||||
axis1 (int, optional): The first axis with respect to take diagonal. Default: 0.
|
||||
axis2 (int, optional): The second axis with respect to take diagonal. Default: 1.
|
||||
name (str, optional): Name for the operation. Default: None.
|
||||
|
||||
Returns:
|
||||
Tensor: the output data type is the same as input data type.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
>>> import paddle
|
||||
>>> x = paddle.to_tensor([[1, 2, 3],
|
||||
... [4, 5, 6],
|
||||
... [7, 8, 9]])
|
||||
>>> out = paddle.trace(x)
|
||||
>>> print(out)
|
||||
Tensor(shape=[], dtype=int64, place=Place(cpu), stop_gradient=True,
|
||||
15)
|
||||
"""
|
||||
if in_dynamic_or_pir_mode():
|
||||
return _C_ops.trace(x, offset, axis1, axis2)
|
||||
else:
|
||||
inputs = {'Input': [x]}
|
||||
attrs = {'offset': offset, 'axis1': axis1, 'axis2': axis2}
|
||||
helper = LayerHelper('trace', **locals())
|
||||
out = helper.create_variable_for_type_inference(dtype=x.dtype)
|
||||
helper.append_op(
|
||||
type='trace',
|
||||
inputs={'Input': x},
|
||||
outputs={'Out': out},
|
||||
attrs=attrs,
|
||||
)
|
||||
return out
|
||||
```
|
||||
|
||||
## 注册到公开接口
|
||||
|
||||
API 实现后,需在 `python/paddle/__init__.py` 或对应模块的 `__init__.py` 中导出,使用户可以通过 `paddle.xxx()` 调用。
|
||||
|
||||
注意事项:
|
||||
- `name` 参数在所有 API 中均为可选,用于调试
|
||||
- docstring 中的 Examples 必须可运行(会被 CI 自动测试)
|
||||
- 参数类型和默认值需与 YAML 配置一致
|
||||
@@ -0,0 +1,193 @@
|
||||
# 单元测试开发
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [测试文件位置](#测试文件位置)
|
||||
- [测试框架 OpTest](#测试框架-optest)
|
||||
- [前向测试](#前向测试)
|
||||
- [反向测试](#反向测试)
|
||||
- [完整测试示例](#完整测试示例)
|
||||
- [测试运行方式](#测试运行方式)
|
||||
- [注意事项](#注意事项)
|
||||
|
||||
## 概述
|
||||
|
||||
新增算子需要在 `test/legacy_test` 目录下添加单元测试,使用 `OpTest` 框架验证算子前向计算和反向梯度的正确性。
|
||||
|
||||
## 测试文件位置
|
||||
|
||||
```
|
||||
test/legacy_test/test_xxx_op.py
|
||||
```
|
||||
|
||||
## 测试框架 OpTest
|
||||
|
||||
继承 `OpTest` 基类来编写算子测试。
|
||||
|
||||
```python
|
||||
from paddle.base import core
|
||||
from paddle.base.tests.unittests.op_test import OpTest
|
||||
import unittest
|
||||
import numpy as np
|
||||
```
|
||||
|
||||
### OpTest 基本结构
|
||||
|
||||
```python
|
||||
class TestXxxOp(OpTest):
|
||||
def setUp(self):
|
||||
self.op_type = "xxx" # 算子名
|
||||
self.python_api = paddle.xxx # 对应的 Python API
|
||||
self.init_config()
|
||||
# 设置输入
|
||||
self.inputs = {
|
||||
'X': np.random.random((3, 4)).astype("float64"),
|
||||
}
|
||||
# 设置属性
|
||||
self.attrs = {
|
||||
'attr1': value1,
|
||||
}
|
||||
# 设置期望输出
|
||||
self.outputs = {
|
||||
'Out': expected_output,
|
||||
}
|
||||
|
||||
def test_check_output(self):
|
||||
self.check_output(check_pir=True)
|
||||
|
||||
def test_check_grad(self):
|
||||
self.check_grad(['X'], 'Out', check_pir=True)
|
||||
```
|
||||
|
||||
## 前向测试
|
||||
|
||||
`check_output()` 验证 C++ 算子前向计算结果与 Python/NumPy 参考实现的一致性。
|
||||
|
||||
```python
|
||||
def test_check_output(self):
|
||||
self.check_output(check_pir=True)
|
||||
```
|
||||
|
||||
- `check_pir=True`:同时检验 PIR 模式下的输出正确性
|
||||
|
||||
## 反向测试
|
||||
|
||||
`check_grad()` 验证反向梯度计算的正确性(通过数值微分法)。
|
||||
|
||||
```python
|
||||
def test_check_grad(self):
|
||||
self.check_grad(
|
||||
['X'], # 需要检查梯度的输入列表
|
||||
'Out', # 对应的输出名
|
||||
check_pir=True
|
||||
)
|
||||
```
|
||||
|
||||
- 输入数据建议使用 `float64` 类型以保证数值微分精度
|
||||
- 如果某些输入不需要检查梯度,可使用 `no_grad_set` 参数
|
||||
|
||||
```python
|
||||
def test_check_grad_no_x(self):
|
||||
self.check_grad(
|
||||
['Y'], 'Out',
|
||||
no_grad_set=set("X"),
|
||||
check_pir=True
|
||||
)
|
||||
```
|
||||
|
||||
## 完整测试示例
|
||||
|
||||
以 trace 算子为例(`test/legacy_test/test_trace_op.py`):
|
||||
|
||||
```python
|
||||
import unittest
|
||||
import numpy as np
|
||||
import paddle
|
||||
from paddle.base import core
|
||||
from paddle.base.tests.unittests.op_test import OpTest
|
||||
|
||||
|
||||
class TestTraceOp(OpTest):
|
||||
def setUp(self):
|
||||
self.op_type = "trace"
|
||||
self.python_api = paddle.trace
|
||||
self.init_config()
|
||||
|
||||
def init_config(self):
|
||||
self.case = np.random.randn(20, 6).astype('float64')
|
||||
self.inputs = {'Input': self.case}
|
||||
self.attrs = {'offset': 0, 'axis1': 0, 'axis2': 1}
|
||||
self.outputs = {
|
||||
'Out': np.trace(self.inputs['Input'],
|
||||
offset=self.attrs['offset'],
|
||||
axis1=self.attrs['axis1'],
|
||||
axis2=self.attrs['axis2'])
|
||||
}
|
||||
|
||||
def test_check_output(self):
|
||||
self.check_output(check_pir=True)
|
||||
|
||||
def test_check_grad(self):
|
||||
self.check_grad(['Input'], 'Out', check_pir=True)
|
||||
|
||||
|
||||
class TestTraceOpCase1(TestTraceOp):
|
||||
"""测试不同参数配置"""
|
||||
def init_config(self):
|
||||
self.case = np.random.randn(20, 6).astype('float64')
|
||||
self.inputs = {'Input': self.case}
|
||||
self.attrs = {'offset': 1, 'axis1': 0, 'axis2': 1}
|
||||
self.outputs = {
|
||||
'Out': np.trace(self.inputs['Input'],
|
||||
offset=self.attrs['offset'],
|
||||
axis1=self.attrs['axis1'],
|
||||
axis2=self.attrs['axis2'])
|
||||
}
|
||||
|
||||
|
||||
class TestTraceOpCase2(TestTraceOp):
|
||||
"""测试高维输入"""
|
||||
def init_config(self):
|
||||
self.case = np.random.randn(2, 20, 2, 3).astype('float64')
|
||||
self.inputs = {'Input': self.case}
|
||||
self.attrs = {'offset': 1, 'axis1': 1, 'axis2': 2}
|
||||
self.outputs = {
|
||||
'Out': np.trace(self.inputs['Input'],
|
||||
offset=self.attrs['offset'],
|
||||
axis1=self.attrs['axis1'],
|
||||
axis2=self.attrs['axis2'])
|
||||
}
|
||||
|
||||
|
||||
class TestTraceAPICase(unittest.TestCase):
|
||||
"""测试 Python API 调用"""
|
||||
def test_case1(self):
|
||||
x = paddle.to_tensor(np.random.randn(20, 6).astype('float64'))
|
||||
result = paddle.trace(x)
|
||||
expected = np.trace(x.numpy())
|
||||
np.testing.assert_allclose(result.numpy(), expected, rtol=1e-05)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
```
|
||||
|
||||
## 测试运行方式
|
||||
|
||||
```bash
|
||||
# 单个测试文件
|
||||
python -m pytest test/legacy_test/test_xxx_op.py -v
|
||||
|
||||
# 或者
|
||||
python test/legacy_test/test_xxx_op.py
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据类型**:反向梯度检查使用 `float64` 确保数值微分精度
|
||||
2. **多 Case 覆盖**:继承基类并重写 `init_config()` 测试不同参数组合
|
||||
3. **边界条件**:测试边界情况(零维、高维、负轴索引等)
|
||||
4. **Python API 测试**:除了 OpTest 还需要测试 Python API 直接调用
|
||||
5. **check_pir=True**:新增算子测试中需添加此参数
|
||||
6. **op_type**:须与 YAML 配置中的算子名一致
|
||||
7. **python_api**:须设置为对应的 Python API 函数
|
||||
@@ -0,0 +1,148 @@
|
||||
# 算子 YAML 配置规则
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [前向算子 ops.yaml 配置](#前向算子-opsyaml-配置)
|
||||
- [反向算子 backward.yaml 配置](#反向算子-backwardyaml-配置)
|
||||
- [特殊配置项](#特殊配置项)
|
||||
- [data_transform 配置](#data_transform-配置)
|
||||
- [trace 算子完整示例](#trace-算子完整示例)
|
||||
|
||||
## 概述
|
||||
|
||||
在 `paddle/phi/ops/yaml/ops.yaml` 和 `paddle/phi/ops/yaml/backward.yaml` 文件中对算子进行描述及定义。框架编译时根据 YAML 配置自动生成 C++ 端的相关代码接口及内部实现,将上层 Python API 与底层 Kernel 连接起来。
|
||||
|
||||
## 前向算子 ops.yaml 配置
|
||||
|
||||
### 基本配置项
|
||||
|
||||
| 配置项 | 说明 |
|
||||
|---|---|
|
||||
| `op` | 算子名称,与 Python API 函数名相同,全小写+下划线命名 |
|
||||
| `args` | 输入参数,与 Python API 输入参数对应。Tensor 类型参数为 Input,非 Tensor 类型为 Attribute |
|
||||
| `output` | 输出类型,支持 `Tensor` 和 `Tensor[]`,多输出逗号分隔,用 `()` 标记名字(默认 `out`) |
|
||||
| `infer_meta:func` | InferMeta 函数名 |
|
||||
| `infer_meta:param` | InferMeta 输入参数(默认传入 args 全部参数) |
|
||||
| `kernel:func` | Kernel 函数注册名 |
|
||||
| `kernel:param` | Kernel 输入参数(默认传入 args 全部参数) |
|
||||
| `kernel:data_type` | 指定推导 kernel data_type 的参数(默认根据输入 Tensor 自动推导) |
|
||||
| `kernel:backend` | 指定推导 kernel Backend 的参数(默认根据输入 Tensor 自动推导) |
|
||||
| `backward` | 对应的反向算子名称 |
|
||||
|
||||
### args 支持的数据类型
|
||||
|
||||
`Tensor`, `Tensor[]`, `float`, `double`, `bool`, `int`, `int64_t`, `int[]`, `int64_t[]`, `str`, `Place`, `DataType`, `DataLayout`, `IntArray`, `Scalar`
|
||||
|
||||
- `Tensor[]`:Tensor 数组
|
||||
- `IntArray`:int 类型数组,用于 shape/index/axes,可用 Tensor 或普通整型数组构造
|
||||
- `Scalar`:标量,支持不同普通数据类型
|
||||
|
||||
### output 规则
|
||||
|
||||
- `Tensor[]` 需在 `{}` 内指定 size 表达式:`Tensor[]{input.size()}`
|
||||
- 未标记名字默认为 `out`
|
||||
|
||||
### invoke 配置
|
||||
|
||||
复用已有算子或自定义 C++ API 时使用 `invoke`,此时不需要配置 `infer_meta` 和 `kernel`:
|
||||
- 复用已有算子:被复用算子须为前向算子且返回值类型相同(参考 `zeros_like`)
|
||||
- 自定义 C++ API:在 `paddle/phi/api/lib/api_custom_impl.h` 声明,`api_custom_impl.cc` 实现(参考 `embedding`)
|
||||
|
||||
### intermediate 配置
|
||||
|
||||
标记前向计算中用于反向计算的中间变量,不出现在 Python API 返回结果中(新增算子不建议使用)。
|
||||
|
||||
## 反向算子 backward.yaml 配置
|
||||
|
||||
| 配置项 | 说明 |
|
||||
|---|---|
|
||||
| `backward_op` | 反向算子名称,一般为前向名称 + `_grad`,二阶为 + `_double_grad` |
|
||||
| `forward` | 对应前向算子的名称、参数、返回值,需与 ops.yaml 一致 |
|
||||
| `args` | 反向输入参数(详见下方排列规则) |
|
||||
| `output` | 反向输出,顺序须与前向输入 Tensor 一致 |
|
||||
| `infer_meta` | 同前向 |
|
||||
| `kernel` | 同前向 |
|
||||
| `backward` | 对应的更高阶反向算子名称 |
|
||||
| `no_need_buffer` | 标记不需要内存数据的前向变量,释放内存优化显存 |
|
||||
|
||||
### 反向 args 排列规则
|
||||
|
||||
**约束 1**:所有参数须在 forward 配置项的参数中(输入、输出及输出的反向梯度)找到对应(按变量名匹配)。
|
||||
|
||||
**约束 2**:参数排列顺序为:
|
||||
1. 前向输入 Tensor
|
||||
2. 前向输出 Tensor
|
||||
3. 前向输出 Tensor 的反向梯度(命名为 `{output_name}_grad`)
|
||||
4. 前向非 Tensor 类型属性变量
|
||||
|
||||
反向不需要使用的前向变量无须添加。
|
||||
|
||||
### 反向 output 规则
|
||||
|
||||
顺序须与前向输入 Tensor 一致。例如前向 `(Tensor x, Tensor y)` -> 反向输出必须为 `Tensor(x_grad), Tensor(y_grad)`。
|
||||
|
||||
## 特殊配置项
|
||||
|
||||
### optional
|
||||
|
||||
指定输入 Tensor 为可选输入。参考 `dropout` 中的 `seed_tensor`。
|
||||
|
||||
### inplace
|
||||
|
||||
对指定输入做原位处理并作为输出返回。格式:`(x -> out)`。
|
||||
|
||||
规则:
|
||||
- 算子名有 `_` 后缀:只生成 inplace 接口
|
||||
- 算子名无 `_` 后缀:同时生成 inplace 接口(自动加 `_` 后缀)和普通接口
|
||||
|
||||
参考:`relu` 算子。
|
||||
|
||||
### view
|
||||
|
||||
与 inplace 类似,返回结果与输入共享内存但不是同一变量。格式:`(x -> out)`。参考:`reshape` 算子。
|
||||
|
||||
### no_need_buffer
|
||||
|
||||
反向算子中标记只需要前向变量的 Shape/LoD 而不需要内存数据的变量。标记后该变量的内存/显存会在前向完成后释放。
|
||||
|
||||
注意:由于 Tensor 内存被释放后影响 dtype 接口使用,须在 kernel 的 `data_type` 配置中指定其他 Tensor 来推导 data_type。
|
||||
|
||||
## data_transform 配置
|
||||
|
||||
控制算子输入参数的自动转换行为(dtype、backend、layout)。
|
||||
|
||||
| 子配置 | 说明 |
|
||||
|---|---|
|
||||
| `skip_transform` | 跳过指定参数的所有数据转换(最高优先级) |
|
||||
| `support_trans_dtype` | 开启指定参数的自动类型转换(非复数类型) |
|
||||
|
||||
## trace 算子完整示例
|
||||
|
||||
### ops.yaml
|
||||
|
||||
```yaml
|
||||
- op: trace
|
||||
args: (Tensor x, int offset = 0, int axis1 = 0, int axis2 = 1)
|
||||
output: Tensor(out)
|
||||
infer_meta:
|
||||
func: TraceInferMeta
|
||||
kernel:
|
||||
func: trace
|
||||
backward: trace_grad
|
||||
```
|
||||
|
||||
### backward.yaml
|
||||
|
||||
```yaml
|
||||
- backward_op: trace_grad
|
||||
forward: trace (Tensor x, int offset, int axis1, int axis2) -> Tensor(out)
|
||||
args: (Tensor x, Tensor out_grad, int offset, int axis1, int axis2)
|
||||
output: Tensor(x_grad)
|
||||
infer_meta:
|
||||
func: UnchangedInferMeta
|
||||
param: [x]
|
||||
kernel:
|
||||
func: trace_grad
|
||||
data_type: x
|
||||
no_need_buffer: x
|
||||
```
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
name: paddle-pull-request
|
||||
description: |
|
||||
自动创建或更新 GitHub Pull Request。
|
||||
当需要为 Paddle 相关仓库创建 PR 时,优先使用本 skill。
|
||||
---
|
||||
|
||||
# Paddle 仓库 PR 创建与更新
|
||||
|
||||
## 流程
|
||||
|
||||
### 1. 检查分支状态
|
||||
|
||||
- 检查当前分支是否已经推送到远端;如果没有,执行 `git push -u origin HEAD`。
|
||||
- 如果当前分支名是 `main` 或 `master`,在继续之前先向用户确认是否真的要在该分支上直接提 PR。
|
||||
|
||||
### 2. 按逻辑主题整理改动
|
||||
|
||||
- 不要机械地罗列每一次 commit。
|
||||
- 按照「功能 / 目的」对改动进行分组,回答:
|
||||
- 为什么需要这次改动?
|
||||
- 解决了什么问题?
|
||||
- 大致改了哪些模块?
|
||||
|
||||
### 3. 使用 Paddle 官方 PR 模板
|
||||
|
||||
- PR 内容必须遵循 Paddle 官方 PR 模板:
|
||||
- 模板链接:`https://github.com/PaddlePaddle/Paddle/blob/develop/.github/PULL_REQUEST_TEMPLATE.md`
|
||||
- 模板使用**三级标题(`###`)**作为各小节标题,生成 PR 描述时需与之保持一致。
|
||||
- 模板结构(简化版):
|
||||
|
||||
```markdown
|
||||
### PR Category
|
||||
<!-- One of [ User Experience | Execute Infrastructure | Operator Mechanism | CINN | Custom Device | Performance Optimization | Distributed Strategy | Parameter Server | Communication Library | Auto Parallel | Inference | Environment Adaptation ] -->
|
||||
|
||||
### PR Types
|
||||
<!-- One of [ New features | Bug fixes | Improvements | Performance | BC Breaking | Deprecations | Docs | Devs | Not User Facing | Security | Others ] -->
|
||||
|
||||
### Description
|
||||
|
||||
### 是否引起精度变化
|
||||
<!-- one of the following [ 是 | 否 ]-->
|
||||
```
|
||||
|
||||
- 生成 PR 描述时,按以上四个小节依次填写:
|
||||
- **PR Category**:高层次类别,例如 Bug fix、Feature、Refactor、Doc 等。
|
||||
- **PR Types**:更细的类型说明,例如 API 变更、性能优化、算子新增等。
|
||||
- **Description**:用自然语言简要说明该 PR 的背景、动机和主要改动点。**描述正文中不要使用三级及三级以上标题**(`###`、`##`、`#`),若需分段小标题,最多使用四级标题(`####`)。
|
||||
- **是否引起精度变化**:明确说明是否会影响已有模型或任务的精度,并给出必要的说明。
|
||||
|
||||
### 4. 提交前运行 prek 检查
|
||||
|
||||
- 在创建或更新 PR 之前,先运行 `prek` 对所有文件进行格式检查:
|
||||
|
||||
```bash
|
||||
prek
|
||||
```
|
||||
|
||||
- 如果 `prek` 自动修改了文件,需要将这些修改加入一个新的 commit,再推送:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "🔧 chore: apply prek fixes"
|
||||
git push
|
||||
```
|
||||
|
||||
- 只有 `prek` 检查通过(没有额外修改)后,再继续创建或更新 PR。
|
||||
- 如果 `prek` 报告无法自动修复的错误(例如类型检查或自定义 hook 失败),需根据错误信息手动修复后重新运行,直到全部检查通过,再继续创建或更新 PR。
|
||||
|
||||
### 5. 使用 gh 命令创建 / 更新 PR
|
||||
|
||||
- 使用 `gh` 命令创建或更新 PR。
|
||||
|
||||
#### 标题规范
|
||||
|
||||
- 标题整体用英文,保持简洁明了。
|
||||
- 推荐格式:`[PR 大类] 简要说明`
|
||||
- 示例:`[CINN] avoid wrong fusion for xxx op`
|
||||
- 示例:`[LargeTensor] fix xxx kernel`
|
||||
- 示例:`[CodeStyle] update code style`
|
||||
- 避免使用含糊标题,例如:
|
||||
- `fix bug` / `update code` / `test` / `temp` / `WIP` 等。
|
||||
- 尽量控制在一行内说清「做了什么」或「修改目的」,不需要罗列所有细节。
|
||||
|
||||
示例命令(根据实际情况替换标题和正文):
|
||||
|
||||
```bash
|
||||
gh pr create --title "[xxx] xxx" --body "$(cat <<'EOF'
|
||||
### PR Category
|
||||
Operator Mechanism
|
||||
|
||||
### PR Types
|
||||
New features
|
||||
|
||||
### Description
|
||||
在这里说明该改动的动机和主要变化,可根据实际情况扩展,优先使用中文。
|
||||
|
||||
### 是否引起精度变化
|
||||
否
|
||||
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 始终使用 Paddle 官方 PR 模板的章节结构,**标题层级与模板一致**(模板使用三级标题 `###`),不要自定义新的顶层标题。
|
||||
- **Description 描述正文**中不要加三级及三级以上标题,若有分段需求,最多使用四级标题(`####`)。
|
||||
- 优先强调「为什么需要这次改动」,而不是罗列所有实现细节。
|
||||
- 如果业务或背景信息不清楚,应先向用户提问澄清,再生成 PR 描述。
|
||||
- 成功创建或更新 PR 后,应返回 PR URL,方便用户查看。
|
||||
- 为 Paddle 相关仓库生成 PR 描述、调试说明或问题分析时,**优先使用中文**,除非上游模板或明确场景要求使用英文。
|
||||
- **不要将任何 bot / 机器账号加入协作者**。
|
||||
@@ -0,0 +1,29 @@
|
||||
# This file is used by clang-format to autoformat paddle source code
|
||||
#
|
||||
# The clang-format is part of llvm toolchain.
|
||||
# It need to install llvm and clang to format source code style.
|
||||
#
|
||||
# The basic usage is,
|
||||
# clang-format -i -style=file PATH/TO/SOURCE/CODE
|
||||
#
|
||||
# The -style=file implicit use ".clang-format" file located in one of
|
||||
# parent directory.
|
||||
# The -i means inplace change.
|
||||
#
|
||||
# The document of clang-format is
|
||||
# http://clang.llvm.org/docs/ClangFormat.html
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 2
|
||||
TabWidth: 2
|
||||
ContinuationIndentWidth: 4
|
||||
AccessModifierOffset: -1 # The private/protected/public has no indent in class
|
||||
Standard: Cpp11
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
BinPackParameters: false
|
||||
BinPackArguments: false
|
||||
IncludeBlocks: Preserve
|
||||
IncludeIsMainSourceRegex: (\.cu)$
|
||||
...
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
---
|
||||
Checks: '
|
||||
bugprone-argument-comment,
|
||||
-bugprone-assert-side-effect,
|
||||
-bugprone-bad-signal-to-kill-thread,
|
||||
-bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-branch-clone,
|
||||
bugprone-copy-constructor-init,
|
||||
-bugprone-dangling-handle,
|
||||
-bugprone-dynamic-static-initializers,
|
||||
bugprone-exception-escape,
|
||||
bugprone-fold-init-type,
|
||||
-bugprone-forwarding-reference-overload,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-infinite-loop,
|
||||
bugprone-integer-division,
|
||||
-bugprone-macro-repeated-side-effects,
|
||||
-bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
-bugprone-move-forwarding-reference,
|
||||
-bugprone-multiple-statement-macro,
|
||||
bugprone-narrowing-conversions,
|
||||
-bugprone-not-null-terminated-result,
|
||||
-bugprone-parent-virtual-call,
|
||||
-bugprone-posix-return,
|
||||
bugprone-signed-char-misuse,
|
||||
-bugprone-sizeof-container,
|
||||
-bugprone-sizeof-expression,
|
||||
-bugprone-string-constructor,
|
||||
bugprone-string-integer-assignment,
|
||||
-bugprone-string-literal-with-embedded-nul,
|
||||
-bugprone-suspicious-enum-usage,
|
||||
-bugprone-suspicious-memset-usage,
|
||||
bugprone-suspicious-missing-comma,
|
||||
-bugprone-suspicious-semicolon,
|
||||
-bugprone-suspicious-string-compare,
|
||||
-bugprone-terminating-continue,
|
||||
-bugprone-throw-keyword-missing,
|
||||
-bugprone-too-small-loop-variable,
|
||||
-bugprone-undefined-memory-manipulation,
|
||||
-bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-use-after-move,
|
||||
-bugprone-virtual-near-miss,
|
||||
-clang-analyzer-apiModeling.StdCLibraryFunctions,
|
||||
-clang-analyzer-apiModeling.TrustNonnull,
|
||||
-clang-analyzer-apiModeling.google.GTest,
|
||||
-clang-analyzer-apiModeling.llvm.CastValue,
|
||||
-clang-analyzer-apiModeling.llvm.ReturnValue,
|
||||
clang-analyzer-core.CallAndMessage,
|
||||
-clang-analyzer-core.DivideZero,
|
||||
-clang-analyzer-core.DynamicTypePropagation,
|
||||
clang-analyzer-core.NonNullParamChecker,
|
||||
-clang-analyzer-core.NonnilStringConstants,
|
||||
-clang-analyzer-core.NullDereference,
|
||||
-clang-analyzer-core.StackAddrEscapeBase,
|
||||
-clang-analyzer-core.StackAddressEscape,
|
||||
clang-analyzer-core.UndefinedBinaryOperatorResult,
|
||||
-clang-analyzer-core.VLASize,
|
||||
-clang-analyzer-core.builtin.BuiltinFunctions,
|
||||
-clang-analyzer-core.builtin.NoReturnFunctions,
|
||||
-clang-analyzer-core.uninitialized.ArraySubscript,
|
||||
clang-analyzer-core.uninitialized.Assign,
|
||||
-clang-analyzer-core.uninitialized.Branch,
|
||||
-clang-analyzer-core.uninitialized.CapturedBlockVariable,
|
||||
-clang-analyzer-core.uninitialized.UndefReturn,
|
||||
clang-analyzer-cplusplus.InnerPointer,
|
||||
-clang-analyzer-cplusplus.Move,
|
||||
-clang-analyzer-cplusplus.NewDelete,
|
||||
clang-analyzer-cplusplus.NewDeleteLeaks,
|
||||
-clang-analyzer-cplusplus.PureVirtualCall,
|
||||
-clang-analyzer-cplusplus.SelfAssignment,
|
||||
-clang-analyzer-cplusplus.SmartPtr,
|
||||
-clang-analyzer-cplusplus.VirtualCallModeling,
|
||||
clang-analyzer-deadcode.DeadStores,
|
||||
-clang-analyzer-fuchsia.HandleChecker,
|
||||
-clang-analyzer-nullability.NullPassedToNonnull,
|
||||
-clang-analyzer-nullability.NullReturnedFromNonnull,
|
||||
-clang-analyzer-nullability.NullabilityBase,
|
||||
-clang-analyzer-nullability.NullableDereferenced,
|
||||
-clang-analyzer-nullability.NullablePassedToNonnull,
|
||||
-clang-analyzer-nullability.NullableReturnedFromNonnull,
|
||||
clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||
-clang-analyzer-optin.cplusplus.VirtualCall,
|
||||
-clang-analyzer-optin.mpi.MPI-Checker,
|
||||
-clang-analyzer-optin.osx.OSObjectCStyleCast,
|
||||
-clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,
|
||||
-clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker,
|
||||
-clang-analyzer-optin.performance.GCDAntipattern,
|
||||
-clang-analyzer-optin.performance.Padding,
|
||||
clang-analyzer-optin.portability.UnixAPI,
|
||||
-clang-analyzer-osx.API,
|
||||
-clang-analyzer-osx.MIG,
|
||||
-clang-analyzer-osx.NSOrCFErrorDerefChecker,
|
||||
-clang-analyzer-osx.NumberObjectConversion,
|
||||
-clang-analyzer-osx.OSObjectRetainCount,
|
||||
-clang-analyzer-osx.ObjCProperty,
|
||||
-clang-analyzer-osx.SecKeychainAPI,
|
||||
-clang-analyzer-osx.cocoa.AtSync,
|
||||
-clang-analyzer-osx.cocoa.AutoreleaseWrite,
|
||||
-clang-analyzer-osx.cocoa.ClassRelease,
|
||||
-clang-analyzer-osx.cocoa.Dealloc,
|
||||
-clang-analyzer-osx.cocoa.IncompatibleMethodTypes,
|
||||
-clang-analyzer-osx.cocoa.Loops,
|
||||
-clang-analyzer-osx.cocoa.MissingSuperCall,
|
||||
-clang-analyzer-osx.cocoa.NSAutoreleasePool,
|
||||
-clang-analyzer-osx.cocoa.NSError,
|
||||
-clang-analyzer-osx.cocoa.NilArg,
|
||||
-clang-analyzer-osx.cocoa.NonNilReturnValue,
|
||||
-clang-analyzer-osx.cocoa.ObjCGenerics,
|
||||
-clang-analyzer-osx.cocoa.RetainCount,
|
||||
-clang-analyzer-osx.cocoa.RetainCountBase,
|
||||
-clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak,
|
||||
-clang-analyzer-osx.cocoa.SelfInit,
|
||||
-clang-analyzer-osx.cocoa.SuperDealloc,
|
||||
-clang-analyzer-osx.cocoa.UnusedIvars,
|
||||
-clang-analyzer-osx.cocoa.VariadicMethodTypes,
|
||||
-clang-analyzer-osx.coreFoundation.CFError,
|
||||
-clang-analyzer-osx.coreFoundation.CFNumber,
|
||||
-clang-analyzer-osx.coreFoundation.CFRetainRelease,
|
||||
-clang-analyzer-osx.coreFoundation.containers.OutOfBounds,
|
||||
-clang-analyzer-osx.coreFoundation.containers.PointerSizedValues,
|
||||
clang-analyzer-security.FloatLoopCounter,
|
||||
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
|
||||
-clang-analyzer-security.insecureAPI.SecuritySyntaxChecker,
|
||||
-clang-analyzer-security.insecureAPI.UncheckedReturn,
|
||||
-clang-analyzer-security.insecureAPI.bcmp,
|
||||
-clang-analyzer-security.insecureAPI.bcopy,
|
||||
-clang-analyzer-security.insecureAPI.bzero,
|
||||
-clang-analyzer-security.insecureAPI.decodeValueOfObjCType,
|
||||
-clang-analyzer-security.insecureAPI.getpw,
|
||||
-clang-analyzer-security.insecureAPI.gets,
|
||||
-clang-analyzer-security.insecureAPI.mkstemp,
|
||||
-clang-analyzer-security.insecureAPI.mktemp,
|
||||
-clang-analyzer-security.insecureAPI.rand,
|
||||
-clang-analyzer-security.insecureAPI.strcpy,
|
||||
clang-analyzer-security.insecureAPI.vfork,
|
||||
-clang-analyzer-unix.API,
|
||||
-clang-analyzer-unix.DynamicMemoryModeling,
|
||||
clang-analyzer-unix.Malloc,
|
||||
-clang-analyzer-unix.MallocSizeof,
|
||||
-clang-analyzer-unix.MismatchedDeallocator,
|
||||
clang-analyzer-unix.Vfork,
|
||||
-clang-analyzer-unix.cstring.BadSizeArg,
|
||||
-clang-analyzer-unix.cstring.CStringModeling,
|
||||
-clang-analyzer-unix.cstring.NullArg,
|
||||
-clang-analyzer-valist.CopyToSelf,
|
||||
-clang-analyzer-valist.Uninitialized,
|
||||
-clang-analyzer-valist.Unterminated,
|
||||
-clang-analyzer-valist.ValistBase,
|
||||
cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
cppcoreguidelines-c-copy-assignment-signature,
|
||||
cppcoreguidelines-explicit-virtual-functions,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-narrowing-conversions,
|
||||
cppcoreguidelines-no-malloc,
|
||||
cppcoreguidelines-pro-type-const-cast,
|
||||
-cppcoreguidelines-pro-type-member-init,
|
||||
-cppcoreguidelines-slicing,
|
||||
-hicpp-avoid-goto,
|
||||
hicpp-exception-baseclass,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
modernize-avoid-bind,
|
||||
modernize-avoid-c-arrays,
|
||||
modernize-deprecated-headers,
|
||||
-modernize-deprecated-ios-base-aliases,
|
||||
modernize-loop-convert,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
-modernize-pass-by-value,
|
||||
modernize-raw-string-literal,
|
||||
modernize-redundant-void-arg,
|
||||
-modernize-replace-auto-ptr,
|
||||
-modernize-replace-random-shuffle,
|
||||
-modernize-shrink-to-fit,
|
||||
-modernize-unary-static-assert,
|
||||
modernize-use-bool-literals,
|
||||
modernize-use-emplace,
|
||||
modernize-use-equals-default,
|
||||
-modernize-use-equals-delete,
|
||||
-modernize-use-noexcept,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-override,
|
||||
modernize-use-transparent-functors,
|
||||
-modernize-use-uncaught-exceptions,
|
||||
performance-faster-string-find,
|
||||
performance-for-range-copy,
|
||||
-performance-implicit-conversion-in-loop,
|
||||
-performance-inefficient-algorithm,
|
||||
performance-inefficient-string-concatenation,
|
||||
-performance-inefficient-vector-operation,
|
||||
performance-move-const-arg,
|
||||
-performance-move-constructor-init,
|
||||
-performance-no-automatic-move,
|
||||
performance-noexcept-move-constructor,
|
||||
performance-trivially-destructible,
|
||||
-performance-type-promotion-in-math-fn,
|
||||
-performance-unnecessary-copy-initialization,
|
||||
readability-container-size-empty,
|
||||
'
|
||||
HeaderFilterRegex: '^(paddle/(?!cinn)).*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
WarningsAsErrors: '*'
|
||||
...
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../.agents/skills
|
||||
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# -----------------------------
|
||||
# Options affecting formatting.
|
||||
# -----------------------------
|
||||
with section("format"):
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# ------------------------------------------------
|
||||
# Options affecting comment reflow and formatting.
|
||||
# ------------------------------------------------
|
||||
with section("markup"):
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = False
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in each
|
||||
# listfile. Use this to preserve formatting of your copyright/license
|
||||
# statements.
|
||||
first_comment_is_literal = True
|
||||
|
||||
# ----------------------------------
|
||||
# Options affecting listfile parsing
|
||||
# ----------------------------------
|
||||
with section("parse"):
|
||||
# Additional FLAGS and KWARGS for custom commands
|
||||
additional_commands = {
|
||||
"cc_library": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"nv_library": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"xpu_library": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"hip_library": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"go_library": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"copy": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DSTS": '*',
|
||||
}
|
||||
},
|
||||
"cc_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"nv_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"hip_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"xpu_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"go_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
"py_test": {
|
||||
"kwargs": {
|
||||
"SRCS": '*',
|
||||
"DEPS": '*',
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
*.DS_Store
|
||||
build/
|
||||
*.user
|
||||
.vscode
|
||||
.idea
|
||||
.project
|
||||
.cproject
|
||||
.pydevproject
|
||||
Makefile
|
||||
.test_env/
|
||||
third_party/
|
||||
*~
|
||||
bazel-*
|
||||
|
||||
!build/*.deb
|
||||
@@ -0,0 +1,26 @@
|
||||
# EditorConfig is a cross-editor configuration file
|
||||
# that helps to unify code styles for multiple
|
||||
# developers collaborative projects.
|
||||
# See more at https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{c,cc,cxx,cpp,cu,cuh,h,hpp,hxx,kps,yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.{py,pyi,java,r,toml}]
|
||||
indent_size = 4
|
||||
|
||||
[Dockerfile.*]
|
||||
indent_size = 4
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
@@ -0,0 +1,79 @@
|
||||
# This file is migrated from CI script, it's an effort of modenizing our dev infra.
|
||||
# Code owners are expected to take responsibility for review patches to respective file.
|
||||
|
||||
/CMakeLists.txt @wanghuancoder @XiaoguangHu01
|
||||
paddle/fluid/distributed/collective @sneaxiy @ForFishes
|
||||
paddle/fluid/eager/autograd_meta.cc @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/autograd_meta.h @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/backward.cc @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/backward.h @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/grad_node_info.cc @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/grad_node_info.h @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/grad_tensor_holder.cc @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/grad_tensor_holder.h @JiabinYang @xiaoguoguo626807
|
||||
paddle/fluid/eager/tensor_wrapper.h @JiabinYang @zhangbo9674
|
||||
paddle/fluid/framework/block_desc.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/details/op_registry.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/framework.proto @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/grad_op_desc_maker.h @XiaoguangHu01 @xiaoguoguo626807 @Xreki
|
||||
paddle/fluid/framework/ir/graph.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/ir/node.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/lod_tensor.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/op_desc.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/operator.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/scope.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/selected_rows.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/tensor.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/framework/unused_var_check.cc @zhangbo9674
|
||||
paddle/fluid/framework/var_desc.h @XiaoguangHu01 @zhangbo9674 @Xreki
|
||||
paddle/fluid/operators/distributed/send_recv.proto.in @gongweibao @seiriosPlus
|
||||
paddle/fluid/prim/api/api.yaml @xiaoguoguo626807 @JiabinYang @zhangbo9674
|
||||
paddle/fluid/prim/api/composite_backward/composite_backward_api.h @xiaoguoguo626807 @JiabinYang
|
||||
paddle/fluid/prim/api/composite_backward/composite_double_backward_api.h @xiaoguoguo626807 @JiabinYang
|
||||
paddle/fluid/prim/api/manual_prim/prim_manual_api.h @xiaoguoguo626807 @JiabinYang
|
||||
paddle/phi/api/include/tensor.h @zhangbo9674
|
||||
paddle/phi/core/attribute.h @zhangbo9674
|
||||
paddle/phi/core/dense_tensor.h @zhangbo9674
|
||||
paddle/phi/core/device_context.h @zhangbo9674
|
||||
paddle/phi/core/infermeta_utils.h @zhangbo9674
|
||||
paddle/phi/core/kernel_context.h @zhangbo9674
|
||||
paddle/phi/core/kernel_factory.h @zhangbo9674
|
||||
paddle/phi/core/kernel_registry.h @zhangbo9674
|
||||
paddle/phi/core/kernel_utils.h @zhangbo9674
|
||||
paddle/phi/core/meta_tensor.h @zhangbo9674
|
||||
paddle/phi/core/tensor_base.h @zhangbo9674
|
||||
paddle/phi/core/tensor_meta.h @zhangbo9674
|
||||
paddle/phi/infermeta/spmd_rules @LiYuRio @ForFishes @From00
|
||||
paddle/scripts/paddle_build.bat @zhwesky2010 @wanghuancoder
|
||||
paddle/scripts/paddle_build.sh @risemeup1 @zhangbo9674 @XieYunshen
|
||||
pyproject.toml @SigureMo @gouzil
|
||||
python/paddle/autograd/backward_utils.py @xiaoguoguo626807 @changeyoung98
|
||||
python/paddle/autograd/ir_backward.py @xiaoguoguo626807 @changeyoung98
|
||||
python/paddle/base/backward.py @XiaoguangHu01 @xiaoguoguo626807 @Xreki @qili93
|
||||
python/paddle/base/compiler.py @XiaoguangHu01 @zhangbo9674 @Xreki @qili93
|
||||
python/paddle/base/dygraph/layers.py @JiabinYang @zhangbo9674
|
||||
python/paddle/base/framework.py @XiaoguangHu01 @zhangbo9674 @Xreki @qili93
|
||||
python/paddle/base/__init__.py @zhangbo9674 @qili93
|
||||
test/white_list/check_op_sequence_batch_1_input_white_list.py @zhangbo9674
|
||||
test/white_list/check_op_sequence_instance_0_input_white_list.py @zhangbo9674
|
||||
test/white_list/check_shape_white_list.py @hong19860320 @zhangbo9674
|
||||
test/white_list/compile_vs_runtime_white_list.py @zhangbo9674
|
||||
test/white_list/no_check_set_white_list.py @zhangbo9674
|
||||
test/white_list/no_grad_set_white_list.py @zhangbo9674
|
||||
test/white_list/op_accuracy_white_list.py @juncaipeng @zhangting2020
|
||||
test/white_list/op_threshold_white_list.py @juncaipeng @zhangting2020
|
||||
python/paddle/distributed/fleet/__init__.py @sneaxiy @raindrops2sea
|
||||
python/paddle/distributed/fleet/launch.py @sneaxiy @raindrops2sea
|
||||
python/paddle/distributed/__init__.py @sneaxiy @raindrops2sea
|
||||
python/paddle/incubate/autograd/composite_rules.py @xiaoguoguo626807 @JiabinYang
|
||||
python/paddle/incubate/autograd/primitives.py @xiaoguoguo626807 @JiabinYang
|
||||
python/paddle/_typing @SigureMo @zrr1999 @gouzil
|
||||
python/requirements.txt @zhangbo9674 @jzhang533 @kolinwei
|
||||
test/dygraph_to_static @SigureMo @DrRyanHuang @zrr1999 @gouzil
|
||||
test/sot @SigureMo @DrRyanHuang @zrr1999 @gouzil
|
||||
tools/parallel_UT_rule.py @zhwesky2010 @wanghuancoder
|
||||
tools/windows/run_unittests.sh @zhwesky2010 @wanghuancoder
|
||||
.pre-commit-config.yaml @SigureMo @gouzil
|
||||
_typos.toml @SigureMo
|
||||
ci/rules @SigureMo @zrr1999
|
||||
ci/rule-tests @SigureMo @zrr1999
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
name: 🐛 报BUG Bug Report
|
||||
description: 报告一个可复现的BUG帮助我们修复框架。 Report a bug to help us reproduce and fix it.
|
||||
labels: [type/bug-report, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 在向Paddle报bug之前,请先查询[历史issue](https://github.com/PaddlePaddle/Paddle/issues)是否报过同样的bug。
|
||||
|
||||
#### Before submitting a bug, please make sure the issue hasn't been already addressed by searching through [the existing and past issues](https://github.com/PaddlePaddle/Paddle/issues).
|
||||
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: bug描述 Describe the Bug
|
||||
description: |
|
||||
请清晰简洁的描述这个bug,最好附上bug复现环境、bug复现步骤及最小代码集,以便我们可以通过运行代码来重现错误。代码片段需要尽可能简洁,请花些时间去掉不相关的代码以帮助我们有效地调试。我们希望通过复制代码并运行得到与你相同的结果,请避免任何外部数据或包含相关的导入等。例如:
|
||||
```python
|
||||
# 导入所有必要的库。 All necessary imports at the beginning.
|
||||
# paddlepaddle <= 2.1.2
|
||||
import paddle
|
||||
|
||||
# 一个简洁的片段,能够定位到bug。 A succinct reproducing example trimmed down to the essential parts.
|
||||
a = paddle.rand(shape=[1,4])
|
||||
b = paddle.rand(shape=[1,4])
|
||||
a.stop_gradient = False
|
||||
b.stop_gradient = False
|
||||
|
||||
c = paddle.zeros((4, 4))
|
||||
c[0, :] = a/b
|
||||
|
||||
print('Is c requires grad: ', not c.stop_gradient) # 注意:这里出现了bug,期望requires_grad=True
|
||||
```
|
||||
如果代码太长,请将可执行代码放到[AIStudio](https://aistudio.baidu.com/aistudio/index)中并将项目设置为公开(或者放到github gist上),请在项目中描述清楚bug复现步骤,在issue中描述期望结果与实际结果。
|
||||
如果你报告的是一个报错信息,请将完整回溯的报错贴在这里,并使用 ` ```三引号块``` `展示错误信息。
|
||||
|
||||
|
||||
placeholder: |
|
||||
请清晰简洁的描述这个bug。A clear and concise description of what the bug is.
|
||||
|
||||
```python
|
||||
# 最小可复现代码。 Sample code to reproduce the problem.
|
||||
```
|
||||
|
||||
```shell
|
||||
带有完整回溯的报错信息。 The error message you got, with the full traceback.
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: others
|
||||
attributes:
|
||||
label: 其他补充信息 Additional Supplementary Information
|
||||
description: |
|
||||
如果你还有其他需要补充的内容,请写在这里。
|
||||
If you have anything else to add, please write it here.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
感谢你的贡献 🎉!Thanks for your contribution 🎉!
|
||||
@@ -0,0 +1,37 @@
|
||||
name: 🚀 新需求 Feature Request
|
||||
description: 提交一个你对Paddle的新需求。 Submit a request for a new Paddle feature.
|
||||
labels: [type/feature-request, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 你可以在这里提出你对Paddle框架的新需求,包括但不限于:功能或模型缺失、功能不全或无法使用、精度/性能不符合预期等。
|
||||
|
||||
#### You could submit a request for a new Paddle feature here, including but not limited to: new features or models, incomplete or unusable features, accuracy/performance not as expected, etc.
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: 需求描述 Feature Description
|
||||
description: |
|
||||
请尽可能包含任务目标、需求场景、功能描述等信息,全面的信息有利于我们准确评估你的需求。
|
||||
Please include as much information as possible, such as mission objectives, requirement scenarios, functional descriptions, etc. Comprehensive information will help us accurately assess your feature request.
|
||||
value: "任务目标(请描述你正在做的项目是什么,如模型、论文、项目是什么?); <br /> 需求场景(请描述你的项目中为什么需要用此功能); <br /> 功能描述(请简单描述或设计这个功能)"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: 替代实现 Alternatives
|
||||
description: |
|
||||
如果你考虑过的任何替代解决方案或功能,请简要描述下,我们会综合评估。
|
||||
A description of any alternative solutions or features you've considered, if any.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
感谢你的贡献 🎉!Thanks for your contribution 🎉!
|
||||
@@ -0,0 +1,68 @@
|
||||
name: 🗂 安装 Build/Installation Issue
|
||||
description: 报告一个安装问题。 Report an issue related to build or install Paddle.
|
||||
labels: [type/build, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 安装请参考[官网文档](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/linux-pip.html),若未能解决你的问题,你可以在这里提issue。
|
||||
|
||||
#### Before submitting a Build/Installation Issue, please make sure you have visited the [official website](https://www.paddlepaddle.org.cn/documentation/docs/en/install/index_en.html).
|
||||
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: 问题描述 Issue Description
|
||||
description: |
|
||||
请详细描述你的问题,同步贴出报错信息、日志/代码关键片段、复现步骤,以便我们快速排查问题。
|
||||
Please describe your problem in detail, and synchronously post the error message, key log/code snippet, and reproduction steps, so that we can quickly troubleshoot the problem.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: 版本&环境信息 Version & Environment Information
|
||||
description: |
|
||||
请参考以下命令运行脚本[summary_env.py](https://github.com/PaddlePaddle/Paddle/blob/develop/tools/summary_env.py)获取版本&环境信息,并将输出拷贝在这里。
|
||||
Please run the following and paste the output below.
|
||||
```shell
|
||||
wget https://raw.githubusercontent.com/PaddlePaddle/Paddle/develop/tools/summary_env.py
|
||||
python3 -m pip install distro
|
||||
python3 summary_env.py
|
||||
```
|
||||
若运行脚本出现问题,请在issue中说明,并提供以下信息:
|
||||
1. PaddlePaddle版本:请提供你的PaddlePaddle版本号(如2.0.0)或CommitID。
|
||||
2. CPU(可选):请提供CPU型号,MKL/OpenBlas/MKLDNN/等数学库的使用情况,是否支持AVX指令集。
|
||||
3. GPU:请提供GPU型号,CUDA(如cuda10.2)和CUDNN版本号(如cudnn7.6.5)。
|
||||
4. 系统环境:请说明系统类型、版本(如Mac OS 10.14)。
|
||||
5. Python版本(如python 3.8)。
|
||||
6. (可选)若安装过程遇到问题,请提供安装方式(pip/conda/docker/源码编译)和相应的安装命令。
|
||||
7. (可选)若使用paddle过程中,遇到了无法使用gpu相关问题,请在命令行中键入`nvidia-smi`和`nvcc -V`,提供这两个命令输出的截图。
|
||||
8. (可选)若使用特殊硬件,请单独注明。
|
||||
|
||||
placeholder: |
|
||||
****************************************
|
||||
Paddle version:
|
||||
Paddle With CUDA:
|
||||
|
||||
OS:
|
||||
GCC version:
|
||||
Clang version:
|
||||
CMake version:
|
||||
Libc version:
|
||||
Python version:
|
||||
|
||||
CUDA version:
|
||||
cuDNN version:
|
||||
Nvidia driver version:
|
||||
Nvidia driver List:
|
||||
****************************************
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
感谢你的贡献 🎉!Thanks for your contribution 🎉!
|
||||
@@ -0,0 +1,37 @@
|
||||
name: 📚 文档 Documentation Issue
|
||||
description: 反馈一个官网文档错误。 Report an issue related to https://www.paddlepaddle.org.cn/.
|
||||
labels: [type/docs, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 请确认反馈的问题来自PaddlePaddle官网文档:https://www.paddlepaddle.org.cn/ 。
|
||||
|
||||
#### Before submitting a Documentation Issue, Please make sure that issue is related to https://www.paddlepaddle.org.cn/.
|
||||
|
||||
- type: textarea
|
||||
id: link
|
||||
attributes:
|
||||
label: 文档链接&描述 Document Links & Description
|
||||
description: |
|
||||
请说明有问题的文档链接以及该文档存在的问题。
|
||||
Please fill in the link to the document and describe the question.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: 请提出你的建议 Please give your suggestion
|
||||
description: |
|
||||
请告诉我们,你希望如何改进这个文档。或者你可以提个PR修复这个问题。[教程参考](https://github.com/PaddlePaddle/docs/wiki#%E8%B4%A1%E7%8C%AE%E6%96%87%E6%A1%A3)
|
||||
Please tell us how you would like to improve this document. Or you can submit a PR to fix this problem.
|
||||
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
感谢你的贡献 🎉!Thanks for your contribution 🎉!
|
||||
@@ -0,0 +1,33 @@
|
||||
name: 🙋🏼♀️🙋🏻♂️提问 Ask a Question
|
||||
description: 提出一个使用/咨询问题。 Ask a usage or consultation question.
|
||||
labels: [type/question, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 你可以在这里提出一个使用/咨询问题,提问之前请确保:
|
||||
|
||||
- 1)已经百度/谷歌搜索过你的问题,但是没有找到解答;
|
||||
|
||||
- 2)已经在官网查询过[API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/index_cn.html)与[FAQ](https://www.paddlepaddle.org.cn/documentation/docs/zh/faq/index_cn.html),但是没有找到解答;
|
||||
|
||||
- 3)已经在[历史issue](https://github.com/PaddlePaddle/Paddle/issues)中搜索过,没有找到同类issue或issue未被解答。
|
||||
|
||||
|
||||
#### You could ask a usage or consultation question here, before your start, please make sure:
|
||||
|
||||
- 1) You have searched your question on Baidu/Google, but found no answer;
|
||||
|
||||
- 2) You have checked the [API documentation](https://www.paddlepaddle.org.cn/documentation/docs/en/api/index_en.html), but found no answer;
|
||||
|
||||
- 3) You have searched [the existing and past issues](https://github.com/PaddlePaddle/Paddle/issues), but found no similar issue or the issue has not been answered.
|
||||
|
||||
|
||||
|
||||
- type: textarea
|
||||
id: question
|
||||
attributes:
|
||||
label: 请提出你的问题 Please ask your question
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,23 @@
|
||||
name: 🧩 其他 Others
|
||||
description: 提出其他问题。 Report any other non-support related issues.
|
||||
labels: [type/others, status/new-issue]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
#### 你可以在这里提出任何前面几类模板不适用的问题,包括但不限于:优化性建议、框架使用体验反馈、版本兼容性问题、报错信息不清楚等。
|
||||
|
||||
#### You can report any issues that are not applicable to the previous types of templates, including but not limited to: enhancement suggestions, feedback on the use of the framework, version compatibility issues, unclear error information, etc.
|
||||
|
||||
- type: textarea
|
||||
id: others
|
||||
attributes:
|
||||
label: 问题描述 Please describe your issue
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
感谢你的贡献 🎉! Thanks for your contribution 🎉!
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- TemplateReference: https://github.com/PaddlePaddle/Paddle/wiki/PULL-REQUEST-TEMPLATE--REFERENCE -->
|
||||
<!-- Demo: https://github.com/PaddlePaddle/Paddle/pull/24810 -->
|
||||
|
||||
### PR Category
|
||||
<!-- One of [ User Experience | Execute Infrastructure | Operator Mechanism | CINN | Custom Device | Performance Optimization | Distributed Strategy | Parameter Server | Communication Library | Auto Parallel | Inference | Environment Adaptation ] -->
|
||||
|
||||
|
||||
### PR Types
|
||||
<!-- One of [ New features | Bug fixes | Improvements | Performance | BC Breaking | Deprecations | Docs | Devs | Not User Facing | Security | Others ] -->
|
||||
|
||||
|
||||
### Description
|
||||
<!-- Describe what you’ve done -->
|
||||
|
||||
|
||||
### 是否引起精度变化
|
||||
<!-- one of the following [ 是 | 否 ]-->
|
||||
@@ -0,0 +1,30 @@
|
||||
name: 'Rerun Workflow'
|
||||
description: 'Re-run GitHub Actions workflow for a given Pull Request'
|
||||
inputs:
|
||||
GITHUB_TOKEN:
|
||||
description: 'GitHub token with repo scope'
|
||||
required: true
|
||||
OWNER:
|
||||
description: 'Repository owner'
|
||||
required: true
|
||||
REPO:
|
||||
description: 'Repository name'
|
||||
required: true
|
||||
PR_ID:
|
||||
description: 'Pull Request ID'
|
||||
required: true
|
||||
JOB_NAME:
|
||||
description: 'Job name to rerun'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- run: bash ./.github/actions/rerun-workflow/rerun.sh
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
|
||||
OWNER: ${{ inputs.OWNER }}
|
||||
REPO: ${{ inputs.REPO }}
|
||||
PR_ID: ${{ inputs.PR_ID }}
|
||||
JOB_NAME: ${{ inputs.JOB_NAME }}
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -e
|
||||
|
||||
COMMIT_SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/pulls/$PR_ID" | jq -r '.head.sha')
|
||||
|
||||
echo "Commit SHA: $COMMIT_SHA"
|
||||
|
||||
response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?head_sha=$COMMIT_SHA&per_page=100")
|
||||
|
||||
echo "Response: $response"
|
||||
|
||||
run_ids=$(echo "$response" | jq -r '.workflow_runs[].id')
|
||||
|
||||
if [ -n "$run_ids" ]; then
|
||||
echo "Found run_ids for commit $COMMIT_SHA: $run_ids"
|
||||
|
||||
for run_id in $run_ids; do
|
||||
if [ "$JOB_NAME" = "all-failed" ]; then
|
||||
echo "Rerunning all failed jobs for run_id: $run_id"
|
||||
|
||||
rerun_response=$(curl -X POST -s -w "%{http_code}" -o /dev/null \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/actions/runs/$run_id/rerun-failed-jobs")
|
||||
if [ "$rerun_response" -eq 201 ]; then
|
||||
echo "Successfully requested rerun for all blocked jobs in run_id: $run_id"
|
||||
else
|
||||
echo "Failed to request rerun for run_id: $run_id with status code $rerun_response"
|
||||
fi
|
||||
|
||||
else
|
||||
jobs_response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/actions/runs/$run_id/jobs")
|
||||
|
||||
echo "Jobs Response for run_id $run_id: $jobs_response"
|
||||
|
||||
# if [[ "$JOB_NAME" == *"bypass"* ]]; then
|
||||
block_jobs=$(echo "$jobs_response" | jq -r --arg job_name "$JOB_NAME" \
|
||||
'.jobs[] | select(.name == $job_name) | .id')
|
||||
# else
|
||||
# block_jobs=$(echo "$jobs_response" | jq -r --arg job_name "$JOB_NAME" \
|
||||
# '.jobs[] | select(.name == $job_name and .conclusion != "success") | .id')
|
||||
# fi
|
||||
|
||||
if [ -n "$block_jobs" ]; then
|
||||
echo "Found block jobs for run_id $run_id: $block_jobs"
|
||||
|
||||
for job_id in $block_jobs; do
|
||||
echo "Rerunning job_id: $job_id"
|
||||
curl -X POST -H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$OWNER/$REPO/actions/jobs/$job_id/rerun"
|
||||
done
|
||||
else
|
||||
echo "No block jobs found for run_id $run_id with name $JOB_NAME."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "No matching workflow runs found for commit $COMMIT_SHA."
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,47 @@
|
||||
name: 'PR Skip Check'
|
||||
description: 'Check if PR should skip CI based on file paths'
|
||||
author: 'Paddle CI Team'
|
||||
|
||||
inputs:
|
||||
ignore-paths:
|
||||
description: 'Comma-separated paths to ignore (e.g., "skill/**,docs/**,**.md")'
|
||||
required: true
|
||||
default: '.agents/skills/**'
|
||||
base-ref:
|
||||
description: 'Base branch (defaults to PR target branch)'
|
||||
required: false
|
||||
default: ${{ github.event.pull_request.base.ref }}
|
||||
|
||||
outputs:
|
||||
should-skip:
|
||||
description: 'Whether CI should be skipped (true/false)'
|
||||
value: ${{ steps.check.outputs.should-skip }}
|
||||
is-pr:
|
||||
description: 'Whether it is a PR event'
|
||||
value: ${{ steps.check.outputs.is-pr }}
|
||||
changed-files:
|
||||
description: 'List of all changed files (newline separated)'
|
||||
value: ${{ steps.check.outputs.changed-files }}
|
||||
non-ignored-files:
|
||||
description: 'List of files not in ignored paths'
|
||||
value: ${{ steps.check.outputs.non-ignored-files }}
|
||||
total-count:
|
||||
description: 'Total number of changed files'
|
||||
value: ${{ steps.check.outputs.total-count }}
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run PR skip check script
|
||||
id: check
|
||||
shell: bash
|
||||
run: bash ${{ github.action_path }}/check_skip.sh
|
||||
env:
|
||||
IGNORE_PATHS: ${{ inputs.ignore-paths }}
|
||||
BASE_REF: ${{ inputs.base-ref }}
|
||||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 [PR Skip Check] Starting..."
|
||||
|
||||
# Parse input parameters
|
||||
IFS=',' read -ra IGNORE_PATHS <<< "${IGNORE_PATHS:-skill/**}"
|
||||
BASE_REF="${BASE_REF:-$GITHUB_BASE_REF}"
|
||||
|
||||
echo "📋 Event type: $GITHUB_EVENT_NAME"
|
||||
echo "📋 Ignore path patterns:"
|
||||
printf ' - %s\n' "${IGNORE_PATHS[@]}"
|
||||
|
||||
# Initialize output
|
||||
IS_PR="false"
|
||||
SHOULD_SKIP="false"
|
||||
CHANGED_FILES=""
|
||||
NON_IGNORED_FILES=""
|
||||
TOTAL_COUNT=0
|
||||
|
||||
# Check if PR event
|
||||
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
||||
IS_PR="true"
|
||||
echo "🔄 Detected PR event, running skip check"
|
||||
|
||||
# Get PR changed files
|
||||
get_pr_changed_files() {
|
||||
local files=""
|
||||
|
||||
if [ -n "$BASE_REF" ]; then
|
||||
echo "📌 Base branch: $BASE_REF" >&2
|
||||
files=$(git diff --name-only "origin/$BASE_REF...HEAD" 2>/dev/null)
|
||||
else
|
||||
echo "⚠️ No base branch specified, using HEAD^..HEAD" >&2
|
||||
files=$(git diff --name-only HEAD^ HEAD 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
echo "$files" | grep -v '^$' || echo ""
|
||||
}
|
||||
|
||||
CHANGED_FILES=$(get_pr_changed_files)
|
||||
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "📋 PR changed files:"
|
||||
echo "$CHANGED_FILES" | sed 's/^/ - /'
|
||||
|
||||
# Count total
|
||||
TOTAL_COUNT=$(echo "$CHANGED_FILES" | wc -l | xargs)
|
||||
|
||||
# Check if files match ignore patterns
|
||||
check_files() {
|
||||
local non_ignored=""
|
||||
|
||||
echo "🔍 [DEBUG] Starting to check files..." >&2
|
||||
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
echo "🔍 [DEBUG] Checking file: '$file'" >&2
|
||||
|
||||
is_ignored=false
|
||||
echo "🔍 [DEBUG] IGNORE_PATHS length: ${#IGNORE_PATHS[@]}" >&2
|
||||
for pattern in "${IGNORE_PATHS[@]}"; do
|
||||
pattern=$(echo "$pattern" | xargs)
|
||||
echo "🔍 [DEBUG] Original pattern: '$pattern'" >&2
|
||||
if [ -n "$pattern" ]; then
|
||||
# Replace ** with * for bash pattern matching
|
||||
bash_pattern="${pattern//\**/*}"
|
||||
echo "🔍 [DEBUG] bash_pattern: '$bash_pattern'" >&2
|
||||
# Debug: show pattern matching
|
||||
if [[ "$file" == $bash_pattern ]]; then
|
||||
is_ignored=true
|
||||
echo " ✅ Ignored: $file (pattern: $pattern -> $bash_pattern)" >&2
|
||||
break
|
||||
else
|
||||
echo " 🔍 Check: $file (pattern: $pattern -> $bash_pattern) - no match" >&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$is_ignored" = false ]; then
|
||||
echo " ❌ Not ignored: $file" >&2
|
||||
if [ -z "$non_ignored" ]; then
|
||||
non_ignored="$file"
|
||||
else
|
||||
non_ignored="$non_ignored"$'\n'"$file"
|
||||
fi
|
||||
fi
|
||||
done <<< "$CHANGED_FILES"
|
||||
|
||||
echo "$non_ignored"
|
||||
}
|
||||
|
||||
NON_IGNORED_FILES=$(check_files)
|
||||
|
||||
echo "📋 Non-ignored files:"
|
||||
echo "$NON_IGNORED_FILES" | sed 's/^/ - /'
|
||||
|
||||
# Determine if should skip
|
||||
if [ -z "$NON_IGNORED_FILES" ]; then
|
||||
SHOULD_SKIP="true"
|
||||
echo "✅ All PR changes are in ignored paths, can skip CI"
|
||||
else
|
||||
SHOULD_SKIP="false"
|
||||
echo "❌ Some files not in ignored paths, continue CI"
|
||||
fi
|
||||
else
|
||||
echo "📭 No changed files detected in PR"
|
||||
SHOULD_SKIP="false"
|
||||
fi
|
||||
else
|
||||
# Non-PR event (push, workflow_dispatch, etc.)
|
||||
echo "🔄 not a PR event ($GITHUB_EVENT_NAME), run CI"
|
||||
SHOULD_SKIP="false"
|
||||
fi
|
||||
|
||||
# Set output variables
|
||||
echo "should-skip=$SHOULD_SKIP" >> $GITHUB_OUTPUT
|
||||
echo "is-pr=$IS_PR" >> $GITHUB_OUTPUT
|
||||
echo "total-count=$TOTAL_COUNT" >> $GITHUB_OUTPUT
|
||||
|
||||
# Handle multiline output (changed-files)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo 'changed-files<<EOF' >> $GITHUB_OUTPUT
|
||||
echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changed-files=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Handle multiline output (non-ignored-files)
|
||||
if [ -n "$NON_IGNORED_FILES" ]; then
|
||||
echo 'non-ignored-files<<EOF' >> $GITHUB_OUTPUT
|
||||
echo "$NON_IGNORED_FILES" >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "non-ignored-files=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
echo "📊 total=$TOTAL_COUNT, can skip=$SHOULD_SKIP"
|
||||
echo "✅ [PR Skip Check] finished"
|
||||
@@ -0,0 +1,13 @@
|
||||
codecov:
|
||||
notify:
|
||||
wait_for_ci: false
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 50% # overall project Coverage
|
||||
threshold: 1% # Allow the coverage to drop by 1%, and posting a success status.
|
||||
patch:
|
||||
default:
|
||||
target: 90% # lines adjusted Coverage < 80% CI will fail
|
||||
@@ -0,0 +1,87 @@
|
||||
name: Api-benchmark-baseline
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
PR_ID:
|
||||
required: false
|
||||
type: string
|
||||
COMMIT_ID:
|
||||
required: false
|
||||
type: string
|
||||
job-name:
|
||||
required: true
|
||||
default: 'api-benchmark'
|
||||
type: choice
|
||||
options:
|
||||
- api-benchmark
|
||||
- others
|
||||
schedule:
|
||||
- cron: '0 21 * * *'
|
||||
|
||||
permissions: read-all
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
clone:
|
||||
name: Api benchmark clone
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
is_pr: 'false'
|
||||
|
||||
build-docker:
|
||||
name: Api benchmark build docker
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
task: build
|
||||
|
||||
build:
|
||||
name: Api benchmark build
|
||||
if: github.event_name == 'schedule' && github.event.schedule == '0 21 * * *'
|
||||
needs: [clone, build-docker]
|
||||
uses: ./.github/workflows/_Linux-build.yml
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
is_pr: 'false'
|
||||
|
||||
api-benchmark-baseline-schedule:
|
||||
name: Api benchmark baseline with schedule
|
||||
strategy:
|
||||
matrix:
|
||||
run-labels: [api-bm-20, api-bm-27]
|
||||
uses: ./.github/workflows/_Api-Benchmark.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
baseline: 'true'
|
||||
run-labels: ${{ matrix.run-labels }}
|
||||
|
||||
api-benchmark-baseline-pr-20:
|
||||
name: Api benchmark baseline with PR on 20
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.job-name == 'api-benchmark'
|
||||
uses: ./.github/workflows/_Api-Benchmark.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
baseline: 'true'
|
||||
MANUALLY_PR_ID: ${{ inputs.PR_ID }}
|
||||
MANUALLY_COMMIT_ID: ${{ inputs.COMMIT_ID }}
|
||||
run-labels: api-bm-20
|
||||
|
||||
api-benchmark-baseline-pr-27:
|
||||
name: Api benchmark baseline with PR on 27
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.job-name == 'api-benchmark'
|
||||
uses: ./.github/workflows/_Api-Benchmark.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
baseline: 'true'
|
||||
MANUALLY_PR_ID: ${{ inputs.PR_ID }}
|
||||
MANUALLY_COMMIT_ID: ${{ inputs.COMMIT_ID }}
|
||||
run-labels: api-bm-27
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Approval
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
env:
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
token: ${{ vars.ACTION_GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: 'approval'
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
check-approvers:
|
||||
name: Check approval
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 200
|
||||
|
||||
- name: Update paddle
|
||||
run: |
|
||||
git switch -c test
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
git fetch upstream $BRANCH
|
||||
git checkout $BRANCH
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git merge test
|
||||
|
||||
- name: Display Required Approvers
|
||||
run: |
|
||||
bash ci/check_approval.sh
|
||||
@@ -0,0 +1,154 @@
|
||||
name: CI-Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches: [develop, release/**, fleety_*]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
jobs:
|
||||
check-skill:
|
||||
name: Check file paths
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
outputs:
|
||||
can-skip: ${{ steps.skip-skill.outputs.should-skip || 'false' }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Run skip check
|
||||
id: skip-skill
|
||||
uses: ./.github/actions/skip-skill
|
||||
with:
|
||||
ignore-paths: '.agents/skills/**'
|
||||
|
||||
clone:
|
||||
name: Clone-linux
|
||||
needs: check-skill
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
workflow-name: 'CI-build'
|
||||
skill-can-skip: ${{ needs.check-skill.outputs.can-skip }}
|
||||
|
||||
build-docker:
|
||||
name: build docker images
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
task: build
|
||||
|
||||
inference:
|
||||
name: PR-CI-Inference
|
||||
uses: ./.github/workflows/_Inference.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_inference_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
build:
|
||||
name: Linux-build
|
||||
uses: ./.github/workflows/_Linux-build.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
static-check:
|
||||
name: Static-Check
|
||||
uses: ./.github/workflows/_Static-Check.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
ce-framework:
|
||||
name: CE-Framework
|
||||
uses: ./.github/workflows/_CE-Framework.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
ce-cinn-framework:
|
||||
name: CE-CINN-Framework
|
||||
uses: ./.github/workflows/_CE-CINN-Framework.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
api-benchmark:
|
||||
name: Api-Benchmark
|
||||
uses: ./.github/workflows/_Api-Benchmark.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
# auto-parallel:
|
||||
# name: Auto-Parallel
|
||||
# uses: ./.github/workflows/_Auto-Parallel.yml
|
||||
# needs: [clone, build-docker, build]
|
||||
# with:
|
||||
# can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
# docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
model-benchmark:
|
||||
name: Model-Benchmark
|
||||
uses: ./.github/workflows/_Model-Benchmark.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
|
||||
doc-preview:
|
||||
name: Doc-Preview
|
||||
uses: ./.github/workflows/_Doc-Preview.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_doc_image: ${{ needs.build-docker.outputs.docker_doc_image }}
|
||||
|
||||
slice:
|
||||
name: Slice
|
||||
uses: ./.github/workflows/_Slice.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
slice-check: ${{ needs.clone.outputs.slice-check }}
|
||||
|
||||
deepmd-test:
|
||||
name: DeepMD-Kit-Test
|
||||
uses: ./.github/workflows/_Deepmd-pd-test.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
build-can-skip: ${{ needs.build.outputs.can-skip }}
|
||||
can-skip: ${{ needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
@@ -0,0 +1,66 @@
|
||||
name: CI-Windows
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches: [develop, release/**, fleety_*]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
jobs:
|
||||
check-skill:
|
||||
name: Check file paths
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
can-skip: ${{ steps.skip-skill.outputs.should-skip }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Run skip check
|
||||
id: skip-skill
|
||||
uses: ./.github/actions/skip-skill
|
||||
with:
|
||||
ignore-paths: '.agents/skills/**'
|
||||
|
||||
clone:
|
||||
name: Clone-windows
|
||||
needs: check-skill
|
||||
uses: ./.github/workflows/_Clone-windows.yml
|
||||
with:
|
||||
skill-can-skip: ${{ needs.check-skill.outputs.can-skip }}
|
||||
|
||||
win-openblas:
|
||||
name: Windows-OPENBLAS
|
||||
uses: ./.github/workflows/_Windows-OPENBLAS.yml
|
||||
needs: clone
|
||||
with:
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
win-gpu:
|
||||
name: Windows-GPU
|
||||
uses: ./.github/workflows/_Windows-GPU.yml
|
||||
needs: clone
|
||||
with:
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
win-inference:
|
||||
name: Windows-Inference
|
||||
uses: ./.github/workflows/_Windows-Inference.yml
|
||||
needs: clone
|
||||
with:
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
@@ -0,0 +1,129 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches: [develop, release/**, fleety_*]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
jobs:
|
||||
check-skill:
|
||||
name: Check file paths
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
can-skip: ${{ steps.skip-skill.outputs.should-skip }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Run skip check
|
||||
id: skip-skill
|
||||
uses: ./.github/actions/skip-skill
|
||||
with:
|
||||
ignore-paths: '.agents/skills/**'
|
||||
|
||||
clone:
|
||||
name: Clone-linux
|
||||
needs: check-skill
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
workflow-name: 'CI'
|
||||
skill-can-skip: ${{ needs.check-skill.outputs.can-skip }}
|
||||
|
||||
build-docker:
|
||||
name: build docker images
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
|
||||
sot:
|
||||
name: PR-CI-SOT
|
||||
uses: ./.github/workflows/_SOT.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_sot_image: ${{ needs.build-docker.outputs.docker_sot_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
mac:
|
||||
name: Mac-CPU
|
||||
uses: ./.github/workflows/_Mac.yml
|
||||
needs: clone
|
||||
with:
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
xpu:
|
||||
name: Linux-XPU
|
||||
uses: ./.github/workflows/_Linux-XPU.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_xpu_image: ${{ needs.build-docker.outputs.docker_xpu_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
dcu:
|
||||
name: Linux-DCU
|
||||
uses: ./.github/workflows/_Linux-DCU.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_dcu_image: ${{ needs.build-docker.outputs.docker_dcu_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
cpu:
|
||||
name: Linux-CPU
|
||||
uses: ./.github/workflows/_Linux-CPU.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_cpu_image: ${{ needs.build-docker.outputs.docker_cpu_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
npu:
|
||||
name: Linux-NPU
|
||||
uses: ./.github/workflows/_Linux-NPU.yml
|
||||
needs: [clone, cpu, build-docker]
|
||||
with:
|
||||
can-skip: ${{ needs.cpu.outputs.can-skip == 'true' || needs.clone.outputs.can-skip == 'true' }}
|
||||
docker_npu_image: ${{ needs.build-docker.outputs.docker_npu_image }}
|
||||
|
||||
# ixuca:
|
||||
# name: Linux-IXUCA
|
||||
# uses: ./.github/workflows/_Linux-IXUCA.yml
|
||||
# needs: [clone]
|
||||
# with:
|
||||
# can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
distribute:
|
||||
name: Distribute-stable-build
|
||||
uses: ./.github/workflows/_Distribute-stable.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_distribute_image: ${{ needs.build-docker.outputs.docker_distribute_image }}
|
||||
clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
# distribute-test:
|
||||
# name: Distribute-stable-test
|
||||
# uses: ./.github/workflows/_Distribute-stable-Test.yml
|
||||
# needs: [clone, build-docker, distribute]
|
||||
# with:
|
||||
# docker_distribute_image: ${{ needs.build-docker.outputs.docker_distribute_image }}
|
||||
# clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
|
||||
# distribute-formers:
|
||||
# name: Distribute-stable-formers
|
||||
# uses: ./.github/workflows/_Distribute-stable-Formers.yml
|
||||
# needs: [clone, build-docker, distribute]
|
||||
# with:
|
||||
# docker_distribute_image: ${{ needs.build-docker.outputs.docker_distribute_image }}
|
||||
# clone-can-skip: ${{ needs.clone.outputs.can-skip }}
|
||||
@@ -0,0 +1,62 @@
|
||||
name: Check PR Template
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [develop, release/**]
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: 'template'
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
check:
|
||||
name: Check
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: Template
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Clone paddle
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check PR Template
|
||||
env:
|
||||
AGILE_PULL_ID: ${{ github.event.pull_request.number }}
|
||||
AGILE_COMPILE_BRANCH: ${{ github.base_ref }}
|
||||
AGILE_CHECKIN_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
method: check_pr
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
run: |
|
||||
set +e
|
||||
python3 tools/CheckPRTemplate.py
|
||||
EXCODE=$?
|
||||
set -e
|
||||
echo "EXCODE: $EXCODE"
|
||||
echo "ipipe_log_param_EXCODE: $EXCODE"
|
||||
if [[ "$EXCODE" != "0" ]];then
|
||||
echo -e "######################################################"
|
||||
echo -e "If you encounter a situation where the PR template does not match the error message, please use the following link to update your PR: [ https://raw.githubusercontent.com/PaddlePaddle/Paddle/develop/.github/PULL_REQUEST_TEMPLATE.md ]"
|
||||
echo -e "## Reference Documentation: ##"
|
||||
echo -e "[ https://github.com/PaddlePaddle/Paddle/wiki/PULL-REQUEST-TEMPLATE--REFERENCE ]"
|
||||
echo -e "[ https://github.com/PaddlePaddle/Paddle/wiki/paddle_ci_manual ]"
|
||||
echo -e "######################################################"
|
||||
exit $EXCODE
|
||||
fi
|
||||
export method=$method
|
||||
echo $method
|
||||
set +x
|
||||
source ~/.icafe
|
||||
wget -q --no-check-certificate https://paddle-qa.bj.bcebos.com/baidu/cloud/modify_icafe.py
|
||||
set -x
|
||||
python3 modify_icafe.py
|
||||
@@ -0,0 +1,62 @@
|
||||
name: Codestyle-Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [develop, release/**]
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "codestyle"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
pre-commit:
|
||||
name: Pre Commit
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass]
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
BRANCH: develop
|
||||
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout base repo
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
fetch-depth: 1000
|
||||
|
||||
- name: Merge PR to test branch
|
||||
run: |
|
||||
git fetch origin pull/${PR_ID}/merge
|
||||
git checkout -b test FETCH_HEAD
|
||||
|
||||
- name: Setup python3.12
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install pre-commit==2.17.0
|
||||
pip install ast-grep-cli==0.44.0 # This version should be consistent with the one in .pre-commit-config.yaml
|
||||
|
||||
- name: Run ast-grep unit tests
|
||||
run: |
|
||||
ast-grep test
|
||||
|
||||
- name: Check pre-commit
|
||||
run: |
|
||||
set +e
|
||||
bash -x tools/codestyle/pre_commit.sh;EXCODE=$?
|
||||
exit $EXCODE
|
||||
@@ -0,0 +1,426 @@
|
||||
name: Coverage
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches: [develop, release/**]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-coverage
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
CI_name: coverage
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-skill:
|
||||
name: Check file paths
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
outputs:
|
||||
can-skip: ${{ steps.skip-skill.outputs.should-skip || 'false' }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Run skip check
|
||||
id: skip-skill
|
||||
uses: ./.github/actions/skip-skill
|
||||
with:
|
||||
ignore-paths: '.agents/skills/**'
|
||||
|
||||
clone:
|
||||
name: Coverage clone
|
||||
needs: check-skill
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
workflow-name: "coverage"
|
||||
clone_dir: Paddle-coverage
|
||||
skill-can-skip: ${{ needs.check-skill.outputs.can-skip }}
|
||||
|
||||
build-docker:
|
||||
name: Coverage build docker
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
clone_dir: Paddle-coverage
|
||||
task: coverage
|
||||
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
needs: [clone]
|
||||
if: needs.clone.outputs.can-skip != 'true'
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: coverage
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Coverage build
|
||||
needs: [clone, build-docker, check-bypass]
|
||||
if: ${{ needs.clone.outputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
outputs:
|
||||
can-skip: ${{ needs.check-bypass.outputs.can-skip }}
|
||||
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Volta
|
||||
WITH_AVX: "ON"
|
||||
WITH_COVERAGE: "ON"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
CUDA_VISIBLE_DEVICES: 0,1
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_PIP_CUDA_LIBRARIES: "OFF"
|
||||
WITH_FLAGCX: "ON"
|
||||
LITE_GIT_TAG: develop
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
ON_INFER: "ON"
|
||||
PADDLE_CUDA_INSTALL_REQUIREMENTS: "ON"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
UT_RUN_TYPE_SETTING: WITHOUT_HYBRID
|
||||
run: |
|
||||
container_name=${TASK}-build-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ needs.build-docker.outputs.docker_coverage_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e WITH_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_PIP_CUDA_LIBRARIES \
|
||||
-e WITH_FLAGCX \
|
||||
-e LITE_GIT_TAG \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ON_INFER \
|
||||
-e PADDLE_CUDA_INSTALL_REQUIREMENTS \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e UT_RUN_TYPE_SETTING \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle-coverage/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream $BRANCH"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir -p ${CFS_DIR}/.cache/coverage
|
||||
mkdir -p ${CFS_DIR}/.ccache/coverage
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash $ci_scripts/coverage_build.sh bdist_wheel
|
||||
'
|
||||
|
||||
- name: Check added unittests
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash $ci_scripts/check_added_ut.sh
|
||||
'
|
||||
|
||||
- name: Check coverage build size requires approval
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash $ci_scripts/coverage_build_size_approval.sh
|
||||
'
|
||||
|
||||
- name: Clean up env
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/utils.sh; clean_build_files
|
||||
Build_Size=$(du -h --max-depth=0 ${work_dir}/build |awk '"'"'{print $1}'"'"')
|
||||
echo "Build_Size=${Build_Size}" > ${work_dir}/dist/coverage_build_size
|
||||
find ./ -type f -size +200M | xargs du -lh
|
||||
rm -rf $(find . -name "*.a")
|
||||
rm -rf $(find . -name "*.o")
|
||||
rm -rf paddle_inference_install_dir
|
||||
rm -rf paddle_inference_c_install_dir
|
||||
rm -rf lib.linux-x86_64-${PY_VERSION}
|
||||
find ./ -name "eager_generator" -or -name "kernel_signature_generator" -or -name "eager_legacy_op_function_generator" | xargs rm -rf
|
||||
rm -rf ./python/build/lib.linux-x86_64-${PY_VERSION}/
|
||||
cd "${work_dir}/build/third_party" && find $(ls | grep -v "dlpack" | grep -v "install" | grep -v "eigen3" | grep -v "gflags") -type f ! -name "*.so" -a ! -name "libdnnl.so*" -delete
|
||||
cd /
|
||||
tar --use-compress-program="pzstd -1" -cf Paddle.tar.gz paddle
|
||||
'
|
||||
|
||||
- name: Upload coverage product
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
paddle_whl: paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd /paddle/dist
|
||||
mkdir -p ${CFS_DIR}/coverage_bos/${PR_ID}/${COMMIT_ID}
|
||||
echo "Uploading coverage build size"
|
||||
python ${{ env.bos_file }} coverage_build_size paddle-github-action/PR/coverage/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading coverage wheel"
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/coverage/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
cd /
|
||||
echo "Uploading Paddle.tar.gz"
|
||||
cp Paddle.tar.gz ${CFS_DIR}/coverage_bos/${PR_ID}/${COMMIT_ID}
|
||||
rm Paddle.tar.gz
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
|
||||
test:
|
||||
name: Coverage test
|
||||
needs: [build, build-docker]
|
||||
if: needs.build.outputs.can-skip != 'true'
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 240
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/root/.ccache/coverage"
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Auto
|
||||
WITH_AVX: "ON"
|
||||
WITH_COVERAGE: "ON"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_MAXSIZE: 200G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
FLAGS_PIR_OPTEST: "TRUE"
|
||||
ON_INFER: "ON"
|
||||
COVERAGE_FILE: ${{ github.workspace }}/build/python-coverage.data
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ needs.build-docker.outputs.docker_coverage_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e WITH_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e FLAGS_PIR_OPTEST \
|
||||
-e ON_INFER \
|
||||
-e COVERAGE_FILE \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/coverage_bos/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz .
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program="pzstd -1" -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash $ci_scripts/coverage_test.sh
|
||||
TEST_EXIT_CODE=$?
|
||||
echo "TEST_EXIT_CODE=${TEST_EXIT_CODE}" >> ${{ github.env }}
|
||||
if [[ "$TEST_EXIT_CODE" -ne 0 && "$TEST_EXIT_CODE" -ne 9 ]]; then
|
||||
exit $TEST_EXIT_CODE
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Generate coverage information
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
unset GREP_OPTIONS
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ${ci_scripts}/utils.sh; check_coverage
|
||||
mkdir -p /home/data/cfs/coverage/${PR_ID}/${COMMIT_ID}
|
||||
cp build/coverage_files/* /home/data/cfs/coverage/${PR_ID}/${COMMIT_ID}
|
||||
'
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: codecov/codecov-action@v6
|
||||
with:
|
||||
directory: build/coverage_files
|
||||
verbose: true
|
||||
|
||||
- name: Determine whether the coverage rate reaches 90%
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
unset GREP_OPTIONS
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ${ci_scripts}/utils.sh
|
||||
bash $ci_scripts/coverage_judge.sh
|
||||
COVERAGE_EXIT_CODE=$?
|
||||
echo $COVERAGE_EXIT_CODE
|
||||
if [ "$COVERAGE_EXIT_CODE" -ne 0 ]; then
|
||||
echo "Coverage check failed, unit tests have all passed, please do not rerun, check whether the newly added code lines are fully covered by unit tests. If you have any questions, please contact XieYunshen."
|
||||
exit $COVERAGE_EXIT_CODE
|
||||
else
|
||||
echo "Coverage passed"
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
rm Paddle.tar.gz
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,736 @@
|
||||
name: CI-H
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches: [develop, release/**]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-coverage
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
CI_name: h-coverage
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
fleet_branch: "release/0.2"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-skill:
|
||||
name: Check file paths
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
outputs:
|
||||
can-skip: ${{ steps.skip-skill.outputs.should-skip }}
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Run skip check
|
||||
id: skip-skill
|
||||
uses: ./.github/actions/skip-skill
|
||||
with:
|
||||
ignore-paths: '.agents/skills/**'
|
||||
- name: Print outputs
|
||||
if: always()
|
||||
run: |
|
||||
echo "=== check-skill outputs ==="
|
||||
echo "steps.skip-skill.outputs.should-skip: '${{ steps.skip-skill.outputs.should-skip }}'"
|
||||
echo "============================"
|
||||
|
||||
clone:
|
||||
name: Coverage clone
|
||||
needs: [check-skill]
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
workflow-name: "coverage"
|
||||
clone_dir: h-ci
|
||||
skill-can-skip: ${{ needs.check-skill.outputs.can-skip }}
|
||||
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
needs: [clone]
|
||||
if: ${{ needs.clone.outputs.can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: h-ci
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Coverage build
|
||||
needs: [clone, check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && needs.clone.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
outputs:
|
||||
can-skip: ${{ needs.check-bypass.outputs.can-skip == 'true' || needs.clone.outputs.can-skip == 'true' || 'false' }}
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Hopper
|
||||
WITH_AVX: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
CUDA_VISIBLE_DEVICES: 0,1
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
LITE_GIT_TAG: develop
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_FA_BUILD_WITH_CACHE: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-build-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:ubuntu24-cuda129-py312-dev
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e LITE_GIT_TAG \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e WITH_FA_BUILD_WITH_CACHE \
|
||||
-e PY_VERSION \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/h-ci/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git config --global --add safe.directory "*"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream $BRANCH"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
flashattn_version=$(git submodule status|grep flashattn|awk "{print \$1}"|sed "s#-##g")
|
||||
echo flashattn_version:$flashattn_version
|
||||
url="https://xly-devops.bj.bcebos.com/gpups/flash-attention/cu90/flashattn_libs_${flashattn_version}.tar"
|
||||
echo url:$url
|
||||
url_return=`curl -s -o /dev/null -w "%{http_code}" $url`
|
||||
if [ "$url_return" != "200" ];then
|
||||
echo "flashattn cache not found, please contact umiswing"
|
||||
exit 7
|
||||
fi
|
||||
mkdir -p ${CFS_DIR}/.cache/coverage
|
||||
mkdir -p ${CFS_DIR}/.ccache/coverage
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-12.9/compat
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash ${ci_scripts}/cmake_preload_data_file.sh
|
||||
pip install -r python/requirements.txt
|
||||
mkdir -p build && cd build
|
||||
ccache -z
|
||||
cmake .. -DPY_VERSION=3.12 -DWITH_GPU=ON -DWITH_DISTRIBUTE=ON -DWITH_TESTING=ON -DCUDA_ARCH_NAME=Manual -DCUDA_ARCH_BIN="90" -DFA_JOB_POOLS_COMPILE=1 -DWITH_CUDNN_FRONTEND=ON -DON_INFER=OFF -DWITH_NVSHMEM=ON
|
||||
make -j20
|
||||
EXIT_CODE=$?
|
||||
ccache -s
|
||||
exit $EXIT_CODE
|
||||
'
|
||||
|
||||
- name: Clean up env
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/utils.sh; clean_build_files
|
||||
: "${PY_VERSION:?PY_VERSION is required}"
|
||||
rm -rf $(find . -name "*.a")
|
||||
rm -rf $(find . -name "*.o")
|
||||
rm -rf lib.linux-x86_64-${PY_VERSION}
|
||||
find ./ -name "eager_generator" -or -name "kernel_signature_generator" -or -name "eager_legacy_op_function_generator" | xargs rm -rf
|
||||
rm -rf ./python/build/lib.linux-x86_64-${PY_VERSION}/
|
||||
cd "${work_dir}/build/third_party" && find $(ls | grep -v "dlpack" | grep -v "install" | grep -v "eigen3" | grep -v "gflags") -type f ! -name "*.so" -a ! -name "libdnnl.so*" -delete
|
||||
cd /
|
||||
tar --use-compress-program="pzstd -1" -cf Paddle.tar.gz paddle
|
||||
'
|
||||
|
||||
- name: Upload coverage product
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
paddle_whl: paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd /paddle
|
||||
mv /Paddle.tar.gz .
|
||||
cp ./build/python/dist/paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl .
|
||||
echo "Uploading Paddle.tar.gz"
|
||||
python ${{ env.bos_file }} Paddle.tar.gz paddle-github-action/PR/h-coverage/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading coverage wheel"
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/h-coverage/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "End Upload"
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
|
||||
test:
|
||||
name: Coverage test
|
||||
needs: [build, check-bypass, check-skill]
|
||||
if: ${{ needs.build.outputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' && needs.check-skill.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: H-Coverage
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
runner_name=`(echo $PWD|awk -F '/' '{print $3}')`
|
||||
echo $runner_name
|
||||
wget -q https://xly-devops.bj.bcebos.com/utils.sh
|
||||
source utils.sh
|
||||
determine_gpu_runner ${runner_name}
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/root/.ccache/coverage"
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Hopper
|
||||
WITH_AVX: "ON"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
GPU_DEVICES: ${{ env.GPU_DEVICES }}
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_MAXSIZE: 200G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
FLAGS_PIR_OPTEST: "TRUE"
|
||||
ON_INFER: "ON"
|
||||
COVERAGE_FILE: ${{ github.workspace }}/build/python-coverage.data
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:ubuntu24-cuda129-py312-dev
|
||||
docker run -d -t --gpus "\"device=${GPU_DEVICES}\"" --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e WITH_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e FLAGS_PIR_OPTEST \
|
||||
-e ON_INFER \
|
||||
-e COVERAGE_FILE \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/h-coverage/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program="pzstd -1" -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
'
|
||||
|
||||
- name: Test
|
||||
id: unit_test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
pip install build//python/dist/*.whl --no-deps
|
||||
pip install -r python/unittest_py/requirements.txt
|
||||
bash $ci_scripts/h-test.sh
|
||||
'
|
||||
|
||||
- name: FA Test
|
||||
if: (success() || failure()) && steps.unit_test.conclusion != 'skipped'
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install pytest einops
|
||||
cd test/test_flashmask_ci
|
||||
bash run.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
rm Paddle.tar.gz
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
|
||||
fleet-build:
|
||||
name: Build Fleet whl
|
||||
needs: [build, check-bypass, check-skill]
|
||||
if: ${{ needs.build.outputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' && needs.check-skill.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
TASK: fleet-ci-paddle-build-whl-${{ github.event.pull_request.number }}
|
||||
docker_image: "ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:ubuntu24-cuda129-py312-dev"
|
||||
PY_VERSION: "3.12"
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
CCACHE_STATSLOG: /paddle/build/.stats.log
|
||||
CCACHE_SLOPPINESS: clang_index_store,time_macros,include_file_mtime
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker pull $docker_image
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e fleet_branch \
|
||||
-e CI_name \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e CCACHE_STATSLOG \
|
||||
-e CCACHE_SLOPPINESS \
|
||||
-e PY_VERSION \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: uv build whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
rm -rf * .[^.]*
|
||||
set -x
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
apt-get update
|
||||
apt-get install -y libnvidia-compute-535
|
||||
python -m pip install --upgrade pip wheel setuptools
|
||||
git clone https://github.com/PaddlePaddle/PaddleFleet.git .
|
||||
git config --global --add safe.directory /paddle
|
||||
git config user.name "PaddleCI"
|
||||
git config user.email "paddle_ci@example.com"
|
||||
git config pull.rebase false
|
||||
if [ "${BRANCH}" != "develop" ]; then
|
||||
git checkout $fleet_branch
|
||||
echo "Checked out fleet branch: $fleet_branch"
|
||||
else
|
||||
git checkout develop
|
||||
echo "Checked out fleet branch: develop"
|
||||
fi
|
||||
mkdir -p /home/.cache/pip
|
||||
pip cache dir
|
||||
echo "Install uv"
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
pip install uv coverage==7.6.1 bce-python-sdk==0.8.74 wrapt
|
||||
echo "uv build"
|
||||
git submodule update --init --recursive
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/compat:$LD_LIBRARY_PATH
|
||||
export IS_NVIDIA=True
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/h-coverage/${PR_ID}/${COMMIT_ID}/paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --no-check-certificate
|
||||
pip uninstall paddlepaddle-gpu -y
|
||||
pip install paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --force-reinstall --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
pip install paddle-nvidia-nvshmem-cu12 --extra-index-url https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
uv build --wheel --no-build-isolation -v --python $(which python)
|
||||
'
|
||||
|
||||
- name: download ops whl from latest
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
set -x
|
||||
OPS_DST=paddlefleet_ops-0.0.0-cp312-cp312-linux_x86_64.whl
|
||||
wget -q --no-proxy "https://paddle-whl.bj.bcebos.com/nightly/cu129/paddlefleet-ops/${OPS_DST}" -O dist/${OPS_DST}
|
||||
'
|
||||
|
||||
- name: upload whl to BOS
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
cd /
|
||||
if [ ! -f "bos/BosClient.py" ]; then
|
||||
wget -q --no-proxy -O bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir bos
|
||||
tar xf bos_new.tar.gz -C bos
|
||||
fi
|
||||
target_path="paddle-github-action/PR/paddlefleet/${{ env.PR_ID }}/${{ env.COMMIT_ID }}"
|
||||
tar zcf paddldfleet.tar.gz paddle
|
||||
python /bos/BosClient.py paddldfleet.tar.gz ${target_path}
|
||||
'
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'bash ci/clean_uv_cache.sh; rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
|
||||
fleet_single_card_test:
|
||||
name: Fleet Unit test (single card)
|
||||
needs: [build, fleet-build]
|
||||
if: needs.build.outputs.can-skip != 'true'
|
||||
runs-on:
|
||||
group: Fleet-H-single-card
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
PIP_CACHE_DIR: /root/.cache/pip
|
||||
CACHE_DIR: /root/.cache
|
||||
TASK: paddle-fleet-CI-${{ github.event.pull_request.number }}-single-card-test
|
||||
PY_VERSION: "3.12"
|
||||
steps:
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
gpu_id=$(( $(echo $PWD | awk -F'/' '{print $3}' | awk -F'-' '{print $2}') - 1 ))
|
||||
echo GPU_DEVICES="$gpu_id" >> $GITHUB_ENV
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
GPU_DEVICES: ${{ env.GPU_DEVICES }}
|
||||
docker_image: "ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:ubuntu24-cuda129-py312-dev"
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker pull $docker_image
|
||||
docker run -d -t --name ${container_name} --gpus "\"device=${GPU_DEVICES}\"" --shm-size=32G \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}/../../../proxy:/root/proxy \
|
||||
-v /ssd1/paddle-1/action_cache:/root/.cache \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e CACHE_DIR \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e PIP_CACHE_DIR \
|
||||
-e PY_VERSION \
|
||||
-e work_dir \
|
||||
-e GITHUB_SHA="${{ github.event.pull_request.head.sha }}" \
|
||||
-e GITHUB_HEAD_REF="${{ github.head_ref }}" \
|
||||
-e GITHUB_BASE_SHA="${{ github.event.pull_request.base.sha }}" \
|
||||
-e GITHUB_REPO_NAME="${{ github.repository }}" \
|
||||
-e GITHUB_EVENT_PULL_REQUEST_NUMBER="${{ github.event.pull_request.number }}" \
|
||||
-e GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" \
|
||||
-e GITHUB_RUN_ID="${{ github.run_id }}" \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Install PaddleFleet
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
rm -rf * .[^.]*
|
||||
source /root/proxy
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
pip install uv coverage==7.6.1 bce-python-sdk==0.8.74 wrapt pytest matplotlib parameterized
|
||||
wget -q --tries=5 --no-proxy --no-check-certificate https://paddle-github-action.cdn.bcebos.com/PR/paddlefleet/${PR_ID}/${COMMIT_ID}/paddldfleet.tar.gz
|
||||
tar -xf paddldfleet.tar.gz --strip-components=1
|
||||
git config --global --add safe.directory /paddle
|
||||
pip install dist/paddlefleet-*.whl --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/ --extra-index-url=https://www.paddlepaddle.org.cn/packages/stable/cu129/
|
||||
pip install dist/paddlefleet_ops-*.whl --extra-index-url=https://www.paddlepaddle.org.cn/packages/stable/cu129/ --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
|
||||
chmod +x /usr/local/bin/yq
|
||||
'
|
||||
|
||||
- name: Download paddle.tar.gz and install paddle whl
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
mkdir -p /PaddlePaddle
|
||||
cd /PaddlePaddle
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/h-coverage/${PR_ID}/${COMMIT_ID}/paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --no-check-certificate
|
||||
export UV_SKIP_WHEEL_FILENAME_CHECK=1 #This environment variable allows installing the latest commit-level whl package of Paddle.
|
||||
export UV_NO_SYNC=1 # This environment variable prevents uv sync from being executed when running un run.
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
pip uninstall paddlepaddle-gpu -y
|
||||
pip install paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --force-reinstall --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
echo "paddlefleet commit:"
|
||||
python -c "import paddlefleet; print(paddlefleet.version.commit)"
|
||||
'
|
||||
|
||||
- name: Single card test
|
||||
timeout-minutes: 60
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -xce '
|
||||
pwd
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
if [ "${BRANCH}" != "develop" ]; then
|
||||
git checkout $fleet_branch
|
||||
echo "Checked out fleet branch: $fleet_branch"
|
||||
else
|
||||
git checkout develop
|
||||
echo "Checked out fleet branch: develop"
|
||||
fi
|
||||
export UV_SKIP_WHEEL_FILENAME_CHECK=1 #This environment variable allows installing the latest commit-level whl package of Paddle.
|
||||
export UV_NO_SYNC=1 # This environment variable prevents uv sync from being executed when running un run.
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
python -c "import paddle; print(paddle.version.commit)"
|
||||
bash ci/single_card_test.sh
|
||||
single_card_exit_code=$?
|
||||
if [[ "$single_card_exit_code" != "0" ]]; then
|
||||
echo -e "::error:: \033[31mSingle card test failed.\033[0m"
|
||||
exit 1
|
||||
else
|
||||
echo -e "\033[32mSingle card test succeeded.\033[0m"
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
|
||||
fleet-multi-card_test:
|
||||
name: Fleet Unit test (multi-card)
|
||||
needs: [build, fleet-build, check-bypass, check-skill]
|
||||
if: ${{ needs.build.outputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' && needs.check-skill.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: Fleet-H-multi-card
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
PIP_CACHE_DIR: /root/.cache/pip
|
||||
TASK: paddle-fleet-CI-${{ github.event.pull_request.number }}-multi-card_test
|
||||
docker_image: "ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:ubuntu24-cuda129-py312-dev"
|
||||
PY_VERSION: "3.12"
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker pull $docker_image
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}/../../../proxy:/root/proxy \
|
||||
-v ${{ github.workspace }}/../../../.cache:/root/.cache \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e CACHE_DIR \
|
||||
-e fleet_branch \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e PIP_CACHE_DIR \
|
||||
-e PY_VERSION \
|
||||
-e work_dir \
|
||||
-e GITHUB_SHA="${{ github.event.pull_request.head.sha }}" \
|
||||
-e GITHUB_HEAD_REF="${{ github.head_ref }}" \
|
||||
-e GITHUB_BASE_SHA="${{ github.event.pull_request.base.sha }}" \
|
||||
-e GITHUB_REPO_NAME="${{ github.repository }}" \
|
||||
-e GITHUB_EVENT_NAME="${{ github.event_name }}" \
|
||||
-e GITHUB_EVENT_PULL_REQUEST_NUMBER="${{ github.event.pull_request.number }}" \
|
||||
-e GITHUB_TOKEN="${{ secrets.GITHUB_TOKEN }}" \
|
||||
-e GITHUB_RUN_ID="${{ github.run_id }}" \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Install PaddleFleet
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
rm -rf * .[^.]*
|
||||
source /root/proxy
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
pip install uv coverage==7.6.1 bce-python-sdk==0.8.74 wrapt pytest matplotlib parameterized
|
||||
wget -q --tries=5 --no-proxy --no-check-certificate https://paddle-github-action.cdn.bcebos.com/PR/paddlefleet/${PR_ID}/${COMMIT_ID}/paddldfleet.tar.gz
|
||||
tar -xf paddldfleet.tar.gz --strip-components=1
|
||||
git config --global --add safe.directory /paddle
|
||||
pip install dist/paddlefleet-*.whl --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/ --extra-index-url=https://www.paddlepaddle.org.cn/packages/stable/cu129/
|
||||
pip install dist/paddlefleet_ops-*.whl --extra-index-url=https://www.paddlepaddle.org.cn/packages/stable/cu129/ --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
|
||||
chmod +x /usr/local/bin/yq
|
||||
'
|
||||
|
||||
- name: Download paddle.tar.gz and install paddle whl
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
mkdir -p /PaddlePaddle
|
||||
cd /PaddlePaddle
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/h-coverage/${PR_ID}/${COMMIT_ID}/paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --no-check-certificate
|
||||
export UV_SKIP_WHEEL_FILENAME_CHECK=1 #This environment variable allows installing the latest commit-level whl package of Paddle.
|
||||
export UV_NO_SYNC=1 # This environment variable prevents uv sync from being executed when running un run.
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
pip uninstall paddlepaddle-gpu -y
|
||||
pip install paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl --force-reinstall --extra-index-url=https://www.paddlepaddle.org.cn/packages/nightly/cu129/
|
||||
echo "paddlefleet commit:"
|
||||
python -c "import paddlefleet; print(paddlefleet.version.commit)"
|
||||
'
|
||||
|
||||
- name: Multi-card test
|
||||
timeout-minutes: 60
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -ce '
|
||||
export PYTHONPATH=$(pwd)
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-12.9/targets/x86_64-linux/lib:/usr/local/cuda/lib64
|
||||
if [ "${BRANCH}" != "develop" ]; then
|
||||
git checkout $fleet_branch
|
||||
echo "Checked out fleet branch: $fleet_branch"
|
||||
else
|
||||
git checkout develop
|
||||
echo "Checked out fleet branch: develop"
|
||||
fi
|
||||
python -c "import paddle; print(paddle.version.commit)"
|
||||
export UV_SKIP_WHEEL_FILENAME_CHECK=1 #This environment variable allows installing the latest commit-level whl package of Paddle.
|
||||
export UV_NO_SYNC=1 # This environment variable prevents uv sync from being executed when running un run.
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
bash ci/multi-card_test.sh
|
||||
multi_card_exit_code=$?
|
||||
if [[ "$multi_card_exit_code" != "0" ]]; then
|
||||
echo -e "::error:: \033[31mMulti card test failed.\033[0m"
|
||||
exit 1
|
||||
else
|
||||
echo -e "\033[32mMulti card test succeeded.\033[0m"
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,393 @@
|
||||
name: Night-Coverage
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 18 * * *"
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-coverage
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
CI_name: coverage
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build-docker:
|
||||
name: Coverage build docker
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
outputs:
|
||||
docker_coverage_image: ${{ steps.build-docker-images.outputs.docker_coverage_image }}
|
||||
runs-on:
|
||||
group: HK-Clone
|
||||
steps:
|
||||
- name: build-docker-images
|
||||
id: build-docker-images
|
||||
run: |
|
||||
set -x
|
||||
cd ${{ github.workspace }}
|
||||
pwd
|
||||
git clone --depth=1000 https://github.com/PaddlePaddle/Paddle.git
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
|
||||
cd Paddle/tools/dockerfile
|
||||
bash ci_dockerfile.sh
|
||||
md5_value=`md5sum Dockerfile.cuda117_cudnn8_gcc82_ubuntu18_coverage |awk '{print $1}'`
|
||||
echo "docker_coverage_image=ccr-2vdh3abv-pub.cnc.bj.baidubce.com/ci/paddle:${md5_value}" >> $GITHUB_OUTPUT
|
||||
|
||||
# clean workspace
|
||||
cd ${{ github.workspace }}
|
||||
rm -rf * .[^.]*
|
||||
|
||||
build:
|
||||
name: Coverage build
|
||||
needs: [build-docker]
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
CCACHE_MAXSIZE: 50G
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Volta
|
||||
WITH_AVX: "ON"
|
||||
WITH_COVERAGE: "ON"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
CUDA_VISIBLE_DEVICES: 0,1
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_PIP_CUDA_LIBRARIES: "OFF"
|
||||
WITH_FLAGCX: "ON"
|
||||
LITE_GIT_TAG: develop
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
ON_INFER: "ON"
|
||||
PADDLE_CUDA_INSTALL_REQUIREMENTS: "ON"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
UT_RUN_TYPE_SETTING: WITHOUT_HYBRID
|
||||
run: |
|
||||
container_name=${TASK}-build-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ needs.build-docker.outputs.docker_coverage_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e WITH_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_PIP_CUDA_LIBRARIES \
|
||||
-e WITH_FLAGCX \
|
||||
-e LITE_GIT_TAG \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ON_INFER \
|
||||
-e PADDLE_CUDA_INSTALL_REQUIREMENTS \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e UT_RUN_TYPE_SETTING \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
echo "Clone Paddle"
|
||||
git clone --depth=1000 https://github.com/PaddlePaddle/Paddle.git .
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
echo "Extracting Paddle"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
git checkout test
|
||||
git submodule update --init --recursive
|
||||
echo "Pull upstream $BRANCH"
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir -p ${CFS_DIR}/.cache/coverage
|
||||
mkdir -p ${CFS_DIR}/.ccache/coverage
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash $ci_scripts/coverage_build.sh bdist_wheel
|
||||
'
|
||||
|
||||
- name: Clean up env
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
Build_Size=$(du -h --max-depth=0 ${work_dir}/build |awk '"'"'{print $1}'"'"')
|
||||
source ${ci_scripts}/utils.sh; clean_build_files
|
||||
echo "Build_Size=${Build_Size}" > ${work_dir}/dist/coverage_build_size
|
||||
find ./ -type f -size +200M | xargs du -lh
|
||||
rm -rf $(find . -name "*.a")
|
||||
rm -rf $(find . -name "*.o")
|
||||
rm -rf paddle_inference_install_dir
|
||||
rm -rf paddle_inference_c_install_dir
|
||||
rm -rf lib.linux-x86_64-${PY_VERSION}
|
||||
find ./ -name "eager_generator" -or -name "kernel_signature_generator" -or -name "eager_legacy_op_function_generator" | xargs rm -rf
|
||||
rm -rf ./python/build/lib.linux-x86_64-${PY_VERSION}/
|
||||
cd "${work_dir}/build/third_party" && find $(ls | grep -v "dlpack" | grep -v "install" | grep -v "eigen3" | grep -v "gflags") -type f ! -name "*.so" -a ! -name "libdnnl.so*" -delete
|
||||
cd /
|
||||
tar --use-compress-program="pzstd -1" -cf Paddle.tar.gz paddle
|
||||
'
|
||||
|
||||
- name: Upload coverage product
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
paddle_whl: paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd /paddle/dist
|
||||
coverage_tag=$(date +%Y-%m-%d)
|
||||
mkdir -p ${CFS_DIR}/coverage_night/${coverage_tag}
|
||||
echo "Uploading coverage build size"
|
||||
python ${{ env.bos_file }} coverage_build_size paddle-github-action/night/coverage/${coverage_tag}
|
||||
python ${{ env.bos_file }} coverage_build_size paddle-github-action/night/coverage
|
||||
echo "Uploading coverage wheel"
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/night/coverage/${coverage_tag}
|
||||
cd /
|
||||
echo "Uploading Paddle.tar.gz"
|
||||
cp Paddle.tar.gz ${CFS_DIR}/coverage_night/${coverage_tag}
|
||||
rm Paddle.tar.gz
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
|
||||
test:
|
||||
name: Coverage test
|
||||
needs: [build, build-docker]
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: "/root/.cache/coverage"
|
||||
CCACHE_DIR: "/root/.ccache/coverage"
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Auto
|
||||
WITH_AVX: "ON"
|
||||
WITH_COVERAGE: "ON"
|
||||
WITH_ALL_COVERAGE: "ON"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.12"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/coverage
|
||||
CCACHE_MAXSIZE: 200G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
FLAGS_PIR_OPTEST: "TRUE"
|
||||
ON_INFER: "ON"
|
||||
COVERAGE_FILE: ${{ github.workspace }}/build/python-coverage.data
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ needs.build-docker.outputs.docker_coverage_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e GIT_PR_ID \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e ci_scripts \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_AVX \
|
||||
-e WITH_COVERAGE \
|
||||
-e WITH_ALL_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e FLAGS_PIR_OPTEST \
|
||||
-e ON_INFER \
|
||||
-e COVERAGE_FILE \
|
||||
-e GITHUB_TOKEN \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz from cfs"
|
||||
coverage_tag=$(date +%Y-%m-%d)
|
||||
cp ${CFS_DIR}/coverage_night/${coverage_tag}/Paddle.tar.gz .
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program="pzstd -1" -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash $ci_scripts/coverage_test.sh
|
||||
TEST_EXIT_CODE=$?
|
||||
echo "TEST_EXIT_CODE=${TEST_EXIT_CODE}" >> ${{ github.env }}
|
||||
if [[ "$TEST_EXIT_CODE" -ne 0 && "$TEST_EXIT_CODE" -ne 9 ]]; then
|
||||
exit $TEST_EXIT_CODE
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Generate coverage information
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
commit_info=$(git log --format=fuller |head -1|awk "{print \$2}")
|
||||
touch ${PADDLE_ROOT}/night_coverage.txt
|
||||
echo "commit:${commit_info}" >>${PADDLE_ROOT}/night_coverage.txt
|
||||
unset GREP_OPTIONS
|
||||
export WITH_ALL_COVERAGE=ON
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ${ci_scripts}/utils.sh; check_coverage
|
||||
coverage_tag=$(date +"%m-%d")
|
||||
mkdir -p ${CFS_DIR}/coverage_night/${coverage_tag}
|
||||
cp build/coverage_files/* ${CFS_DIR}/coverage_night/${coverage_tag}
|
||||
'
|
||||
|
||||
- name: Upload coverage product
|
||||
if: always()
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
paddle_whl: paddlepaddle_gpu-0.0.0-cp312-cp312-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
echo "Uploading night_coverage.txt"
|
||||
coverage_time=$(date +%Y-%m-%d)
|
||||
python ${{ env.bos_file }} night_coverage.txt paddle-github-action/night/coverage/${coverage_time}
|
||||
echo "Uploaded night_coverage.txt"
|
||||
echo "Uploading coverage-full.info"
|
||||
python ${{ env.bos_file }} build/coverage-full.info paddle-github-action/night/coverage/${coverage_time}
|
||||
echo "Uploaded coverage-full.info"
|
||||
echo "Uploading python-coverage-full.info"
|
||||
python ${{ env.bos_file }} build/python-coverage-full.info paddle-github-action/night/coverage/${coverage_time}
|
||||
echo "Uploaded python-coverage-full.info"
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
rm Paddle.tar.gz
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Slice-baseline-paddle
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
PR_ID:
|
||||
required: false
|
||||
type: string
|
||||
COMMIT_ID:
|
||||
required: false
|
||||
type: string
|
||||
# schedule:
|
||||
# - cron: '0 20 * * 0'
|
||||
|
||||
permissions: read-all
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
clone:
|
||||
name: Slice-base clone
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
is_pr: 'false'
|
||||
|
||||
build-docker:
|
||||
name: Slice build docker
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
task: build
|
||||
|
||||
build:
|
||||
name: Slice build
|
||||
needs: [clone, build-docker]
|
||||
uses: ./.github/workflows/_Linux-build.yml
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
is_pr: 'false'
|
||||
|
||||
slice-test:
|
||||
name: Slice test
|
||||
uses: ./.github/workflows/_Slice.yml
|
||||
needs: [clone, build-docker, build]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
slice-check: 'true'
|
||||
SLICE_TEST_MODE: insert_baseline
|
||||
MANUALLY_PR_ID: ${{ inputs.PR_ID }}
|
||||
MANUALLY_COMMIT_ID: ${{ inputs.COMMIT_ID }}
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Slice-baseline-torch
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
permissions: read-all
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
clone:
|
||||
name: Slice-base clone
|
||||
uses: ./.github/workflows/_Clone-linux.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
is_pr: 'false'
|
||||
|
||||
build-docker:
|
||||
name: Slice build docker
|
||||
needs: clone
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
clone_dir: Paddle-build
|
||||
task: build
|
||||
|
||||
slice-test:
|
||||
name: Slice test
|
||||
uses: ./.github/workflows/_Slice.yml
|
||||
needs: [clone, build-docker]
|
||||
with:
|
||||
docker_build_image: ${{ needs.build-docker.outputs.docker_build_image }}
|
||||
slice-check: 'true'
|
||||
SLICE_TEST_MODE: insert_baseline
|
||||
SLICE_BENCHMARK_FRAMEWORKS: torch
|
||||
@@ -0,0 +1,165 @@
|
||||
name: Api-Benchmark
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
baseline:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
MANUALLY_PR_ID:
|
||||
type: string
|
||||
required: false
|
||||
MANUALLY_COMMIT_ID:
|
||||
type: string
|
||||
required: false
|
||||
run-labels:
|
||||
type: string
|
||||
required: false
|
||||
default: "api-bm"
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-api-benchmark
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref || github.ref_name }}
|
||||
CI_name: api-benchmark
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "api-benchmark"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
data-storage:
|
||||
name: Performance data storage
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true'}}
|
||||
runs-on:
|
||||
group: Api-bm
|
||||
labels: [self-hosted, "${{ inputs.run-labels }}"]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
echo "docker_image=${docker_image}" >> $GITHUB_ENV
|
||||
docker run -i --rm -v ${{ github.workspace }}:/paddle -w /paddle $docker_image /bin/bash -c 'rm -rf * .[^.]*'
|
||||
cp -r /home/PTSTools .
|
||||
runner_name=`(echo $PWD|awk -F '/' '{print $4}')`
|
||||
echo $runner_name
|
||||
core_index=-1
|
||||
if [ $runner_name == "paddle-1" ];then
|
||||
core_index=0
|
||||
elif [ $runner_name == "paddle-2" ];then
|
||||
core_index=8
|
||||
fi
|
||||
echo "core_index=${core_index}" >> $GITHUB_ENV
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
python: "python3.10"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
wheel_link: https://paddle-github-action.bj.bcebos.com/PR/build/${{ github.event.pull_request.number }}/${{ github.event.pull_request.head.sha }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker container ls -a --filter "name=paddle-CI-*-api-benchmark-${core_index}*" --format "{{.ID}}" | xargs -r docker rm -f
|
||||
docker container ls -a --filter "name=api_benchmark_ci_baseline_" --format "{{.ID}} {{.CreatedAt}}" | awk '$2 <= "'$(date -d '1 day ago' +'%Y-%m-%d')'" {print $1}' | xargs -r docker rm -f
|
||||
docker run -d -t --name ${container_name} --shm-size=128g \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e python \
|
||||
-e core_index \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e RUN_ID \
|
||||
-e wheel_link \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download PaddleTest.tar.gz
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
ldconfig
|
||||
set -e
|
||||
echo "Downloading PaddleTest.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleTest.tar.gz --no-check-certificate
|
||||
echo "Extracting PaddleTest.tar.gz"
|
||||
# git config --global --add safe.directory ${work_dir}
|
||||
tar -zvxf PaddleTest.tar.gz 1>/dev/null 2>&1
|
||||
# git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
mkdir -p ${{ github.workspace }}/../../../pip
|
||||
${python} -m pip config set global.cache-dir ${{ github.workspace }}/../../../pip
|
||||
${python} -m pip install -r ./PaddleTest/framework/e2e/api_benchmark_new/requirement.txt
|
||||
'
|
||||
|
||||
- name: Paddletest check
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-11.8/compat:/usr/local/cuda/compat:/usr/local/cuda/lib:/usr/local/cuda/lib64:/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}
|
||||
cd ./PaddleTest/framework/e2e/api_benchmark_new
|
||||
cp /paddle/PTSTools/Uploader/apibm_config.yml .
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
if [[ "${{ inputs.baseline }}" == "true" ]];then
|
||||
set -e
|
||||
if [[ "${{ inputs.MANUALLY_PR_ID }}" == "" ]]; then
|
||||
export pr_wheel_link=https://paddle-github-action.bj.bcebos.com/PR/build/$PR_ID/$COMMIT_ID/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
else
|
||||
export pr_wheel_link=https://paddle-github-action.bj.bcebos.com/PR/build/${{ inputs.MANUALLY_PR_ID }}/${{ inputs.MANUALLY_COMMIT_ID }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
fi
|
||||
${python} -m pip install $pr_wheel_link
|
||||
${python} runner_ci_multipro_action.py --yaml ../yaml/sort_api_benchmark_fp32.yml --core_index ${core_index} --baseline_whl_link $pr_wheel_link
|
||||
exit 0
|
||||
fi
|
||||
${python} -m pip install $wheel_link
|
||||
if [ ${core_index} -eq -1 ];then
|
||||
${python} runner_ci_action.py --yaml ../yaml/api_benchmark_fp32.yml --core_index 2
|
||||
else
|
||||
${python} runner_ci_multipro_action.py --yaml ../yaml/sort_api_benchmark_fp32.yml --core_index ${core_index}
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,152 @@
|
||||
name: Auto-Parallel
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /workspace/Paddle
|
||||
PADDLE_ROOT: /workspace/Paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-Auto-Parallel
|
||||
ci_scripts: /workspace/Paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: auto-parallel
|
||||
no_proxy: "localhost,bj.bcebos.com,su.bcebos.com,bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "auto-parallel"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
parallel-test:
|
||||
name: Parallel test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: Auto-Parallel
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_dynamic_static_unified_comm: "True"
|
||||
python_version: "3.10"
|
||||
paddle_whl: https://paddle-github-action.bj.bcebos.com/PR/build/${{ github.event.pull_request.number }}/${{ github.event.pull_request.head.sha }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
nvidia-docker run -d -t --name ${container_name} --net=host -v /dev/shm:/dev/shm --shm-size=32G \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/workspace \
|
||||
-v /home/FleetX_CI:/gpt_data \
|
||||
-v /home/Llm_gpt_CI:/llm_gpt_data \
|
||||
-v /home/Llama_CI:/llama_data \
|
||||
-v /home/.cache/pip:/home/.cache/pip \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e paddle_whl \
|
||||
-e FLAGS_dynamic_static_unified_comm \
|
||||
-e python_version \
|
||||
-w /workspace --runtime=nvidia ${docker_image}
|
||||
|
||||
- name: Download Paddle
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/build/${{ github.event.pull_request.number }}/${{ github.event.pull_request.head.sha }}/build.tar.gz --no-check-certificate
|
||||
echo "Extracting build.tar.gz"
|
||||
tar --use-compress-program="pzstd" -xpf build.tar.gz
|
||||
mv paddle Paddle
|
||||
rm -f build.tar.gz
|
||||
'
|
||||
|
||||
- name: Download PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "Download and extract PaddleNLP.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddleNLP.tar --no-check-certificate
|
||||
tar xf PaddleNLP.tar && rm -rf PaddleNLP.tar
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
cd PaddleNLP
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git pull
|
||||
git checkout 6ac04028757dfbcc089916997493611f62de81b2
|
||||
git switch -c 6ac04028757dfbcc089916997493611f62de81b2
|
||||
git cherry-pick bc08aeec91d2c992c3d8d39755bea7c6213b0e82
|
||||
git cherry-pick 7ab35ce94eca977bcf3b44bfb42deb0e0b5ef158
|
||||
git cherry-pick 2ac85997c2dafe3d67a4aac01d553ad76d6024bf
|
||||
git submodule update --init --recursive --force
|
||||
'
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
ldconfig
|
||||
set -e
|
||||
pip config set global.cache-dir "/home/.cache/pip"
|
||||
ln -sf $(which python${python_version}) /usr/bin/python
|
||||
python -c "import sys; print(sys.version_info[:])"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
timeout 80m bash Paddle/ci/auto_parallel/ci_auto_parallel.sh ${paddle_whl}
|
||||
'
|
||||
|
||||
- name: Upload and display logs
|
||||
if: always()
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd /workspace/case_logs
|
||||
for FILE in /workspace/case_logs/*; do
|
||||
file=$(basename "$FILE")
|
||||
python ${{ env.bos_file }} $file paddle-github-action/PR/Auto-Parallel/${PR_ID}/${COMMIT_ID}/logs
|
||||
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/Auto-Parallel/${PR_ID}/${COMMIT_ID}/logs/$file"
|
||||
done
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,141 @@
|
||||
name: CE-CINN-Framework
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-CE-CINN-Framework
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: ce-cinn-framework
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: ce-cinn-framework
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
cinn:
|
||||
name: CINN
|
||||
if: ${{ inputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass]
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: /home/data/cfs/.cache
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker container ls -a --filter "name=paddle-CI-*-api-benchmark-${core_index}*" --format "{{.ID}}" | xargs -r docker rm -f
|
||||
docker container ls -a --filter "name=api_benchmark_ci_baseline_" --format "{{.ID}} {{.CreatedAt}}" | awk '$2 <= "'$(date -d '1 day ago' +'%Y-%m-%d')'" {print $1}' | xargs -r docker rm -f
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e python \
|
||||
-e core_index \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e CACHE_DIR \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download Paddle and PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
git checkout test
|
||||
rm build.tar.gz
|
||||
cd /
|
||||
echo "Downloading PaddleTest.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleTest.tar.gz --no-check-certificate
|
||||
echo "Extracting PaddleTest.tar.gz"
|
||||
tar -zvxf PaddleTest.tar.gz 1>/dev/null 2>&1
|
||||
'
|
||||
|
||||
- name: Determine ci trigger
|
||||
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ${ci_scripts}/ce_cinn_diff.sh
|
||||
if [ ${sum_num} -eq 0 ];then
|
||||
echo "The modified files does not affect LayerCase in CE-CINN-Framework, so skip this ci."
|
||||
echo "skip_ci=true" >> ${{ github.env }}
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Run check
|
||||
if: ${{ env.skip_ci != 'true' }}
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
pip config set global.cache-dir "$CACHE_DIR/pip"
|
||||
pip install /paddle/build/pr_whl/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
cd /PaddleTest/framework/e2e/PaddleLT_new
|
||||
pip install -r requirement.txt
|
||||
source ./scene/set_ci_dy^dy2stcinn_train^dy2stcinn_eval_inputspec_env.sh
|
||||
python support/dict_to_yml.py --filename apibm_config.yml --data_str "$(cat $CACHE_DIR/cinn_config)"
|
||||
set -e
|
||||
python run.py
|
||||
exit $(head -n 1 "exit_code.txt")
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,312 @@
|
||||
name: CE-Framework
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-CE-Framework
|
||||
CI_name: ce-framework
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass-whl:
|
||||
name: Check bypass (ce-whl)
|
||||
if: ${{ inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: ce-whl
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
check-bypass-infer:
|
||||
name: Check bypass (ce-infer)
|
||||
if: ${{ inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: ce-infer
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
check-bypass-test:
|
||||
name: Check bypass (ce-test)
|
||||
if: ${{ inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: ce-test
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
whl:
|
||||
name: Whl
|
||||
if: ${{ inputs.can-skip != 'true' && needs.check-bypass-whl.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass-whl]
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-CE-Framework-whl
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: /home/data/cfs/.cache
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e CACHE_DIR \
|
||||
-e CFS_DIR \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download Paddle and PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm build.tar.gz
|
||||
'
|
||||
|
||||
- name: Check whl size
|
||||
env:
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
bash ci/check_whl_size.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
|
||||
infer:
|
||||
name: Infer
|
||||
if: ${{ inputs.can-skip != 'true' && needs.check-bypass-infer.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass-infer]
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-CE-Framework-infer
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: /home/data/cfs/.cache
|
||||
FLAGS_enable_eager_mode: 1
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e CACHE_DIR \
|
||||
-e FLAGS_enable_eager_mode \
|
||||
-e CFS_DIR \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download Paddle and PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm build.tar.gz
|
||||
cd /
|
||||
cp /paddle/build/pr_whl/*.whl .
|
||||
echo "Downloading PaddleTest.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleTest.tar.gz --no-check-certificate
|
||||
echo "Extracting PaddleTest.tar.gz"
|
||||
tar -zvxf PaddleTest.tar.gz 1>/dev/null 2>&1
|
||||
'
|
||||
|
||||
- name: Install paddle and dependencies
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir run_env
|
||||
ln -s $(which python3.10) run_env/python
|
||||
ln -s $(which pip3.10) run_env/pip
|
||||
export PATH=$(pwd)/run_env:${PATH}
|
||||
pip config set global.cache-dir "$CACHE_DIR/pip"
|
||||
pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
|
||||
python -m pip install pip --upgrade
|
||||
pip install /paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl --no-index --no-deps
|
||||
pip install -r /PaddleTest/inference/python_api_test/requirements.txt
|
||||
'
|
||||
|
||||
- name: Check
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PATH=$(pwd)/run_env:${PATH}
|
||||
cd /PaddleTest/inference/python_api_test
|
||||
bash parallel_run.sh 2
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
if: ${{ inputs.can-skip != 'true' && needs.check-bypass-test.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass-test]
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-CE-Framework-test
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: /home/data/cfs/.cache
|
||||
FLAGS_enable_eager_mode: 1
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e CACHE_DIR \
|
||||
-e FLAGS_enable_eager_mode \
|
||||
-e CFS_DIR \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download Paddle and PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm build.tar.gz
|
||||
cd /
|
||||
cp /paddle/build/pr_whl/*.whl .
|
||||
echo "Downloading PaddleTest.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://xly-devops.bj.bcebos.com/PaddleTest/PaddleTest.tar.gz --no-check-certificate
|
||||
echo "Extracting PaddleTest.tar.gz"
|
||||
tar -zvxf PaddleTest.tar.gz 1>/dev/null 2>&1
|
||||
'
|
||||
|
||||
- name: Install paddle and dependencies
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir run_env
|
||||
ln -s $(which python3.10) run_env/python
|
||||
ln -s $(which pip3.10) run_env/pip
|
||||
export PATH=$(pwd)/run_env:${PATH}
|
||||
pip config set global.cache-dir "${CFS_DIR}/.cache/pip"
|
||||
pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
|
||||
pip install sympy
|
||||
pip install /paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl --no-index --no-deps
|
||||
'
|
||||
|
||||
- name: Check
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PATH=$(pwd)/run_env:${PATH}
|
||||
cd /PaddleTest/framework/api
|
||||
rm ./device/test_cuda_get_device_capability.py
|
||||
bash run_paddle_ci.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,161 @@
|
||||
name: Clone-linux
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
workflow-name:
|
||||
type: string
|
||||
required: false
|
||||
clone_dir:
|
||||
type: string
|
||||
required: false
|
||||
default: "Paddle"
|
||||
is_pr:
|
||||
type: string
|
||||
required: false
|
||||
default: "true"
|
||||
skill-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
outputs:
|
||||
can-skip:
|
||||
value: ${{ jobs.clone.outputs.can-skip }}
|
||||
slice-check:
|
||||
value: ${{ jobs.clone.outputs.slice-check }}
|
||||
xpu-only:
|
||||
value: ${{ jobs.clone.outputs.xpu-only }}
|
||||
|
||||
permissions: read-all
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
ci_scripts: ${{ github.workspace }}/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref || github.ref_name }}
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: ${{ inputs.workflow-name }}
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
clone:
|
||||
name: Clone Paddle
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
needs: [check-bypass]
|
||||
outputs:
|
||||
can-skip: ${{ needs.check-bypass.outputs.can-skip == 'true' || inputs.skill-can-skip == 'true' }}
|
||||
slice-check: ${{ steps.check-execution.outputs.slice-check }}
|
||||
xpu-only: ${{ steps.xpu-only-check.outputs.xpu-only }}
|
||||
runs-on:
|
||||
group: HK-Clone
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Debug - Print inputs values
|
||||
run: |
|
||||
echo "=== Debug Info ==="
|
||||
echo "inputs.skill-can-skip: '${{ inputs.skill-can-skip }}'"
|
||||
echo "inputs.skill-can-skip length: $(echo '${{ inputs.skill-can-skip }}' | wc -c)"
|
||||
echo "==="
|
||||
|
||||
- name: Set environment variables and print
|
||||
id: set-vars
|
||||
run: |
|
||||
# Determine if can skip based on check-bypass and skill-can-skip
|
||||
if [[ "${{ needs.check-bypass.outputs.can-skip }}" == "true" ]] || [[ "${{ inputs.skill-can-skip }}" == "true" ]]; then
|
||||
echo "CAN_SKIP=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "CAN_SKIP=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Print can-skip value
|
||||
run: |
|
||||
echo "can-skip output: ${{ env.CAN_SKIP }}"
|
||||
|
||||
- name: Check submodules status
|
||||
run: git submodule foreach --recursive 'git rev-parse HEAD || rm -rf $PWD' || true
|
||||
|
||||
- name: Clone paddle
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
fetch-depth: 1000
|
||||
|
||||
- name: Merge PR to test branch
|
||||
id: check-execution
|
||||
if: ${{ inputs.is_pr == 'true' }}
|
||||
run: |
|
||||
git submodule foreach --recursive sh -c "git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'"
|
||||
git switch ${{ github.event.pull_request.base.ref }}
|
||||
set +e
|
||||
git branch -D test
|
||||
set -e
|
||||
git gc
|
||||
git switch -c test
|
||||
git config user.name "PaddleCI"
|
||||
git config user.email "paddle_ci@example.com"
|
||||
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr
|
||||
git merge --no-ff pr
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --recursive
|
||||
git branch -d pr
|
||||
source ${ci_scripts}/check_execution.sh
|
||||
bash ${ci_scripts}/third_party_tag.sh
|
||||
|
||||
- name: Check if XPU-only PR
|
||||
id: xpu-only-check
|
||||
if: ${{ inputs.is_pr == 'true' }}
|
||||
env:
|
||||
DISABLE_HW_CI_SKIP: ${{ vars.DISABLE_HW_CI_SKIP || 'false' }}
|
||||
run: |
|
||||
if bash ci/check_xpu_only.sh; then
|
||||
echo "xpu-only=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "xpu-only=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Download bos client
|
||||
env:
|
||||
home_path: "/home/paddle/actions-runner/"
|
||||
bos_file: "/home/paddle/actions-runner/bos/BosClient.py"
|
||||
run: |
|
||||
if [ ! -f "${bos_file}" ]; then
|
||||
wget -q --no-proxy -O ${home_path}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir ${home_path}/bos
|
||||
tar xf ${home_path}/bos_new.tar.gz -C ${home_path}/bos
|
||||
fi
|
||||
|
||||
- name: Push paddle-action.tar.gz to bos
|
||||
env:
|
||||
AK: paddle
|
||||
SK: paddle
|
||||
bos_file: "/home/paddle/actions-runner/bos/BosClient.py"
|
||||
run: |
|
||||
cd ..
|
||||
tar -I 'zstd -T0' -cf Paddle.tar.gz Paddle
|
||||
echo "::group::Install bce-python-sdk"
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
python ${bos_file} Paddle.tar.gz paddle-github-action/PR/${{ inputs.clone_dir }}/${PR_ID}/${COMMIT_ID}
|
||||
rm Paddle.tar.gz
|
||||
cd -
|
||||
git switch ${BRANCH}
|
||||
set +e
|
||||
git branch -D test
|
||||
git gc
|
||||
|
||||
# - name: Clean environment
|
||||
# if: always()
|
||||
# run: |
|
||||
# cd ${{ github.workspace }}
|
||||
# rm -rf * .[^.]*
|
||||
@@ -0,0 +1,90 @@
|
||||
name: Clone-windows
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
skill-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
outputs:
|
||||
can-skip:
|
||||
value: ${{ jobs.clone.outputs.can-skip }}
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
ci_scripts: ${{ github.workspace }}\ci\windows
|
||||
WORK_DIR: ${{ github.workspace }}\..
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
|
||||
jobs:
|
||||
clone:
|
||||
name: Clone Paddle
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
outputs:
|
||||
can-skip: ${{ inputs.skill-can-skip == 'true' }}
|
||||
runs-on:
|
||||
group: win-clone
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Git config
|
||||
run: |
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git config --global http.postBuffer 524288000
|
||||
git config --global core.longpaths true
|
||||
|
||||
- name: Clone paddle
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
fetch-depth: 1000
|
||||
|
||||
- name: Merge pr
|
||||
run: |
|
||||
REM git submodule foreach --recursive sh -c "git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'"
|
||||
git switch %BRANCH%
|
||||
git branch -D test
|
||||
git gc
|
||||
git switch -c test
|
||||
git fetch origin pull/%PR_ID%/head:pr
|
||||
git merge --no-ff pr
|
||||
git branch -d pr
|
||||
REM call %ci_scripts%\third_party_tag.bat
|
||||
git config -f .gitmodules submodule.third_party/openvino.update none && git submodule sync third_party/openvino
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Upload paddle to bos
|
||||
working-directory: ..
|
||||
env:
|
||||
BCE_FILE: ${{ github.workspace }}\..\bce-python-sdk-new\BosClient.py
|
||||
run: |
|
||||
if not exist %WORK_DIR%\bce-python-sdk-new (
|
||||
echo There is no bce in this PC, will install bce.
|
||||
pip install wget
|
||||
pip install shutil
|
||||
echo Download package from https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz
|
||||
python -c "import wget;wget.download('https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz')"
|
||||
python -c "import shutil;shutil.unpack_archive('bos_new.tar.gz', extract_dir='./bce-python-sdk-new',format='gztar')"
|
||||
)
|
||||
python -m pip install pycryptodome
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
tar -cf Paddle.tar Paddle && zstd Paddle.tar
|
||||
python %BCE_FILE% Paddle.tar.zst paddle-github-action/windows/PR/%PR_ID%/%COMMIT_ID%
|
||||
del Paddle.tar Paddle.tar.zst
|
||||
|
||||
- name: Clean env
|
||||
run: |
|
||||
cd ${{ github.workspace }}
|
||||
git switch %BRANCH%
|
||||
git branch -D test
|
||||
git config -f .gitmodules submodule.third_party/openvino.update none && git submodule sync third_party/openvino
|
||||
git submodule update --init --recursive
|
||||
git gc
|
||||
@@ -0,0 +1,206 @@
|
||||
name: DeepMD-Kit Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
MANUALLY_PR_ID:
|
||||
type: string
|
||||
required: false
|
||||
MANUALLY_COMMIT_ID:
|
||||
type: string
|
||||
required: false
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-deepmd
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref || github.ref_name }}
|
||||
CI_name: deepmd
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "deepmd"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
deepmd-test:
|
||||
name: DeepMD-Kit Integration Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
wheel_link: https://paddle-github-action.bj.bcebos.com/PR/build/${{ env.PR_ID }}/${{ env.COMMIT_ID }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
run: |
|
||||
container_name="deepmd_test_ci_${RUN_ID}"
|
||||
echo "container_name=${container_name}" >> $GITHUB_ENV
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e RUN_ID \
|
||||
-e wheel_link \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Print PR information
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
echo "Testing PR #${{ env.PR_ID }}"
|
||||
echo "Commit: ${{ env.COMMIT_ID }}"
|
||||
echo "Branch: ${{ env.BRANCH }}"
|
||||
'
|
||||
|
||||
- name: Install PaddlePaddle
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
mkdir -p ${{ github.workspace }}/../../../.cache/pip
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python3.10 -m pip config set global.cache-dir ${{ github.workspace }}/../../../.cache/pip
|
||||
|
||||
if [[ "${{ inputs.MANUALLY_PR_ID }}" == "" ]]; then
|
||||
echo "Installing PaddlePaddle from: $wheel_link"
|
||||
python3.10 -m pip install $wheel_link
|
||||
else
|
||||
echo "Installing PaddlePaddle from manual PR: ${{ inputs.MANUALLY_PR_ID }}"
|
||||
python3.10 -m pip install https://paddle-github-action.bj.bcebos.com/PR/build/${{ inputs.MANUALLY_PR_ID }}/${{ inputs.MANUALLY_COMMIT_ID }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
fi
|
||||
|
||||
python3.10 -c "import paddle; print(f\"PaddlePaddle version: {paddle.__version__}\")"
|
||||
'
|
||||
|
||||
- name: Clone and setup deepmd-kit
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
cd /paddle
|
||||
rm -rf deepmd-kit
|
||||
echo "Cloning deepmd-kit repository..."
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
git clone https://github.com/deepmodeling/deepmd-kit.git -b v3.1.2
|
||||
ls -lah /paddle/deepmd-kit
|
||||
cd deepmd-kit
|
||||
'
|
||||
|
||||
- name: Install deepmd-kit dependencies
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
cd /paddle/deepmd-kit
|
||||
echo "Installing deepmd-kit..."
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
DP_ENABLE_TENSORFLOW=0 DP_ENABLE_PYTORCH=0 python3.10 -m pip install -v -e . -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
'
|
||||
|
||||
- name: Install test dependencies
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
echo "Installing pytest..."
|
||||
python3.10 -m pip install \
|
||||
pytest pytest-xdist pytest-json-report pytest-metadata pytest-mock pytest-rich pytest-sugar pytest-timeout \
|
||||
-i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
'
|
||||
|
||||
- name: Run deepmd-kit pytest
|
||||
id: pytest_run
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
cd /paddle/deepmd-kit
|
||||
echo "=========================================="
|
||||
echo "Running DeepMD-Kit Integration Tests"
|
||||
echo "=========================================="
|
||||
|
||||
python3.10 -m pytest -vvv --tb=long --color=yes \
|
||||
source/tests/pd/test_auto_batch_size.py \
|
||||
source/tests/pd/test_change_bias.py \
|
||||
source/tests/pd/test_decomp.py \
|
||||
source/tests/pd/test_dp_show.py \
|
||||
source/tests/pd/test_finetune.py \
|
||||
source/tests/pd/test_multitask.py \
|
||||
source/tests/pd/test_training.py \
|
||||
source/tests/pd/test_update_sel.py \
|
||||
source/tests/pd/test_utils.py \
|
||||
source/tests/pd/model/test_atomic_model_atomic_stat.py \
|
||||
source/tests/pd/model/test_atomic_model_global_stat.py \
|
||||
source/tests/pd/model/test_autodiff.py \
|
||||
source/tests/pd/model/test_deeppot.py \
|
||||
source/tests/pd/model/test_descriptor_dpa1.py \
|
||||
source/tests/pd/model/test_descriptor_dpa2.py \
|
||||
source/tests/pd/model/test_dp_atomic_model.py \
|
||||
source/tests/pd/model/test_dp_model.py \
|
||||
source/tests/pd/model/test_dpa1.py \
|
||||
source/tests/pd/model/test_dpa2.py \
|
||||
source/tests/pd/model/test_dpa3.py \
|
||||
source/tests/pd/model/test_dynamic_sel.py \
|
||||
source/tests/pd/model/test_ener_fitting.py \
|
||||
source/tests/pd/model/test_env_mat.py \
|
||||
source/tests/pd/model/test_exclusion_mask.py \
|
||||
source/tests/pd/model/test_force_grad.py \
|
||||
source/tests/pd/model/test_forward_lower.py \
|
||||
source/tests/pd/model/test_get_model.py \
|
||||
source/tests/pd/model/test_jit.py \
|
||||
source/tests/pd/model/test_mlp.py \
|
||||
source/tests/pd/model/test_nlist.py \
|
||||
source/tests/pd/model/test_null_input.py \
|
||||
source/tests/pd/model/test_permutation_denoise.py \
|
||||
source/tests/pd/model/test_permutation.py \
|
||||
source/tests/pd/model/test_region.py \
|
||||
source/tests/pd/model/test_rot_denoise.py \
|
||||
source/tests/pd/model/test_rot.py \
|
||||
source/tests/pd/model/test_rotation.py \
|
||||
source/tests/pd/model/test_se_e2_a.py \
|
||||
source/tests/pd/model/test_smooth.py \
|
||||
source/tests/pd/model/test_trans_denoise.py \
|
||||
source/tests/pd/model/test_trans.py \
|
||||
source/tests/pd/model/test_unused_params.py 2>&1 | tee /paddle/pytest_output.log
|
||||
TEST_RESULT=${PIPESTATUS[0]}
|
||||
|
||||
echo "DeepMD-Kit Test Finished with status: $TEST_RESULT"
|
||||
exit $TEST_RESULT
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'cd /paddle && rm -rf deepmd-kit'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,189 @@
|
||||
name: Distribute-stable-Formers
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_distribute_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-distribute-formers
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: distribute
|
||||
no_proxy: bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn,paddlepaddle.org.cn
|
||||
docker_image: ${{ inputs.docker_distribute_image }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "formers"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
formers-test:
|
||||
name: formers-Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: Distribute
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 4
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_TESTING: "ON"
|
||||
WITH_COVERAGE: "OFF"
|
||||
CMAKE_BUILD_TYPE: Release
|
||||
PADDLE_FRACTION_GPU_MEMORY_TO_USE: 0.15
|
||||
PRECISION_TEST: "OFF"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
AGILE_COMPILE_BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
AGILE_REVISION: ${{ github.event.pull_request.head.sha }}
|
||||
WITH_INCREMENTAL_COVERAGE: "OFF"
|
||||
WITH_ONNXRUNTIME: "OFF"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PY_VERSION: "3.10"
|
||||
CUDA_ARCH_NAME: Auto
|
||||
WITH_CUDNN_FRONTEND: "ON"
|
||||
FLAGS_enable_cudnn_frontend: 1
|
||||
CACHE_DIR: /root/.cache/build
|
||||
CCACHE_DIR: /root/.ccache/formers
|
||||
CFS_DIR: /home/data/cfs
|
||||
paddle_whl: /workspace/dist/*.whl
|
||||
formers_docker: ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddle:cuda126-dev-latest
|
||||
run: |
|
||||
export CUDA_SO="$(\ls -d /usr/lib64/libcuda* | xargs -I{} echo '-v {}:{}') $(\ls -d /usr/lib64/libnvidia* | xargs -I{} echo '-v {}:{}')"
|
||||
export DEVICES="$(\ls -d /dev/nvidia* | xargs -I{} echo "-v {}:{}") $(\ls /dev/nvidia-caps/* | xargs -I{} echo "-v {}:{}")"
|
||||
export SMI="-v /usr/bin/nvidia-smi:/usr/bin/nvidia-smi"
|
||||
container_name=${TASK}-test-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run -d -t --name ${container_name} ${CUDA_SO} ${DEVICES} ${SMI} --runtime=nvidia --shm-size=32G --privileged \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache/:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/ssd1/models:/home/models" \
|
||||
-v "/ssd1/root:/root" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/workspace \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e CI_name \
|
||||
-e PF_HOME=/home/models \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e WITH_AVX \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_TESTING \
|
||||
-e WITH_COVERAGE \
|
||||
-e CMAKE_BUILD_TYPE \
|
||||
-e PADDLE_FRACTION_GPU_MEMORY_TO_USE \
|
||||
-e PRECISION_TEST \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e AGILE_COMPILE_BRANCH \
|
||||
-e AGILE_REVISION \
|
||||
-e WITH_INCREMENTAL_COVERAGE \
|
||||
-e WITH_ONNXRUNTIME \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e GIT_PR_ID \
|
||||
-e PY_VERSION \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_CUDNN_FRONTEND \
|
||||
-e FLAGS_enable_cudnn_frontend \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CFS_DIR \
|
||||
-e paddle_whl \
|
||||
-e no_proxy \
|
||||
-w /workspace --network host ${formers_docker}
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/gpups/${{ env.PR_ID }}/${{ env.COMMIT_ID }}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program="pzstd" -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git config --global --add safe.directory /workspace
|
||||
git checkout test
|
||||
'
|
||||
- name: Test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ${{ github.workspace }}/../../../AISTUDIO_ACCESS_TOKEN
|
||||
set -ex
|
||||
bash /workspace/ci/formers_test.sh
|
||||
'
|
||||
- name: Upload and display logs
|
||||
if: always()
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
if [ -n "$PR_ID" ] && [ "$PR_ID" != "0" ]; then
|
||||
bos_prefix="${PR_ID}/${COMMIT_ID}"
|
||||
else
|
||||
bos_prefix="schedule/$(date +%Y%m%d)"
|
||||
fi
|
||||
# api test logs
|
||||
cd /workspace/PaddleFormers/unittest_logs
|
||||
for FILE in /workspace/PaddleFormers/unittest_logs/*; do
|
||||
file=$(basename "$FILE")
|
||||
python ${{ env.bos_file }} $file paddle-github-action/PR/PaddleFormers/unittest-gpu/${bos_prefix}/logs
|
||||
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/PaddleFormers/unittest-gpu/${bos_prefix}/logs/$file"
|
||||
done
|
||||
# models test logs
|
||||
cd /workspace/PaddleFormers/model_unittest_logs
|
||||
for FILE in /workspace/PaddleFormers/model_unittest_logs/*; do
|
||||
file=$(basename "$FILE")
|
||||
python ${{ env.bos_file }} $file paddle-github-action/PR/PaddleFormers/model-unittest-gpu/${bos_prefix}/logs
|
||||
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/PaddleFormers/model-unittest-gpu/${bos_prefix}/logs/$file"
|
||||
done
|
||||
'
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,170 @@
|
||||
name: Distribute-stable-Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_distribute_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-distribute-test
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: distribute
|
||||
no_proxy: bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn,paddlepaddle.org.cn
|
||||
docker_image: ${{ inputs.docker_distribute_image }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: distribute-test
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: Distribute
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 4
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_TESTING: "ON"
|
||||
WITH_COVERAGE: "OFF"
|
||||
CMAKE_BUILD_TYPE: Release
|
||||
PADDLE_FRACTION_GPU_MEMORY_TO_USE: 0.15
|
||||
PRECISION_TEST: "OFF"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
AGILE_COMPILE_BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
AGILE_REVISION: ${{ github.event.pull_request.head.sha }}
|
||||
WITH_INCREMENTAL_COVERAGE: "OFF"
|
||||
WITH_ONNXRUNTIME: "OFF"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PY_VERSION: "3.10"
|
||||
CUDA_ARCH_NAME: Auto
|
||||
WITH_CUDNN_FRONTEND: "ON"
|
||||
FLAGS_enable_cudnn_frontend: 1
|
||||
CACHE_DIR: /root/.cache/build
|
||||
CCACHE_DIR: /root/.ccache/gpubox
|
||||
run: |
|
||||
export CUDA_SO="$(\ls -d /usr/lib64/libcuda* | xargs -I{} echo '-v {}:{}') $(\ls -d /usr/lib64/libnvidia* | xargs -I{} echo '-v {}:{}')"
|
||||
export DEVICES="$(\ls -d /dev/nvidia* | xargs -I{} echo "-v {}:{}") $(\ls /dev/nvidia-caps/* | xargs -I{} echo "-v {}:{}")"
|
||||
export SMI="-v /usr/bin/nvidia-smi:/usr/bin/nvidia-smi"
|
||||
container_name=${TASK}-test-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run -d -t --name ${container_name} ${CUDA_SO} ${DEVICES} ${SMI} --runtime=nvidia --shm-size=32G \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache/:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/ssd1/root:/root" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e CI_name \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e WITH_AVX \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_TESTING \
|
||||
-e WITH_COVERAGE \
|
||||
-e CMAKE_BUILD_TYPE \
|
||||
-e PADDLE_FRACTION_GPU_MEMORY_TO_USE \
|
||||
-e PRECISION_TEST \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e AGILE_COMPILE_BRANCH \
|
||||
-e AGILE_REVISION \
|
||||
-e WITH_INCREMENTAL_COVERAGE \
|
||||
-e WITH_ONNXRUNTIME \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e PADDLE_VERSION \
|
||||
-e GIT_PR_ID \
|
||||
-e PY_VERSION \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_CUDNN_FRONTEND \
|
||||
-e FLAGS_enable_cudnn_frontend \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/gpups/${{ env.PR_ID }}/${{ env.COMMIT_ID }}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program="pzstd" -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git checkout test
|
||||
'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/distribute_test.sh
|
||||
'
|
||||
|
||||
- name: Upload and display logs
|
||||
if: always()
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd /case_logs
|
||||
for FILE in /case_logs/*; do
|
||||
file=$(basename "$FILE")
|
||||
python ${{ env.bos_file }} $file paddle-github-action/PR/Distribute-Stable/${PR_ID}/${COMMIT_ID}/logs
|
||||
echo "$file: https://paddle-github-action.bj.bcebos.com/PR/Distribute-Stable/${PR_ID}/${COMMIT_ID}/logs/$file"
|
||||
done
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,234 @@
|
||||
name: Distribute-stable-Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_distribute_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-distribute
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: distribute
|
||||
no_proxy: bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn,paddlepaddle.org.cn
|
||||
docker_image: ${{ inputs.docker_distribute_image }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: distribute
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
outputs:
|
||||
can-skip: ${{ needs.check-bypass.outputs.can-skip }}
|
||||
needs: [check-bypass]
|
||||
if: ${{ inputs.clone-can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 4
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_MKL: "OFF"
|
||||
WITH_PYTHON: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_TESTING: "ON"
|
||||
WITH_INFERENCE_API_TEST: "OFF"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
CUDA_VISIBLE_DEVICES: 0,1
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
GPUBOX_DEMO_INSTALL_DIR: /root/.cache/build
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/python35
|
||||
PY_VERSION: "3.10"
|
||||
WITH_TENSORRT: "OFF"
|
||||
GENERATOR: "Ninja"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
CUDA_ARCH_NAME: Ampere
|
||||
WITH_CUDNN_FRONTEND: "ON"
|
||||
FLAGS_enable_cudnn_frontend: 1
|
||||
CACHE_DIR: /root/.cache/build
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
CCACHE_STATSLOG: /paddle/build/.stats.log
|
||||
CCACHE_SLOPPINESS: clang_index_store,time_macros,include_file_mtime
|
||||
run: |
|
||||
container_name=${TASK}-build-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache/:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e CI_name \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_MKL \
|
||||
-e WITH_TESTING \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PY_VERSION \
|
||||
-e WITH_TENSORRT \
|
||||
-e GENERATOR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e WITH_AVX \
|
||||
-e WITH_PYTHON \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e CCACHE_STATSLOG \
|
||||
-e CCACHE_SLOPPINESS \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e WITH_INFERENCE_API_TEST \
|
||||
-e CUDA_VISIBLE_DEVICES \
|
||||
-e GPUBOX_DEMO_INSTALL_DIR \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_CUDNN_FRONTEND \
|
||||
-e FLAGS_enable_cudnn_frontend \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir -p /root/.cache/build
|
||||
mkdir -p /root/.ccache/gpubox
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
git checkout test
|
||||
echo "Pull upstream develop"
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Download flashattn cache
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set +e
|
||||
flashattn_version=$(git submodule status | grep flashattn | awk "{print \$1}" | sed "s#-##g")
|
||||
echo "flashattn_version=${flashattn_version}" >> ${{ github.env }}
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/gpups/flashattn_cache/flashattn_libs_${flashattn_version}.tar.gz --no-check-certificate; FACODE=$?
|
||||
if [ $FACODE -ne 0 ]; then
|
||||
echo "flashattn_cached_package=true" >> ${{ github.env }}
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Build
|
||||
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
'
|
||||
|
||||
- name: Packaging of products
|
||||
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
if [ "${{ env.flashattn_cached_package }}" == "true" ]; then
|
||||
cd ${work_dir}/build/third_party/install/flashattn/lib
|
||||
mkdir flashattn_libs_${{ env.flashattn_version }} && cd flashattn_libs_${{ env.flashattn_version }}
|
||||
mkdir fa_libs && cp ../lib*.so fa_libs && tar -zcf fa_libs.tar ./fa_libs && rm -rf ./fa_libs
|
||||
md5sum fa_libs.tar |awk "{print \$1}" >MD5.txt
|
||||
cd .. && tar -zcf flashattn_libs_${{ env.flashattn_version }}.tar ./flashattn_libs_${{ env.flashattn_version }}
|
||||
fi
|
||||
bash ${ci_scripts}/compress_build.sh
|
||||
cd ${work_dir}/..
|
||||
tar --use-compress-program="pzstd -1" --warning=no-file-changed -cf Paddle.tar.gz paddle
|
||||
'
|
||||
|
||||
- name: Upload product to bos
|
||||
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos_retry/BosClient.py
|
||||
paddle_whl: "*.whl"
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -x
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
echo "::group::Install bce-python-sdk"
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
cd ..
|
||||
source ${{ github.workspace }}/../../../unproxy
|
||||
echo "Uploading Paddle.tar.gz to bos"
|
||||
python ${{ env.bos_file }} Paddle.tar.gz paddle-github-action/PR/gpups/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading whl to bos"
|
||||
mv ${work_dir}/dist/${{ env.paddle_whl }} .
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/gpups/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
if [ "${{ env.flashattn_cached_package }}" == "true" ]; then
|
||||
echo "Uploading flashattn_libs_${flashattn_version}.tar.gz to bos"
|
||||
mv ${work_dir}/build/third_party/install/flashattn/lib/flashattn_libs_${{ env.flashattn_version }}.tar .
|
||||
python ${{ env.bos_file }} flashattn_libs_${{ env.flashattn_version }}.tar paddle-github-action/PR/gpups/flashattn_cache
|
||||
fi
|
||||
rm -rf Paddle.tar.gz ${{ env.paddle_whl }} flashattn_libs_${flashattn_version}.tar
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,123 @@
|
||||
name: Doc-Preview
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_doc_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /workspace/paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-Doc-Preview
|
||||
CI_name: Doc-Preview
|
||||
CFS_DIR: /home/data/cfs
|
||||
work_dir: /paddle
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "Doc-Preview"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-doc:
|
||||
name: Build doc
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CACHE_DIR: /home/data/cfs/.cache
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AGILE_PULL_ID: ${{ github.event.pull_request.number }}
|
||||
AGILE_REVISION: ${{ github.event.pull_request.head.sha }}
|
||||
BUILD_DOC: "true"
|
||||
UPLOAD_DOC: "true"
|
||||
BOSBUCKET: "paddle-site-web-dev"
|
||||
PREVIEW_SITE: "paddle-docs-preview.paddlepaddle.org.cn"
|
||||
AGILE_COMPILE_BRANCH: ${{ startsWith(github.event.pull_request.base.ref, 'fleety_') && 'develop' || github.event.pull_request.base.ref }}
|
||||
BOS_CREDENTIAL_AK: "paddle"
|
||||
BOS_CREDENTIAL_SK: "paddle"
|
||||
PADDLE_WHL: https://paddle-github-action.bj.bcebos.com/PR/build/${{ github.event.pull_request.number }}/${{ github.event.pull_request.head.sha }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_doc_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache/python35-cpu:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CACHE_DIR \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e AGILE_PULL_ID \
|
||||
-e AGILE_REVISION \
|
||||
-e BUILD_DOC \
|
||||
-e UPLOAD_DOC \
|
||||
-e BOSBUCKET \
|
||||
-e PREVIEW_SITE \
|
||||
-e BRANCH \
|
||||
-e AGILE_COMPILE_BRANCH \
|
||||
-e BOS_CREDENTIAL_AK \
|
||||
-e BOS_CREDENTIAL_SK \
|
||||
-e PADDLE_WHL \
|
||||
-e CFS_DIR \
|
||||
-e work_dir \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Doc build
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${AGILE_PULL_ID}/${AGILE_REVISION}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
if ! api_doc_spec_diff=$(python tools/diff_api.py paddle/fluid/API_DEV.spec.doc paddle/fluid/API_PR.spec.doc); then
|
||||
echo "diff_api.py failed for API doc specs."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$api_doc_spec_diff" ]; then
|
||||
echo "API documents no change."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd /
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
pip3 install --progress-bar off -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple --force-reinstall ${work_dir}/build/pr_whl/*.whl
|
||||
bash ${work_dir}/ci/run_docs_preview.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,322 @@
|
||||
name: PR-CI-Inference
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_inference_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /paddle/ci
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
docker_image: ${{ inputs.docker_inference_image }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "inference"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-inference_build
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_fraction_of_gpu_memory_to_use: "0.15"
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 4
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_TESTING: "OFF"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
CUDA_VISIBLE_DEVICES: "0,1"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/inference_demo
|
||||
WITH_PYTHON: "OFF"
|
||||
PY_VERSION: "3.10"
|
||||
WITH_ONNXRUNTIME: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_NVCC_LAZY: "OFF"
|
||||
PYTHON_ABI: cp310-cp310
|
||||
CACHE_DIR: /root/.cache/inference
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: "0.8"
|
||||
CUDA_ARCH_NAME: Pascal
|
||||
PADDLE_CUDA_INSTALL_REQUIREMENTS: "ON"
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/home/data/cfs/.ccache/inference:/root/.ccache/inference" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v "${{ github.workspace }}/../../..:/action-runner" \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e WITH_AVX \
|
||||
-e CUDA_VISIBLE_DEVICES \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e WITH_PYTHON \
|
||||
-e WITH_ONNXRUNTIME \
|
||||
-e WITH_NVCC_LAZY \
|
||||
-e PYTHON_ABI \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_TESTING \
|
||||
-e PY_VERSION \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e PADDLE_CUDA_INSTALL_REQUIREMENTS \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${container_name} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle-build/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git config --global --add safe.directory "*"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
source /action-runner/proxy
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream develop"
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Run build
|
||||
run: |
|
||||
docker exec -t ${container_name} /bin/bash -c '
|
||||
source /action-runner/proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash ${ci_scripts}/inference_build.sh
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Upload build.tar.gz
|
||||
env:
|
||||
home_path: /action-runner
|
||||
bos_file: /action-runner/bos_retry/BosClient.py
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
source /action-runner/proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
rm -rf `find . -name "*.o"`
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --tries=5 --no-proxy -O ${{ env.home_path }}/bos_retry.tar.gz https://xly-devops.bj.bcebos.com/home/bos_retry.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos_retry
|
||||
tar xf ${{ env.home_path }}/bos_retry.tar.gz -C ${{ env.home_path }}/bos_retry
|
||||
fi
|
||||
source /action-runner/unproxy
|
||||
cd /
|
||||
tar --use-compress-program="pigz -1" -cpPf build.tar.gz paddle
|
||||
echo "Uploading build.tar.gz to cfs"
|
||||
mkdir -p ${CFS_DIR}/inference_bos/${PR_ID}/${COMMIT_ID}
|
||||
cp build.tar.gz ${CFS_DIR}/inference_bos/${PR_ID}/${COMMIT_ID} && echo success
|
||||
rm build.tar.gz
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
# docker exec -t ${container_name} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${container_name}
|
||||
docker rm ${container_name}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: build
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-inference_test
|
||||
runs-on:
|
||||
group: Inference-P4
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
FLAGS_fraction_of_gpu_memory_to_use: "0.15"
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 4
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_TESTING: "OFF"
|
||||
COVERALLS_UPLOAD: "ON"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
CUDA_VISIBLE_DEVICES: "0,1"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
INFERENCE_DEMO_INSTALL_DIR: /root/.cache/inference_demo
|
||||
WITH_PYTHON: "OFF"
|
||||
PY_VERSION: "3.10"
|
||||
WITH_ONNXRUNTIME: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_NVCC_LAZY: "OFF"
|
||||
PYTHON_ABI: cp310-cp310
|
||||
CACHE_DIR: /root/.cache/inference
|
||||
CCACHE_DIR: /root/.ccache/inference
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: "0.8"
|
||||
CUDA_ARCH_NAME: Auto
|
||||
PADDLE_CUDA_INSTALL_REQUIREMENTS: "ON"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker pull $docker_image
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v "${{ github.workspace }}/../../..:/action-runner" \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e WITH_AVX \
|
||||
-e CUDA_VISIBLE_DEVICES \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e WITH_PYTHON \
|
||||
-e WITH_ONNXRUNTIME \
|
||||
-e WITH_NVCC_LAZY \
|
||||
-e PYTHON_ABI \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_TESTING \
|
||||
-e PY_VERSION \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e PADDLE_CUDA_INSTALL_REQUIREMENTS \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download paddle.tar.gz
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/inference_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
tar --use-compress-program="pigz -1" -xpf build.tar.gz --strip-components=1
|
||||
rm build.tar.gz
|
||||
export PATH=$(pwd)/run_env:${PATH}
|
||||
echo "export PATH=${PATH}" >> ~/.bashrc
|
||||
echo "::group::Install dependencies"
|
||||
source /action-runner/proxy
|
||||
pip install -r "python/unittest_py/requirements.txt"
|
||||
echo "::endgroup::"
|
||||
'
|
||||
|
||||
- name: Test fluid library for inference
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/utils.sh
|
||||
init
|
||||
source /action-runner/proxy
|
||||
test_fluid_lib
|
||||
'
|
||||
|
||||
- name: Test go inference api
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/utils.sh
|
||||
init
|
||||
source /action-runner/proxy
|
||||
test_go_inference_api
|
||||
'
|
||||
|
||||
- name: Check approvals of unittest
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/utils.sh
|
||||
init
|
||||
source /action-runner/proxy
|
||||
check_approvals_of_unittest 3
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
# docker exec -t ${container_name} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${container_name}
|
||||
docker rm ${container_name}
|
||||
@@ -0,0 +1,201 @@
|
||||
name: Linux-CPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_cpu_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
outputs:
|
||||
can-skip:
|
||||
description: "Whether to skip the job"
|
||||
value: ${{ jobs.check-bypass.outputs.can-skip }}
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-cpu
|
||||
ci_scripts: ${{ github.workspace }}/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: cpu
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: cpu
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-and-test:
|
||||
name: Build and test
|
||||
outputs:
|
||||
can-skip: ${{ needs.check-bypass.outputs.can-skip || inputs.clone-can-skip || 'false' }}
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
WITH_GPU: "OFF"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_MKL: "OFF"
|
||||
WITH_TESTING: "ON"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
PREC_SUFFIX: .py3
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.10"
|
||||
PROC_RUN: 12
|
||||
FLAGS_enable_eager_mode: 1
|
||||
WITH_TENSORRT: "OFF"
|
||||
GENERATOR: "Ninja"
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
WITH_AVX: "OFF"
|
||||
CACHE_DIR: "/root/.cache/cpu"
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
WITH_OPENVINO: "ON"
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_cpu_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache/python35-cpu:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e WITH_GPU \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_MKL \
|
||||
-e WITH_TESTING \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PREC_SUFFIX \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e PROC_RUN \
|
||||
-e FLAGS_enable_eager_mode \
|
||||
-e WITH_TENSORRT \
|
||||
-e GENERATOR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e GITHUB_ENV \
|
||||
-e ci_scripts \
|
||||
-e WITH_AVX \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e CI_name \
|
||||
-e no_proxy \
|
||||
-e WITH_OPENVINO \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
cp ci/git_pull.sh ci/git_pull_copy.sh
|
||||
git checkout $BRANCH
|
||||
bash ci/git_pull_copy.sh $BRANCH
|
||||
git fetch upstream $BRANCH
|
||||
git checkout test
|
||||
git merge --no-edit $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_linux_cpu_test.sh
|
||||
EXCODE=$?
|
||||
source ${ci_scripts}/utils.sh; clean_build_files
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Upload paddle_whl
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos/BosClient.py
|
||||
paddle_whl: paddlepaddle-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
echo "::group::Install bce-python-sdk"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
echo "::endgroup::"
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos
|
||||
tar -xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
|
||||
fi
|
||||
cd dist
|
||||
echo "Uploading paddle_whl to bos"
|
||||
source ${{ github.workspace }}/../../../unproxy
|
||||
python3.10 ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/cpu_whl/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,308 @@
|
||||
name: Linux-DCU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_dcu_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
docker_image: ${{ inputs.docker_dcu_image }}
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /paddle/ci
|
||||
ci_scripts_runner: ${{ github.workspace }}/ci
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
PADDLE_BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: dcu
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "dcu"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-dcu_build
|
||||
runs-on:
|
||||
group: HK-CPU
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
WITH_DOC: "OFF"
|
||||
WITH_GPU: "OFF"
|
||||
WITH_ROCM: "ON"
|
||||
WITH_RCCL: "ON"
|
||||
WITH_XPU: "OFF"
|
||||
WITH_TENSORRT: "OFF"
|
||||
WITH_COVERAGE: "OFF"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
CMAKE_BUILD_TYPE: "Release"
|
||||
WITH_AVX: "ON"
|
||||
WITH_MKL: "ON"
|
||||
WITH_ARM: "OFF"
|
||||
WITH_CACHE: "ON"
|
||||
RUN_TEST: "ON"
|
||||
WITH_TESTING: "ON"
|
||||
CI_SKIP_CPP_TEST: "OFF"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS: "ON"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
PY_VERSION: "3.10"
|
||||
CACHE_DIR: /root/.cache
|
||||
CCACHE_DIR: /root/.ccache
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
home_dir: ${{ github.workspace }}/../../../..
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run --shm-size=128G \
|
||||
--ulimit nofile=102400:102400 -d -t --name ${container_name} \
|
||||
-v $home_dir/.cache:/root/.cache \
|
||||
-v $home_dir/.ccache:/root/.ccache \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_DOC \
|
||||
-e WITH_GPU \
|
||||
-e WITH_ROCM \
|
||||
-e WITH_RCCL \
|
||||
-e WITH_XPU \
|
||||
-e WITH_TENSORRT \
|
||||
-e WITH_COVERAGE \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e CMAKE_BUILD_TYPE \
|
||||
-e WITH_MKL \
|
||||
-e WITH_AVX \
|
||||
-e WITH_ARM \
|
||||
-e RUN_TEST \
|
||||
-e WITH_TESTING \
|
||||
-e CI_SKIP_CPP_TEST \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e BRANCH \
|
||||
-e PADDLE_BRANCH \
|
||||
-e PADDLE_VERSION \
|
||||
-e no_proxy \
|
||||
-e CMAKE_EXPORT_COMPILE_COMMANDS \
|
||||
-e PY_VERSION \
|
||||
-e GIT_PR_ID \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
ulimit -n 102400
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream develop or target branch"
|
||||
git pull upstream $BRANCH --no-edit
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Run build
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source /opt/dtk-24.04.1/env.sh
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
rm -rf `find . -name "*.a"`
|
||||
rm -rf `find . -name "*.o"`
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Upload build.tar.gz and paddle_whl to bos
|
||||
env:
|
||||
AK: paddle
|
||||
SK: paddle
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos/BosClient.py
|
||||
paddle_whl: paddlepaddle_dcu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos
|
||||
tar xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
|
||||
fi
|
||||
apt install zstd -y
|
||||
cd ..
|
||||
tar --use-compress-program="pzstd -5" -cf build.tar.gz paddle
|
||||
echo "Uploading build.tar.gz"
|
||||
python ${{ env.bos_file }} build.tar.gz paddle-github-action/PR/dcu/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading paddle_whl"
|
||||
cp /paddle/dist/${{ env.paddle_whl }} .
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/dcu/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker stop ${container_name}
|
||||
docker rm ${container_name}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: build
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-dcu_test
|
||||
runs-on:
|
||||
group: dcu-z100
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
set -x
|
||||
runner_name=`(echo $PWD|awk -F '/' '{print $3}')`
|
||||
wget -q https://xly-devops.bj.bcebos.com/utils.sh
|
||||
source utils.sh
|
||||
determine_dcu_runner ${runner_name}
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
CMAKE_BUILD_TYPE: Release
|
||||
WITH_ROCM: "ON"
|
||||
WITH_RCCL: "ON"
|
||||
WITH_AVX: "ON"
|
||||
WITH_MKL: "ON"
|
||||
IF_DCU: "OFF"
|
||||
WITH_TENSORRT: "OFF"
|
||||
WITH_XPU: "OFF"
|
||||
WITH_CINN: "ON"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_TESTING: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
HIP_VISIBLE_DEVICES: ${{ env.HIP_VISIBLE_DEVICES }}
|
||||
PY_VERSION: "3.10"
|
||||
CACHE_DIR: /root/.cache
|
||||
CCACHE_DIR: /root/.ccache
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
home_dir: ${{ github.workspace }}/../../../..
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run --ulimit nofile=102400 --ulimit core=-1 --shm-size=32g -d -t --name ${container_name} \
|
||||
-v /ssd1/cibuild/.cache:/root/.cache \
|
||||
-v /ssd1/cibuild/.ccache:/root/.ccache \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
--device=/dev/kfd \
|
||||
--device=/dev/dri \
|
||||
--device=/dev/mkfd \
|
||||
--group-add video \
|
||||
--shm-size=32g \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_ROCM \
|
||||
-e WITH_RCCL \
|
||||
-e WITH_AVX \
|
||||
-e WITH_MKL \
|
||||
-e WITH_TENSORRT \
|
||||
-e WITH_XPU \
|
||||
-e IF_DCU \
|
||||
-e HIP_VISIBLE_DEVICES \
|
||||
-e WITH_RCCL \
|
||||
-e CMAKE_BUILD_TYPE \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_TESTING \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PY_VERSION \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e WITH_INFERENCE_API_TEST \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e WITH_AVX \
|
||||
-e no_proxy \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download build.tar.gz
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf ./*
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/dcu/${PR_ID}/${COMMIT_ID}/build.tar.gz --no-check-certificate
|
||||
tar --use-compress-program="pzstd" -xf build.tar.gz --strip-components=1
|
||||
rm build.tar.gz
|
||||
'
|
||||
|
||||
- name: Run test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PATH=/usr/local/bin:${PATH}
|
||||
ln -sf $(which python3.10) /usr/local/bin/python
|
||||
ln -sf $(which pip3.10) /usr/local/bin/pip
|
||||
pip3.10 install ./dist/paddlepaddle_dcu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
wget -q --no-proxy https://paddle-device.bj.bcebos.com/dcu/hyhal-Z100.tar.gz
|
||||
tar -zxf hyhal-Z100.tar.gz -C /opt
|
||||
source /opt/dtk-24.04.1/env.sh
|
||||
bash -x ${ci_scripts}/dcu_test.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
'
|
||||
docker stop ${container_name}
|
||||
docker rm ${container_name}
|
||||
@@ -0,0 +1,466 @@
|
||||
name: Linux-IXUCA
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
concurrency:
|
||||
group: linux-ixuca-pr-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: ixuca
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "ixuca"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
test-primary:
|
||||
name: Build and Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on: iluvatar-gpu-2
|
||||
timeout-minutes: 120
|
||||
container:
|
||||
image: ccr-2vdh3abv-pub.cnc.bj.baidubce.com/device/paddle-ixuca:3.3.0
|
||||
env:
|
||||
LD_LIBRARY_PATH: /usr/local/corex/lib
|
||||
LIBRARY_PATH: /usr/local/corex/lib
|
||||
env:
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
outputs:
|
||||
result: ${{ steps.set-result.outputs.result }}
|
||||
|
||||
steps:
|
||||
- name: Check approval
|
||||
id: check-approval
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
AUTHORIZED_REVIEWERS=("YqGe585" "yongqiangma")
|
||||
|
||||
echo "Authorized reviewers: ${AUTHORIZED_REVIEWERS[*]}"
|
||||
echo "Repository: ${{ github.repository }}"
|
||||
echo "PR number: ${{ github.event.pull_request.number }}"
|
||||
|
||||
response=""
|
||||
for i in 1 2 3; do
|
||||
_tmp=$(curl -s --fail --max-time 30 \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews" 2>/dev/null) && { response="$_tmp"; break; }
|
||||
echo "Attempt $i to fetch PR reviews failed, retrying..."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
echo "Response length: ${#response}"
|
||||
|
||||
can_skip=$(python3 -c '
|
||||
import json, sys
|
||||
|
||||
def debug(msg):
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
debug("=== Review Check Debug Info ===")
|
||||
debug(f"Authorized reviewers: {sys.argv[1:]}")
|
||||
AUTHORIZED = set(sys.argv[1:])
|
||||
|
||||
try:
|
||||
input_data = sys.stdin.read()
|
||||
debug(f"Raw input data length: {len(input_data)}")
|
||||
data = json.loads(input_data)
|
||||
debug(f"Parsed {len(data)} reviews")
|
||||
except Exception as e:
|
||||
debug(f"JSON parse error: {str(e)}")
|
||||
print("false")
|
||||
sys.exit(0)
|
||||
|
||||
latest_state = {}
|
||||
debug("\n=== Review States ===")
|
||||
for r in data:
|
||||
user = r.get("user", {}).get("login")
|
||||
if not user:
|
||||
continue
|
||||
state = r.get("state")
|
||||
latest_state[user] = state
|
||||
commit_id = r.get("commit_id") or ""
|
||||
debug(f"- {user}: {state} (commit: {commit_id[:8]})")
|
||||
|
||||
debug("\n=== Final Check ===")
|
||||
for user, state in latest_state.items():
|
||||
if user in AUTHORIZED and state == "APPROVED":
|
||||
debug(f"Found APPROVED review from authorized user: {user}")
|
||||
print("true")
|
||||
sys.exit(0)
|
||||
|
||||
debug("No APPROVED review found from authorized users")
|
||||
print("false")
|
||||
' "${AUTHORIZED_REVIEWERS[@]}" <<< "$response")
|
||||
|
||||
echo "can-skip=$can_skip" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [ "$can_skip" = "true" ]; then
|
||||
echo "Found valid approval from authorized reviewer, skipping IXUCA CI"
|
||||
else
|
||||
echo "No valid approval found, running full CI"
|
||||
fi
|
||||
|
||||
- name: Download Paddle.tar.gz and setup
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy \
|
||||
https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program='pzstd' -xpf Paddle.tar.gz
|
||||
rm Paddle.tar.gz
|
||||
cd Paddle
|
||||
git config --global --add safe.directory "*"
|
||||
git config --global http.proxy http://oversea-website-proxy.aistudio.public:8888
|
||||
git config --global https.proxy http://oversea-website-proxy.aistudio.public:8888
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Fetching upstream develop branch"
|
||||
git fetch upstream develop
|
||||
echo "Rebasing test branch onto upstream/develop"
|
||||
git rebase upstream/develop || {
|
||||
echo "Rebase failed, attempting to continue with current state"
|
||||
git rebase --abort || true
|
||||
}
|
||||
echo "Latest 5 commits after rebase:"
|
||||
git log --oneline -5
|
||||
|
||||
- name: Get Paddle-iluvatar PR number
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
id: get-pcd-pr
|
||||
run: |
|
||||
# Get Paddle PR description
|
||||
PR_BODY=$(curl -s \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}" \
|
||||
| python3 -c "import json,sys; data=json.load(sys.stdin); print(data.get('body', ''))")
|
||||
|
||||
# Extract [Paddle-iluvatar PR] XXXX from description
|
||||
PCD_PR_NUM=$(echo "$PR_BODY" | grep -oP '\[Paddle-iluvatar PR\]\s*\K\d+' || echo "")
|
||||
|
||||
if [ -n "$PCD_PR_NUM" ]; then
|
||||
echo "Found Paddle-iluvatar PR: $PCD_PR_NUM"
|
||||
echo "pcd_pr_num=$PCD_PR_NUM" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "No Paddle-iluvatar PR found in PR description"
|
||||
echo "pcd_pr_num=" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Clone Paddle-iluvatar and setup
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
run: |
|
||||
git config --global --get http.proxy
|
||||
git config --global --get https.proxy
|
||||
for i in 1 2 3; do
|
||||
git clone --depth=1 -b develop https://github.com/PaddlePaddle/Paddle-iluvatar.git && break
|
||||
echo "git clone attempt $i failed, retrying in 10s..."
|
||||
rm -rf Paddle-iluvatar
|
||||
sleep 10
|
||||
done
|
||||
cd Paddle-iluvatar
|
||||
|
||||
# If Paddle-iluvatar PR number exists, fetch and merge it
|
||||
PCD_PR_NUM="${{ steps.get-pcd-pr.outputs.pcd_pr_num }}"
|
||||
if [ -n "$PCD_PR_NUM" ]; then
|
||||
git config user.email "Paddle-CI@example.com"
|
||||
git config user.name "Paddle-CI-Bot"
|
||||
git fetch --unshallow origin
|
||||
echo "Fetching and merging Paddle-iluvatar PR #$PCD_PR_NUM"
|
||||
git fetch origin pull/$PCD_PR_NUM/head:pr-$PCD_PR_NUM
|
||||
git merge pr-$PCD_PR_NUM --no-edit
|
||||
echo "Successfully merged Paddle-iluvatar PR #$PCD_PR_NUM"
|
||||
fi
|
||||
|
||||
rm -rf Paddle
|
||||
mv ../Paddle .
|
||||
|
||||
- name: Build paddlepaddle-iluvatar
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
run: |
|
||||
export PATH=/usr/local/corex/bin:$PATH
|
||||
cd Paddle-iluvatar
|
||||
apt-get install -y patchelf
|
||||
bash build_paddle.sh
|
||||
|
||||
- name: Install paddlepaddle-iluvatar
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
run: |
|
||||
pip install Paddle-iluvatar/Paddle/build/python/dist/paddlepaddle_iluvatar*.whl
|
||||
retry_or_skip() {
|
||||
if "$@"; then
|
||||
return 0
|
||||
fi
|
||||
echo "WARN: command failed, retrying in 20s: $*"
|
||||
sleep 20
|
||||
if "$@"; then
|
||||
return 0
|
||||
fi
|
||||
echo "WARN: command failed again, skip install: $*"
|
||||
return 0
|
||||
}
|
||||
retry_or_skip pip install parameterized pyyaml
|
||||
|
||||
- name: Run tests
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
run: |
|
||||
export FLAG_SKIP_FLOAT64=1
|
||||
cd Paddle-iluvatar/tests && bash run_test.sh
|
||||
|
||||
- name: Set result
|
||||
if: steps.check-approval.outputs.can-skip != 'true'
|
||||
id: set-result
|
||||
run: |
|
||||
echo "result=success" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
chmod -R 777 . || true
|
||||
|
||||
# test-fallback:
|
||||
# name: Build and Test (Fallback)
|
||||
# needs: [check-bypass, test-primary]
|
||||
# if: >-
|
||||
# ${{ always()
|
||||
# && needs.check-bypass.result == 'success'
|
||||
# && needs.check-bypass.outputs.can-skip != 'true'
|
||||
# && needs.test-primary.outputs.result != 'success' }}
|
||||
# runs-on:
|
||||
# group: test2
|
||||
# timeout-minutes: 120
|
||||
# env:
|
||||
# TASK: paddle-CI-${{ github.event.pull_request.number }}-ixuca
|
||||
|
||||
# steps:
|
||||
# - name: Check approval
|
||||
# id: check-approval
|
||||
# run: |
|
||||
# set -euo pipefail
|
||||
|
||||
# export https_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
# export http_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
|
||||
# AUTHORIZED_REVIEWERS=("YqGe585" "yongqiangma")
|
||||
|
||||
# echo "Authorized reviewers: ${AUTHORIZED_REVIEWERS[*]}"
|
||||
# echo "Repository: ${{ github.repository }}"
|
||||
# echo "PR number: ${{ github.event.pull_request.number }}"
|
||||
|
||||
# response=""
|
||||
# for i in 1 2 3; do
|
||||
# _tmp=$(curl -s --fail --max-time 30 \
|
||||
# -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
# -H "Accept: application/vnd.github.v3+json" \
|
||||
# "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews" 2>/dev/null) && { response="$_tmp"; break; }
|
||||
# echo "Attempt $i to fetch PR reviews failed, retrying..."
|
||||
# sleep 5
|
||||
# done
|
||||
|
||||
# echo "Response length: ${#response}"
|
||||
|
||||
# can_skip=$(python3 -c '
|
||||
# import json, sys
|
||||
|
||||
# def debug(msg):
|
||||
# print(msg, file=sys.stderr)
|
||||
|
||||
# debug("=== Review Check Debug Info ===")
|
||||
# debug(f"Authorized reviewers: {sys.argv[1:]}")
|
||||
# AUTHORIZED = set(sys.argv[1:])
|
||||
|
||||
# try:
|
||||
# input_data = sys.stdin.read()
|
||||
# debug(f"Raw input data length: {len(input_data)}")
|
||||
# data = json.loads(input_data)
|
||||
# debug(f"Parsed {len(data)} reviews")
|
||||
# except Exception as e:
|
||||
# debug(f"JSON parse error: {str(e)}")
|
||||
# print("false")
|
||||
# sys.exit(0)
|
||||
|
||||
# latest_state = {}
|
||||
# debug("\n=== Review States ===")
|
||||
# for r in data:
|
||||
# user = r.get("user", {}).get("login")
|
||||
# if not user:
|
||||
# continue
|
||||
# state = r.get("state")
|
||||
# latest_state[user] = state
|
||||
# commit_id = r.get("commit_id") or ""
|
||||
# debug(f"- {user}: {state} (commit: {commit_id[:8]})")
|
||||
|
||||
# debug("\n=== Final Check ===")
|
||||
# for user, state in latest_state.items():
|
||||
# if user in AUTHORIZED and state == "APPROVED":
|
||||
# debug(f"Found APPROVED review from authorized user: {user}")
|
||||
# print("true")
|
||||
# sys.exit(0)
|
||||
|
||||
# debug("No APPROVED review found from authorized users")
|
||||
# print("false")
|
||||
# ' "${AUTHORIZED_REVIEWERS[@]}" <<< "$response")
|
||||
|
||||
# echo "can-skip=$can_skip" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# if [ "$can_skip" = "true" ]; then
|
||||
# echo "Found valid approval from authorized reviewer, skipping IXUCA CI"
|
||||
# else
|
||||
# echo "No valid approval found, running full CI"
|
||||
# fi
|
||||
|
||||
# - name: Download Paddle.tar.gz and setup
|
||||
# if: steps.check-approval.outputs.can-skip != 'true'
|
||||
# timeout-minutes: 30
|
||||
# run: |
|
||||
# set -e
|
||||
# echo "Downloading Paddle.tar.gz"
|
||||
# wget -q --tries=5 --no-proxy \
|
||||
# https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
# echo "Extracting Paddle.tar.gz"
|
||||
# tar --use-compress-program='pzstd' -xpf Paddle.tar.gz
|
||||
# rm Paddle.tar.gz
|
||||
# cd Paddle
|
||||
# git config --global --add safe.directory "*"
|
||||
# git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
# git config pull.rebase false
|
||||
# git checkout test
|
||||
# echo "Fetching upstream develop branch"
|
||||
# git config --global --unset-all http.proxy || true
|
||||
# git config --global --unset-all https.proxy || true
|
||||
# export https_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
# export http_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
# git config --global http.proxy "$http_proxy"
|
||||
# git config --global https.proxy "$https_proxy"
|
||||
# git fetch upstream develop
|
||||
# echo "Rebasing test branch onto upstream/develop"
|
||||
# git rebase upstream/develop || {
|
||||
# echo "Rebase failed, attempting to continue with current state"
|
||||
# git rebase --abort || true
|
||||
# }
|
||||
# echo "Latest 5 commits after rebase:"
|
||||
# git log --oneline -5
|
||||
|
||||
# - name: Get Paddle-iluvatar PR number
|
||||
# if: steps.check-approval.outputs.can-skip != 'true'
|
||||
# id: get-pcd-pr
|
||||
# run: |
|
||||
# export https_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
# export http_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
|
||||
# # Get Paddle PR description
|
||||
# PR_BODY=$(curl -s \
|
||||
# -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
# -H "Accept: application/vnd.github.v3+json" \
|
||||
# "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}" \
|
||||
# | python3 -c "import json,sys; data=json.load(sys.stdin); print(data.get('body', ''))")
|
||||
|
||||
# # Extract [Paddle-iluvatar PR] XXXX from description
|
||||
# PCD_PR_NUM=$(echo "$PR_BODY" | grep -oP '\[Paddle-iluvatar PR\]\s*\K\d+' || echo "")
|
||||
|
||||
# if [ -n "$PCD_PR_NUM" ]; then
|
||||
# echo "Found Paddle-iluvatar PR: $PCD_PR_NUM"
|
||||
# echo "pcd_pr_num=$PCD_PR_NUM" >> "$GITHUB_OUTPUT"
|
||||
# else
|
||||
# echo "No Paddle-iluvatar PR found in PR description"
|
||||
# echo "pcd_pr_num=" >> "$GITHUB_OUTPUT"
|
||||
# fi
|
||||
|
||||
# - name: Clone Paddle-iluvatar and setup
|
||||
# if: steps.check-approval.outputs.can-skip != 'true'
|
||||
# run: |
|
||||
# export https_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
# export http_proxy=http://oversea-website-proxy.aistudio.public:8888
|
||||
|
||||
# rm -rf Paddle-iluvatar
|
||||
# git clone --depth=1 -b develop https://github.com/PaddlePaddle/Paddle-iluvatar.git
|
||||
# cd Paddle-iluvatar
|
||||
|
||||
# # If Paddle-iluvatar PR number exists, fetch and merge it
|
||||
# PCD_PR_NUM="${{ steps.get-pcd-pr.outputs.pcd_pr_num }}"
|
||||
# if [ -n "$PCD_PR_NUM" ]; then
|
||||
# git config user.email "Paddle-CI@example.com"
|
||||
# git config user.name "Paddle-CI-Bot"
|
||||
# git fetch --unshallow origin
|
||||
# echo "Fetching and merging Paddle-iluvatar PR #$PCD_PR_NUM"
|
||||
# git fetch origin pull/$PCD_PR_NUM/head:pr-$PCD_PR_NUM
|
||||
# git merge pr-$PCD_PR_NUM --no-edit
|
||||
# echo "Successfully merged Paddle-iluvatar PR #$PCD_PR_NUM"
|
||||
# fi
|
||||
|
||||
# rm -rf Paddle
|
||||
# mv ../Paddle .
|
||||
|
||||
# - name: Start docker container
|
||||
# if: steps.check-approval.outputs.can-skip != 'true'
|
||||
# run: |
|
||||
# container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
# echo "container_name=${container_name}" >> $GITHUB_ENV
|
||||
# docker run --network host --privileged --cap-add=ALL \
|
||||
# --pid=host --shm-size=128G -d -t --name ${container_name} \
|
||||
# -v /usr/src:/usr/src -v /lib/modules:/lib/modules \
|
||||
# -v /dev:/dev -v /home:/home -v /data:/data \
|
||||
# -v ${{ github.workspace }}/Paddle-iluvatar:/paddle \
|
||||
# -e LD_LIBRARY_PATH=/usr/local/corex/lib \
|
||||
# -e LIBRARY_PATH=/usr/local/corex/lib \
|
||||
# -v /root/.cache:/root/.cache \
|
||||
# -v /root/.cache:/root/.ccache \
|
||||
# -e BRANCH -e PR_ID -e COMMIT_ID \
|
||||
# -w /paddle \
|
||||
# ccr-2vdh3abv-pub.cnc.bj.baidubce.com/device/paddle-ixuca:3.3.0 /bin/bash
|
||||
|
||||
# - name: Build and test
|
||||
# if: steps.check-approval.outputs.can-skip != 'true'
|
||||
# run: |
|
||||
# docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
# retry_or_skip() {
|
||||
# if "$@"; then
|
||||
# return 0
|
||||
# fi
|
||||
# echo "WARN: command failed, retrying in 20s: $*"
|
||||
# sleep 20
|
||||
# if "$@"; then
|
||||
# return 0
|
||||
# fi
|
||||
# echo "WARN: command failed again, skip install: $*"
|
||||
# return 0
|
||||
# }
|
||||
# export PATH=/usr/local/corex/bin:$PATH
|
||||
# apt-get install -y patchelf
|
||||
# bash build_paddle.sh
|
||||
# pip install Paddle/build/python/dist/paddlepaddle_iluvatar*.whl
|
||||
# retry_or_skip pip install parameterized pyyaml
|
||||
# export FLAG_SKIP_FLOAT64=1
|
||||
# cd tests && bash run_test.sh
|
||||
# '
|
||||
|
||||
# - name: Cleanup
|
||||
# if: always()
|
||||
# run: |
|
||||
# docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*' || true
|
||||
# docker stop ${{ env.container_name }} || true
|
||||
# docker rm ${{ env.container_name }} || true
|
||||
@@ -0,0 +1,197 @@
|
||||
name: Linux-NPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
docker_npu_image:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
env:
|
||||
docker_image: ${{ inputs.docker_npu_image }}
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /paddle/ci
|
||||
ci_scripts_runner: ${{ github.workspace }}/ci
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-npu
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: npu
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "npu"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: NPU
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker run -i --rm \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e BRANCH \
|
||||
-w /paddle $docker_image /bin/bash -c 'rm -rf * .[^.]*'
|
||||
source ~/.bashrc
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
tar --use-compress-program='pzstd' -xpf Paddle.tar.gz
|
||||
rm Paddle.tar.gz
|
||||
cd Paddle
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream develop"
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
runner_name=`(echo $PWD|awk -F '/' '{print $3}')`
|
||||
echo $runner_name
|
||||
source ${{ github.workspace }}/Paddle/ci/utils.sh
|
||||
determine_npu_runner ${runner_name}
|
||||
echo no_proxy="localhost,127.0.0.1,localaddress,.bj.bcebos.com,.localdomain.com,.cdn.bcebos.com,.baidu.com,.bcebos.com" >> ${{ github.env }}
|
||||
|
||||
- name: Clone PaddleCustomDevice repository
|
||||
run: |
|
||||
source ~/.bashrc
|
||||
git clone --depth=1000 -b develop https://github.com/PaddlePaddle/PaddleCustomDevice.git
|
||||
cd PaddleCustomDevice
|
||||
cp -r ../Paddle .
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_COVERAGE: "OFF"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AGILE_PULL_ID: ${{ github.event.pull_request.number }}
|
||||
AGILE_REVISION: ${{ github.event.pull_request.head.sha }}
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PYTHON_VERSION: "3.10"
|
||||
no_proxy: bcebos.com
|
||||
USE_910B: 1
|
||||
FLAGS_set_to_1d: "False"
|
||||
NVIDIA_TF32_OVERRIDE: 0
|
||||
paddle_submodule: "ON"
|
||||
MC2: 1
|
||||
HCCL_OP_BASE_FFTS_MODE_ENABLE: "TRUE"
|
||||
PADDLE_XCCL_BACKEND: npu
|
||||
HCCL_SOCKET_IFNAME: =xgbe0
|
||||
FLAGS_eager_communication_connection: 1
|
||||
FLAGS_use_stride_kernel: 0
|
||||
FLAGS_allocator_strategy: naive_best_fit
|
||||
FLAGS_npu_storage_format: 0
|
||||
TEST_IMPORTANT: "ON"
|
||||
PADDLE_BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
home_dir: ${{ github.workspace }}/../../../..
|
||||
run: |
|
||||
echo ${ASCEND_RT_VISIBLE_DEVICES}
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run --privileged --pids-limit 409600 --shm-size=128G -d -t \
|
||||
--cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name ${container_name} \
|
||||
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
|
||||
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
||||
-v /usr/local/dcmi:/usr/local/dcmi \
|
||||
-v /ssd2/workspace/npu-dev/.cache:/root/.cache \
|
||||
-v /ssd2/workspace/npu-dev/.ccache:/root/.ccache \
|
||||
-v $home_dir/actions-runner:$home_dir/actions-runner \
|
||||
-v ${{ github.workspace }}/PaddleCustomDevice:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e PADDLE_VERSION \
|
||||
-e ASCEND_RT_VISIBLE_DEVICES \
|
||||
-e WITH_COVERAGE \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e AGILE_PULL_ID \
|
||||
-e AGILE_REVISION \
|
||||
-e GIT_PR_ID \
|
||||
-e PYTHON_VERSION \
|
||||
-e no_proxy \
|
||||
-e USE_910B \
|
||||
-e FLAGS_set_to_1d \
|
||||
-e NVIDIA_TF32_OVERRIDE \
|
||||
-e paddle_submodule \
|
||||
-e MC2 \
|
||||
-e HCCL_OP_BASE_FFTS_MODE_ENABLE \
|
||||
-e PADDLE_XCCL_BACKEND \
|
||||
-e HCCL_SOCKET_IFNAME \
|
||||
-e FLAGS_eager_communication_connection \
|
||||
-e FLAGS_use_stride_kernel \
|
||||
-e FLAGS_allocator_strategy \
|
||||
-e FLAGS_npu_storage_format \
|
||||
-e TEST_IMPORTANT \
|
||||
-e PADDLE_BRANCH \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Install Paddle-CPU
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -x
|
||||
source ~/.bashrc
|
||||
wget -q https://sys-p0.bj.bcebos.com/libstdc%2B%2B6_13.1.0-8ubuntu1_20.04.2_amd64.deb
|
||||
dpkg -i *deb
|
||||
wget -q --no-proxy https://paddle-github-action.bj.bcebos.com/PR/cpu_whl/${PR_ID}/${COMMIT_ID}/paddlepaddle-0.0.0-cp310-cp310-linux_x86_64.whl --no-check-certificate
|
||||
PATH=/usr/local/bin:${PATH}
|
||||
echo "export PATH=$PATH" >> ~/.bashrc
|
||||
ln -sf $(which python3.10) /usr/local/bin/python
|
||||
ln -sf $(which pip3.10) /usr/local/bin/pip
|
||||
ln -sf $(which python3.10) /usr/bin/python
|
||||
ln -sf $(which pip3.10) /usr/bin/pip
|
||||
echo "::group::Install Paddle"
|
||||
pip install paddlepaddle-*.whl && rm -rf paddlepaddle-*.whl
|
||||
python -c "import paddle; print(paddle.__version__)"
|
||||
python -c "import paddle; print(paddle.version.commit)"
|
||||
echo "::endgroup::"
|
||||
'
|
||||
|
||||
- name: Build and test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ~/.bashrc
|
||||
set -x
|
||||
echo "::group::Install dependencies"
|
||||
python -m pip install PyGithub
|
||||
python -m pip install wheel
|
||||
echo "::endgroup::"
|
||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh
|
||||
pip install -U numpy==1.26.4
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
git config --global --add safe.directory ${work_dir}/Paddle
|
||||
cd Paddle
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
cd ..
|
||||
bash backends/npu/tools/pr_ci_npu.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${container_name} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${container_name}
|
||||
docker rm ${container_name}
|
||||
@@ -0,0 +1,283 @@
|
||||
name: Linux-XPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_xpu_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
docker_image: ${{ inputs.docker_xpu_image }}
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /paddle/ci
|
||||
ci_scripts_runner: ${{ github.workspace }}/ci
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: xpu
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "xpu"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-xpu_build
|
||||
runs-on:
|
||||
group: XPU-build
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_XPU: "ON"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
WITH_AVX: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_TESTING: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
PY_VERSION: "3.10"
|
||||
XPU_VISIBLE_DEVICES: "0,1"
|
||||
WITH_XPU_BKCL: "ON"
|
||||
WITH_XPU_FFT: "ON"
|
||||
WITH_XPU_XRE5: "ON"
|
||||
CACHE_DIR: /root/.cache
|
||||
CCACHE_DIR: /root/.ccache
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
IF_KUNLUN3: "OFF"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
home_dir: ${{ github.workspace }}/../../../..
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run --ulimit nofile=102400:102400 -d -t --name ${container_name} \
|
||||
-v $home_dir/.cache:/root/.cache \
|
||||
-v $home_dir/.ccache:/root/.ccache \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_XPU \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_TESTING \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PY_VERSION \
|
||||
-e XPU_VISIBLE_DEVICES \
|
||||
-e WITH_XPU_BKCL \
|
||||
-e WITH_XPU_FFT \
|
||||
-e WITH_XPU_XRE5 \
|
||||
-e WITH_INFERENCE_API_TEST \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e WITH_AVX \
|
||||
-e IF_KUNLUN3 \
|
||||
-e no_proxy \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download paddle.tar.gz and update test branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
ulimit -n 102400
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
git config pull.rebase false
|
||||
git checkout test
|
||||
echo "Pull upstream develop or target branch"
|
||||
bash ci/git_pull.sh $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Run build
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
apt install zstd -y
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
bash ${ci_scripts}/compress_build.sh
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Upload build.tar.gz and paddle_whl to bos
|
||||
env:
|
||||
AK: paddle
|
||||
SK: paddle
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos/BosClient.py
|
||||
paddle_whl: paddlepaddle_xpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
set -e
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos
|
||||
tar xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
|
||||
fi
|
||||
cd ..
|
||||
tar --use-compress-program="pzstd -5" -cf build.tar.gz paddle
|
||||
# source /home/opt/deck/1.0/etc/bashrc
|
||||
echo "Uploading build.tar.gz"
|
||||
python ${{ env.bos_file }} build.tar.gz paddle-github-action/PR/xpu/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading paddle_whl"
|
||||
cp /paddle/dist/${{ env.paddle_whl }} .
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/xpu/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${container_name}
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: build
|
||||
env:
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-xpu_test
|
||||
runs-on:
|
||||
group: Kunlun
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Determine the runner
|
||||
run: |
|
||||
runner_name=`(echo $PWD|awk -F '/' '{print $3}')`
|
||||
echo $runner_name
|
||||
wget -q https://xly-devops.bj.bcebos.com/utils.sh
|
||||
source utils.sh
|
||||
determine_kunlun_runner ${runner_name}
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
WITH_XPU: "ON"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
CMAKE_BUILD_TYPE: Release
|
||||
WITH_AVX: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_TESTING: "ON"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
PY_VERSION: "3.10"
|
||||
XPU_VISIBLE_DEVICES: ${{ env.CUDA_VISIBLE_DEVICES }}
|
||||
CUDA_VISIBLE_DEVICES: ${{ env.CUDA_VISIBLE_DEVICES }}
|
||||
WITH_XPU_BKCL: "ON"
|
||||
CACHE_DIR: /root/.cache
|
||||
CCACHE_DIR: /root/.ccache
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
IF_KUNLUN3: "OFF"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
home_dir: ${{ github.workspace }}/../../../..
|
||||
FLAGS_use_stride_kernel: "0"
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker run --ulimit nofile=102400 --ulimit core=-1 --shm-size=32g -d -t --name ${container_name} \
|
||||
-v /ssd1/cibuild/.cache:/root/.cache \
|
||||
-v /ssd1/cibuild/.ccache:/root/.ccache \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-v /ssd1/cibuild/tmp:/tmp \
|
||||
--device ${XPU_CODE_1} \
|
||||
--device ${XPU_CODE_2} \
|
||||
--device /dev/xpuctrl \
|
||||
--shm-size=32g \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_XPU \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e CMAKE_BUILD_TYPE \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_TESTING \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PY_VERSION \
|
||||
-e XPU_VISIBLE_DEVICES \
|
||||
-e CUDA_VISIBLE_DEVICES \
|
||||
-e WITH_XPU_BKCL \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e WITH_INFERENCE_API_TEST \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e ci_scripts \
|
||||
-e WITH_AVX \
|
||||
-e IF_KUNLUN3 \
|
||||
-e no_proxy \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e FLAGS_use_stride_kernel \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image} /bin/bash
|
||||
|
||||
- name: Download build.tar.gz
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
wget -q --no-proxy https://paddle-github-action.bj.bcebos.com/PR/xpu/${PR_ID}/${COMMIT_ID}/build.tar.gz --no-check-certificate
|
||||
tar --use-compress-program="pzstd" -xf build.tar.gz --strip-components=1
|
||||
rm build.tar.gz
|
||||
'
|
||||
|
||||
- name: Run test
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/kunlun_test.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
docker exec -t ${container_name} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${container_name}
|
||||
@@ -0,0 +1,236 @@
|
||||
name: Linux-build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
is_pr:
|
||||
type: string
|
||||
required: false
|
||||
default: "true"
|
||||
clone-can-skip:
|
||||
default: "false"
|
||||
required: false
|
||||
type: string
|
||||
outputs:
|
||||
can-skip:
|
||||
description: "Whether to skip the job"
|
||||
value: ${{ jobs.check-bypass.outputs.can-skip }}
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-build
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref || github.ref_name }}
|
||||
CI_name: build
|
||||
CFS_DIR: /home/data/cfs
|
||||
is_pr: ${{ inputs.is_pr }}
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: build
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
PADDLE_CUDA_INSTALL_REQUIREMENTS: "ON"
|
||||
FLAGS_fraction_of_gpu_memory_to_use: 0.15
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CTEST_PARALLEL_LEVEL: 2
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Volta
|
||||
WITH_COVERAGE: "OFF"
|
||||
PADDLE_FRACTION_GPU_MEMORY_TO_USE: 0.15
|
||||
CUDA_VISIBLE_DEVICES: 0,1
|
||||
PRECISION_TEST: "ON"
|
||||
WITH_CINN: "ON"
|
||||
INFERENCE_DEMO_INSTALL_DIR: /home/data/cfs/.cache/build
|
||||
WITH_INCREMENTAL_COVERAGE: "OFF"
|
||||
WITH_AVX: "ON"
|
||||
WITH_TESTING: "OFF"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PY_VERSION: "3.10"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
CCACHE_STATSLOG: /paddle/build/.stats.log
|
||||
CCACHE_SLOPPINESS: clang_index_store,time_macros,include_file_mtime
|
||||
CACHE_DIR: /home/data/cfs/.cache/build
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e BRANCH \
|
||||
-e is_pr \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e PADDLE_CUDA_INSTALL_REQUIREMENTS \
|
||||
-e FLAGS_fraction_of_gpu_memory_to_use \
|
||||
-e CTEST_OUTPUT_ON_FAILURE \
|
||||
-e CTEST_PARALLEL_LEVEL \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_COVERAGE \
|
||||
-e PADDLE_FRACTION_GPU_MEMORY_TO_USE \
|
||||
-e CUDA_VISIBLE_DEVICES \
|
||||
-e PRECISION_TEST \
|
||||
-e WITH_CINN \
|
||||
-e INFERENCE_DEMO_INSTALL_DIR \
|
||||
-e WITH_INCREMENTAL_COVERAGE \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_TESTING \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PY_VERSION \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e WITH_AVX \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e CCACHE_SLOPPINESS \
|
||||
-e CCACHE_STATSLOG \
|
||||
-e CFS_DIR \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle-build/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar -xf Paddle.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
'
|
||||
|
||||
- name: Merge target branch
|
||||
if: ${{ inputs.is_pr == 'true' }}
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
cp ci/git_pull.sh ci/git_pull_copy.sh
|
||||
git checkout $BRANCH
|
||||
bash ci/git_pull_copy.sh $BRANCH
|
||||
git fetch upstream $BRANCH
|
||||
git checkout test
|
||||
git merge --no-edit $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Build
|
||||
if: needs.check-bypass.outputs.can-skip != 'true'
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir -p /root/.cache/build
|
||||
mkdir -p /root/.ccache/build
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
'
|
||||
|
||||
- name: Check sequence op
|
||||
if: needs.check-bypass.outputs.can-skip != 'true'
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${ci_scripts}/utils.sh; init
|
||||
bash ${work_dir}/tools/check_sequence_op.sh
|
||||
clean_build_files
|
||||
'
|
||||
|
||||
- name: Upload paddle_whl
|
||||
if: needs.check-bypass.outputs.can-skip != 'true'
|
||||
env:
|
||||
home_path: ${{ github.workspace }}/..
|
||||
bos_file: ${{ github.workspace }}/../bos/BosClient.py
|
||||
paddle_whl: paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
bash ${ci_scripts}/compress_build.sh
|
||||
export AK=paddle
|
||||
export SK=paddle
|
||||
if [ ! -f "${{ env.bos_file }}" ]; then
|
||||
wget -q --no-proxy -O ${{ env.home_path }}/bos_new.tar.gz https://xly-devops.bj.bcebos.com/home/bos_new.tar.gz --no-check-certificate
|
||||
mkdir ${{ env.home_path }}/bos
|
||||
tar xf ${{ env.home_path }}/bos_new.tar.gz -C ${{ env.home_path }}/bos
|
||||
fi
|
||||
cd /paddle/build/paddle
|
||||
ls | grep -v cinn | xargs rm -rf
|
||||
rm -rf /paddle/build/third_party
|
||||
rm -rf /paddle/build/dist
|
||||
cd /
|
||||
tar --use-compress-program="pzstd -1" -cf build.tar.gz paddle
|
||||
echo "Uploading build.tar.gz to bos"
|
||||
python ${{ env.bos_file }} build.tar.gz paddle-github-action/PR/build/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
echo "Uploading build.tar.gz to cfs"
|
||||
mkdir -p ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}
|
||||
mv build.tar.gz ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID} && echo success
|
||||
mv /paddle/${{ env.paddle_whl }} .
|
||||
echo "Uploading paddle_whl to bos"
|
||||
python ${{ env.bos_file }} ${{ env.paddle_whl }} paddle-github-action/PR/build/${{ env.PR_ID }}/${{ env.COMMIT_ID }}
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && always() }}
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,106 @@
|
||||
name: Mac-CPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: "${{ github.workspace }}/Paddle"
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.11
|
||||
PADDLE_DEV_NAME: "paddlepaddle/paddle:dev"
|
||||
PADDLE_VERSION: 0.0.0
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
WITH_DEB: "OFF"
|
||||
RUN_TEST: "OFF"
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
WITH_FLUID_ONLY: "ON"
|
||||
WITH_TESTING: "ON"
|
||||
WITH_INFERENCE_API_TEST: "OFF"
|
||||
INSTALL_PREFIX: "/Users/paddle/CI_install_path"
|
||||
PYTHON_ABI: "cp310-cp310"
|
||||
PY_VERSION: "3.10"
|
||||
WITH_AVX: "OFF"
|
||||
WITH_ARM: "ON"
|
||||
PROC_RUN: 8
|
||||
WITH_CACHE: "ON"
|
||||
NIGHTLY_MODE: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PRECISION_TEST: "OFF"
|
||||
CI_SKIP_CPP_TEST: "OFF"
|
||||
WITH_ONNXRUNTIME: "OFF"
|
||||
WITH_TENSORRT: "OFF"
|
||||
GENERATOR: "Ninja"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: mac
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
build-and-test:
|
||||
name: Build and test
|
||||
if: ${{ inputs.clone-can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass]
|
||||
runs-on:
|
||||
group: Mac-CI
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- name: Check environment
|
||||
run: |
|
||||
set -x
|
||||
cd ${work_dir}
|
||||
[ -d "${work_dir}/Paddle" ] && rm -rf ${work_dir}/Paddle
|
||||
[ -f "${work_dir}/Paddle.tar.gz" ] && rm -rf ${work_dir}/Paddle.tar.gz
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
tar xf Paddle.tar.gz && cd Paddle
|
||||
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote -v
|
||||
set +e
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
set -e
|
||||
cp ci/git_pull.sh ci/git_pull_copy.sh
|
||||
git checkout $BRANCH
|
||||
bash ci/git_pull_copy.sh $BRANCH
|
||||
git fetch upstream $BRANCH
|
||||
git checkout test
|
||||
git merge --no-edit $BRANCH
|
||||
git submodule update
|
||||
|
||||
- name: Build with mac python3.10
|
||||
run: |
|
||||
set -x
|
||||
cd ${work_dir}/Paddle
|
||||
source ~/.zshrc
|
||||
bash -x ${work_dir}/Paddle/ci/run_setup.sh bdist_wheel ${parallel_number:-""}
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
|
||||
- name: Test with mac python3.10
|
||||
run: |
|
||||
set -ex
|
||||
cd ${work_dir}/Paddle
|
||||
pip3.10 install -r ${work_dir}/Paddle/python/unittest_py/requirements.txt
|
||||
pip3.10 install -U ${work_dir}/Paddle/dist/*whl
|
||||
bash -x ${work_dir}/Paddle/ci/run_mac_test.sh ${PYTHON_ABI:-""} ${PROC_RUN:-""}
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
@@ -0,0 +1,168 @@
|
||||
name: Model-benchmark
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
ci_scripts: /workspace/paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-Model-benchmark
|
||||
CI_name: model-benchmark
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "model-benchmark"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
model-benchmark:
|
||||
name: Benchmark test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: model-benchmark
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
AGILE_PULL_ID: ${{ github.event.pull_request.number }}
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PRID: ${{ github.event.pull_request.number }}
|
||||
AGILE_REVISION: ${{ github.event.pull_request.head.sha }}
|
||||
CUDA_ARCH_NAME: Volta
|
||||
CCACHE_MAXSIZE: 150G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
benchmark_ci_cache: /home/data/cfs/.cache/model_benchmark/new_benchmark
|
||||
ROOT_DIR: /workspace
|
||||
bos_path: modelBK_CI
|
||||
CACHE_DIR: /root/.cache/model_benchmark
|
||||
work_dir: /workspace/paddle
|
||||
AGILE_COMMENTS: '[{"Commit":"${{ github.event.pull_request.head.sha }}","author":"${{ github.event.pull_request.user.login }}"}]'
|
||||
run: |
|
||||
container_name=${TASK}-${core_index}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/workspace \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e BRANCH \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e AGILE_PULL_ID \
|
||||
-e GIT_PR_ID \
|
||||
-e PRID \
|
||||
-e AGILE_REVISION \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e benchmark_ci_cache \
|
||||
-e bos_path \
|
||||
-e ROOT_DIR \
|
||||
-e CACHE_DIR \
|
||||
-e work_dir \
|
||||
-e AGILE_COMMENTS \
|
||||
-w /workspace --network host ${docker_image}
|
||||
|
||||
- name: Prepare environment and download paddle
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec ${container_name} bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo $AGILE_COMMENTS
|
||||
DEVICE_ID=$(cat /sys/class/dmi/id/product_uuid |awk -F "-" "{print \$5}")
|
||||
echo "export DEVICE_ID=$DEVICE_ID" >> ~/.bashrc
|
||||
echo $DEVICE_ID
|
||||
echo "Downloading build.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/build/${PR_ID}/${COMMIT_ID}/build.tar.gz --no-check-certificate
|
||||
echo "Extracting build.tar.gz"
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz
|
||||
rm build.tar.gz
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
cd paddle && git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
source ${ci_scripts}/model_benchmark.sh
|
||||
check_paddle ${{ github.env }}
|
||||
'
|
||||
|
||||
- name: Download model_benchmark_ci
|
||||
if: ${{ env.can-skip != 'true' }}
|
||||
run: |
|
||||
docker exec ${container_name} bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/model_benchmark.sh
|
||||
wget_model_benchmark_ci
|
||||
'
|
||||
|
||||
- name: Download paddlescope
|
||||
timeout-minutes: 30
|
||||
if: ${{ env.can-skip != 'true' }}
|
||||
run: |
|
||||
docker exec ${container_name} bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/model_benchmark.sh
|
||||
get_paddlescope_tar
|
||||
'
|
||||
|
||||
- name: Check skip
|
||||
if: ${{ env.can-skip != 'true' }}
|
||||
run: |
|
||||
docker exec ${container_name} bash -c '
|
||||
source ~/.bashrc
|
||||
source ${ci_scripts}/model_benchmark.sh
|
||||
check_skip ${{ github.env }}
|
||||
'
|
||||
|
||||
- name: Check model benchmark
|
||||
if: ${{ env.can-skip != 'true' }}
|
||||
run: |
|
||||
docker exec ${container_name} bash -c '
|
||||
source ~/.bashrc
|
||||
export EXCODE=0
|
||||
source ${ci_scripts}/model_benchmark.sh
|
||||
check_model_benchmark
|
||||
if [[ $EXCODE -eq 0 ]];then
|
||||
echo "Congratulations! Your PR passed the model benchmark ci."
|
||||
elif [[ $EXCODE -eq 10 ]];then
|
||||
echo "Sorry, some models failed to run, Please check the result_html.html."
|
||||
elif [[ $EXCODE -eq 11 ]];then
|
||||
echo "Sorry, some models have abnormal performance, Please check the result_html.html."
|
||||
else
|
||||
echo "Sorry, There are environmental issues, please contact QA(guomengmeng01) for exemption."
|
||||
fi
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,318 @@
|
||||
name: PR-CI-SOT
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_sot_image:
|
||||
type: string
|
||||
required: true
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-sot
|
||||
ci_scripts: /paddle/ci
|
||||
CI_name: sot
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "sot"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-and-test:
|
||||
name: Build and Test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: GZ_BD-CPU
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: run container
|
||||
env:
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_MKL: "OFF"
|
||||
WITH_TESTING: "OFF"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
PREC_SUFFIX: .py3
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
PROC_RUN: 12
|
||||
FLAGS_enable_eager_mode: 1
|
||||
WITH_TENSORRT: "OFF"
|
||||
GENERATOR: Ninja
|
||||
WITH_INFERENCE_API_TEST: "OFF"
|
||||
CCACHE_MAXSIZE: 50G
|
||||
CCACHE_LIMIT_MULTIPLE: 0.8
|
||||
WITH_AVX: "OFF"
|
||||
CACHE_DIR: "/root/.cache/sot"
|
||||
CCACHE_DIR: "/home/data/shared/.ccache/l1" # L1 cache on machine shared dir
|
||||
CCACHE_SECONDARY_STORAGE: "file:///home/data/cfs/.ccache/l2" # L2 cache on cfs
|
||||
run: |
|
||||
set -x
|
||||
container_name=${TASK}-$(date +%s)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_sot_image }}
|
||||
docker run -d -t --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/shared:/home/data/shared" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v "${{ github.workspace }}/../../..:${{ github.workspace }}/../../.." \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e CI_name \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_MKL \
|
||||
-e WITH_TESTING \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e PREC_SUFFIX \
|
||||
-e WITH_UNITY_BUILD \
|
||||
-e PROC_RUN \
|
||||
-e FLAGS_enable_eager_mode \
|
||||
-e WITH_TENSORRT \
|
||||
-e GENERATOR \
|
||||
-e WITH_INFERENCE_API_TEST \
|
||||
-e CCACHE_MAXSIZE \
|
||||
-e CCACHE_LIMIT_MULTIPLE \
|
||||
-e GITHUB_ENV \
|
||||
-e ci_scripts \
|
||||
-e WITH_AVX \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e CCACHE_SECONDARY_STORAGE \
|
||||
-e no_proxy \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading Paddle.tar.gz"
|
||||
wget -q --tries=5 --no-proxy https://paddle-github-action.bj.bcebos.com/PR/Paddle/${PR_ID}/${COMMIT_ID}/Paddle.tar.gz --no-check-certificate
|
||||
echo "Extracting Paddle.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar xf Paddle.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm Paddle.tar.gz
|
||||
git config --global user.name "PaddleCI"
|
||||
git config --global user.email "paddle_ci@example.com"
|
||||
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
cp ci/git_pull.sh ci/git_pull_copy.sh
|
||||
git checkout $BRANCH
|
||||
bash ci/git_pull_copy.sh $BRANCH
|
||||
git fetch upstream $BRANCH
|
||||
git checkout test
|
||||
git merge --no-edit $BRANCH
|
||||
git submodule update
|
||||
'
|
||||
|
||||
- name: Determine sot ci trigger
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/determine_sot_ci_trigger.sh
|
||||
determine_excode=$?
|
||||
echo "determine_excode=$determine_excode" >> ${{ github.env }}
|
||||
'
|
||||
|
||||
- name: CMake Pre-download
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/cmake-predownload.sh
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Build with python3.10
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PY_VERSION=3.10
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test with python3.10
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_sot_test.sh 3.10
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Build with python3.11
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PY_VERSION=3.11
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test with python3.11
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_sot_test.sh 3.11
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Build with python3.12
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PY_VERSION=3.12
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test with python3.12
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_sot_test.sh 3.12
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Build with python3.13
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PY_VERSION=3.13
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test with python3.13
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_sot_test.sh 3.13
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Build with python3.14
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
export PY_VERSION=3.14
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_setup.sh bdist_wheel
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Test with python3.14
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
PADDLE_ROOT: ${{ github.workspace }}
|
||||
if: ${{ env.determine_excode == 0 }}
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/run_sot_test.sh 3.14
|
||||
EXCODE=$?
|
||||
rm -rf ${PADDLE_ROOT}/build/CMakeCache.txt
|
||||
exit $EXCODE
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,140 @@
|
||||
name: Slice
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
slice-check:
|
||||
type: string
|
||||
required: false
|
||||
SLICE_TEST_MODE:
|
||||
type: string
|
||||
required: false
|
||||
default: "test_ci"
|
||||
SLICE_BENCHMARK_FRAMEWORKS:
|
||||
type: string
|
||||
required: false
|
||||
default: "paddle"
|
||||
MANUALLY_PR_ID:
|
||||
type: string
|
||||
required: false
|
||||
MANUALLY_COMMIT_ID:
|
||||
type: string
|
||||
required: false
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '0' }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-slice
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref || github.ref_name }}
|
||||
CI_name: slice
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass-slice.yml
|
||||
with:
|
||||
workflow-name: "slice"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
slice:
|
||||
name: Slice test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: slice
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
wheel_link: https://paddle-github-action.bj.bcebos.com/PR/build/${{ env.PR_ID }}/${{ env.COMMIT_ID }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
SLICE_TEST_MODE: ${{ inputs.SLICE_TEST_MODE }}
|
||||
SLICE_BENCHMARK_FRAMEWORKS: ${{ inputs.SLICE_BENCHMARK_FRAMEWORKS }}
|
||||
run: |
|
||||
container_name="api_benchmark_ci_${RUN_ID}"
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} --shm-size=128g \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-e core_index \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e RUN_ID \
|
||||
-e wheel_link \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e SLICE_TEST_MODE \
|
||||
-e SLICE_BENCHMARK_FRAMEWORKS \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download PaddleTest
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
echo "Downloading PaddleTest"
|
||||
wget -q https://xly-devops.bj.bcebos.com/PaddleTest/PaddleTest.tar.gz --no-proxy
|
||||
echo "Extracting PaddleTest"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar -xzf PaddleTest.tar.gz && cd PaddleTest
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
'
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
mkdir -p ${{ github.workspace }}/../../../.cache/pip
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
python3.10 -m pip config set global.cache-dir ${{ github.workspace }}/../../../.cache/pip
|
||||
if [[ "${{ inputs.SLICE_BENCHMARK_FRAMEWORKS }}" == "torch" ]];then
|
||||
python3.10 -m pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 --index-url https://download.pytorch.org/whl/cu118
|
||||
else
|
||||
if [[ "${{ inputs.MANUALLY_PR_ID }}" == "" ]]; then
|
||||
python3.10 -m pip install $wheel_link
|
||||
else
|
||||
python3.10 -m pip install https://paddle-github-action.bj.bcebos.com/PR/build/${{ inputs.MANUALLY_PR_ID }}/${{ inputs.MANUALLY_COMMIT_ID }}/paddlepaddle_gpu-0.0.0-cp310-cp310-linux_x86_64.whl
|
||||
fi
|
||||
fi
|
||||
python3.10 -m pip install -r PaddleTest/framework/e2e/api_benchmark/requirement.txt
|
||||
cd PaddleTest/framework/slice_benchmark
|
||||
cp ${{ github.workspace }}/../../../apibm_config.yml .
|
||||
bash run.sh
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker rm -f ${{ env.container_name }}
|
||||
@@ -0,0 +1,172 @@
|
||||
name: Static-check
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
docker_build_image:
|
||||
type: string
|
||||
required: true
|
||||
can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
build-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
work_dir: /paddle
|
||||
PADDLE_ROOT: /paddle
|
||||
TASK: paddle-CI-${{ github.event.pull_request.number }}-static-check
|
||||
ci_scripts: /paddle/ci
|
||||
BRANCH: ${{ github.event.pull_request.base.ref }}
|
||||
CI_name: static-check
|
||||
CFS_DIR: /home/data/cfs
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
if: ${{ github.repository_owner == 'PaddlePaddle' && inputs.build-can-skip != 'true' }}
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: static-check
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
build:
|
||||
name: Test
|
||||
if: ${{ inputs.can-skip != 'true' && needs.check-bypass.outputs.can-skip != 'true' }}
|
||||
needs: [check-bypass]
|
||||
runs-on:
|
||||
group: BD_BJ-V100
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Debug - Print inputs
|
||||
run: |
|
||||
echo "=== Static-Check Debug Info ==="
|
||||
echo "inputs.can-skip: ${{ inputs.can-skip }}"
|
||||
echo "needs.check-bypass.outputs.can-skip: ${{ needs.check-bypass.outputs.can-skip }}"
|
||||
echo "needs.check-bypass.result: ${{ needs.check-bypass.result }}"
|
||||
echo "==============================="
|
||||
|
||||
- name: Check docker image and run container
|
||||
env:
|
||||
WITH_GPU: "ON"
|
||||
CUDA_ARCH_NAME: Volta
|
||||
WITH_AVX: "ON"
|
||||
WITH_TESTING: "OFF"
|
||||
WITH_COVERAGE: "OFF"
|
||||
COVERALLS_UPLOAD: "OFF"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
PADDLE_VERSION: 0.0.0
|
||||
WITH_DISTRIBUTE: "ON"
|
||||
PY_VERSION: "3.10"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
WITH_MKL: "ON"
|
||||
SAMPLE_CODE_EXEC_THREADS: 1
|
||||
CACHE_DIR: /home/data/cfs/.cache/static-check
|
||||
CCACHE_DIR: /home/data/cfs/.ccache/static-check
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
container_name=${TASK}-$(date +%Y%m%d-%H%M%S)
|
||||
echo "container_name=${container_name}" >> ${{ github.env }}
|
||||
docker_image=${{ inputs.docker_build_image }}
|
||||
docker run -d -t --gpus all --name ${container_name} \
|
||||
-v "/home/data/cfs:/home/data/cfs" \
|
||||
-v "/home/data/cfs/.cache:/root/.cache" \
|
||||
-v "/home/data/cfs/.ccache:/root/.ccache" \
|
||||
-v "/dev/shm:/dev/shm" \
|
||||
-v ${{ github.workspace }}/../../..:${{ github.workspace }}/../../.. \
|
||||
-v ${{ github.workspace }}:/paddle \
|
||||
-v /root/.cache/paddle/dataset/ESC-50-master \
|
||||
-e BRANCH \
|
||||
-e PR_ID \
|
||||
-e COMMIT_ID \
|
||||
-e work_dir \
|
||||
-e PADDLE_ROOT \
|
||||
-e ci_scripts \
|
||||
-e WITH_MKL \
|
||||
-e SAMPLE_CODE_EXEC_THREADS \
|
||||
-e WITH_GPU \
|
||||
-e CUDA_ARCH_NAME \
|
||||
-e WITH_COVERAGE \
|
||||
-e WITH_SHARED_PHI \
|
||||
-e WITH_TESTING \
|
||||
-e COVERALLS_UPLOAD \
|
||||
-e GIT_PR_ID \
|
||||
-e PADDLE_VERSION \
|
||||
-e WITH_DISTRIBUTE \
|
||||
-e PY_VERSION \
|
||||
-e WITH_AVX \
|
||||
-e CACHE_DIR \
|
||||
-e CCACHE_DIR \
|
||||
-e no_proxy \
|
||||
-e CI_name \
|
||||
-e GITHUB_API_TOKEN \
|
||||
-e CFS_DIR \
|
||||
-w /paddle --network host ${docker_image}
|
||||
|
||||
- name: Download paddle.tar.gz and merge target branch
|
||||
env:
|
||||
work_dir: ${{ github.workspace }}
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
rm -rf * .[^.]*
|
||||
set -e
|
||||
echo "Downloading build.tar.gz from cfs"
|
||||
cp ${CFS_DIR}/build_bos/${PR_ID}/${COMMIT_ID}/build.tar.gz .
|
||||
echo "Extracting build.tar.gz"
|
||||
git config --global --add safe.directory ${work_dir}
|
||||
tar --use-compress-program="pzstd -1" -xpf build.tar.gz --strip-components=1
|
||||
git submodule foreach "git config --global --add safe.directory \$toplevel/\$sm_path"
|
||||
rm build.tar.gz
|
||||
git checkout test
|
||||
'
|
||||
|
||||
- name: Static check
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${ci_scripts}/static_check.sh
|
||||
'
|
||||
|
||||
- name: Check api approval
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
source ~/.bashrc
|
||||
unset GREP_OPTIONS
|
||||
bash ${work_dir}/tools/check_api_approvals.sh;approval_error=$?
|
||||
if [ "$approval_error" != 0 ];then
|
||||
exit 6
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Check GPU Kernel approval
|
||||
run: |
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c '
|
||||
source ${{ github.workspace }}/../../../proxy
|
||||
bash ${work_dir}/tools/check_gpu_kernel_approval.sh;approval_error=$?
|
||||
if [ "$approval_error" != 0 ];then
|
||||
exit 6
|
||||
fi
|
||||
'
|
||||
|
||||
- name: Terminate and delete the container
|
||||
if: always()
|
||||
run: |
|
||||
set +e
|
||||
docker exec -t ${{ env.container_name }} /bin/bash -c 'rm -rf * .[^.]*'
|
||||
docker stop ${{ env.container_name }}
|
||||
docker rm ${{ env.container_name }}
|
||||
@@ -0,0 +1,114 @@
|
||||
name: Windows-GPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
ci_scripts: ${{ github.workspace }}\ci\windows
|
||||
ACTION_DIR: ${{ github.workspace }}\..\..\..
|
||||
WORKSPACE_DIR: ${{ github.workspace }}\..
|
||||
cache_dir: C:\action-cache
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "win-gpu"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
build-and-test:
|
||||
name: Build and test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: win-gpu
|
||||
timeout-minutes: 240
|
||||
env:
|
||||
PADDLE_VERSION: 0.0.0
|
||||
NIGHTLY_MODE: "OFF"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_TPCACHE: "OFF"
|
||||
WITH_SCCACHE: "ON"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
WITH_TESTING: "ON"
|
||||
PRECISION_TEST: "OFF"
|
||||
PYTHON_ROOT: C:\Python310
|
||||
vcvars64_dir: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat'
|
||||
CUDA_TOOLKIT_ROOT_DIR: 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0'
|
||||
TENSORRT_ROOT: D:\TensorRT
|
||||
CTEST_PARALLEL_LEVEL: 1
|
||||
GENERATOR: "Ninja"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MSVC_STATIC_CRT: "OFF"
|
||||
WITH_MKL: "ON"
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
ON_INFER: "ON"
|
||||
WITH_TENSORRT: "ON"
|
||||
WITH_INFERENCE_API_TEST: "OFF"
|
||||
WIN_UNITTEST_LEVEL: 0
|
||||
CUDA_ARCH_NAME: "Auto"
|
||||
steps:
|
||||
- name: Download Paddle and clean env
|
||||
working-directory: ..
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
whoami
|
||||
cd
|
||||
rmdir /s/q %WORKSPACE_DIR%\Paddle
|
||||
echo "path=%path%;C:\Program Files\NVIDIA Corporation\NVSMI" >> %GITHUB_ENV%
|
||||
python -m pip install wget
|
||||
python -c "import wget;wget.download('https://paddle-github-action.bj.bcebos.com/windows/PR/%PR_ID%/%COMMIT_ID%/Paddle.tar.zst')"
|
||||
zstd -d Paddle.tar.zst && tar -xf Paddle.tar
|
||||
del Paddle.tar Paddle.tar.zst
|
||||
call %ci_scripts%\clean_env.bat
|
||||
|
||||
- name: Config env
|
||||
run: |
|
||||
call %ACTION_DIR%\proxy.bat
|
||||
call %ci_scripts%\config_env.bat
|
||||
|
||||
- name: Build paddle
|
||||
run: |
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
call %ACTION_DIR%\proxy.bat
|
||||
call %ci_scripts%\build.bat
|
||||
|
||||
- name: Test whl package
|
||||
run: |
|
||||
call %ci_scripts%\test_whl_package.bat
|
||||
|
||||
- name: Test paddle
|
||||
run: |
|
||||
call %ci_scripts%\test.bat
|
||||
|
||||
- name: Test fluid library
|
||||
run: |
|
||||
call %ci_scripts%\test_fluid_library.bat
|
||||
|
||||
- name: Clean up dir
|
||||
if: always()
|
||||
run: |
|
||||
call %ci_scripts%\clean_env.bat
|
||||
if "%WITH_TESTING%"=="ON" (
|
||||
for /F "tokens=1 delims= " %%# in ('tasklist ^| findstr /i test') do taskkill /f /im %%# /t
|
||||
) || ver >nul
|
||||
@@ -0,0 +1,112 @@
|
||||
name: Windows-GPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
ci_scripts: ${{ github.workspace }}\ci\windows
|
||||
ACTION_DIR: ${{ github.workspace }}\..\..\..
|
||||
WORKSPACE_DIR: ${{ github.workspace }}\..
|
||||
cache_dir: C:\action-cache
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "win-inference"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
build-and-test:
|
||||
name: Build and test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: win-infer
|
||||
timeout-minutes: 240
|
||||
env:
|
||||
PADDLE_VERSION: 0.0.0
|
||||
NIGHTLY_MODE: "OFF"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_TPCACHE: "OFF"
|
||||
WITH_SCCACHE: "ON"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
WITH_TESTING: "ON"
|
||||
PRECISION_TEST: "OFF"
|
||||
PYTHON_ROOT: C:\Python310
|
||||
vcvars64_dir: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat'
|
||||
CUDA_TOOLKIT_ROOT_DIR: 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7'
|
||||
TENSORRT_ROOT: D:/TensorRT-8.0.1.6
|
||||
CTEST_PARALLEL_LEVEL: 1
|
||||
GENERATOR: "Ninja"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WITH_MKL: "ON"
|
||||
WITH_GPU: "ON"
|
||||
WITH_AVX: "ON"
|
||||
MSVC_STATIC_CRT: "ON"
|
||||
ON_INFER: "ON"
|
||||
WITH_TENSORRT: "ON"
|
||||
WITH_INFERENCE_API_TEST: "ON"
|
||||
WITH_ONNXRUNTIME: "ON"
|
||||
WIN_UNITTEST_LEVEL: 2
|
||||
CUDA_ARCH_NAME: "Auto"
|
||||
steps:
|
||||
- name: Download Paddle and clean env
|
||||
working-directory: ..
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
whoami
|
||||
cd
|
||||
rmdir /s/q %WORKSPACE_DIR%\Paddle
|
||||
echo "path=%path%;C:\Program Files\NVIDIA Corporation\NVSMI" >> %GITHUB_ENV%
|
||||
python -m pip install wget
|
||||
python -c "import wget;wget.download('https://paddle-github-action.bj.bcebos.com/windows/PR/%PR_ID%/%COMMIT_ID%/Paddle.tar.zst')"
|
||||
zstd -d Paddle.tar.zst && tar -xf Paddle.tar
|
||||
del Paddle.tar Paddle.tar.zst
|
||||
call %ci_scripts%\clean_env.bat
|
||||
|
||||
- name: Config env
|
||||
run: |
|
||||
call %ACTION_DIR%\proxy.bat
|
||||
call %ci_scripts%\config_env.bat
|
||||
|
||||
- name: Build paddle
|
||||
run: |
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
call %ci_scripts%\pre_download.bat
|
||||
call %ACTION_DIR%\proxy.bat
|
||||
call %ci_scripts%\build.bat
|
||||
|
||||
- name: Test whl package
|
||||
run: |
|
||||
call %ci_scripts%\test_whl_package.bat
|
||||
|
||||
- name: Test paddle
|
||||
run: |
|
||||
call %ci_scripts%\test.bat
|
||||
|
||||
- name: Clean up dir
|
||||
if: always()
|
||||
run: |
|
||||
call %ci_scripts%\clean_env.bat
|
||||
if "%WITH_TESTING%"=="ON" (
|
||||
for /F "tokens=1 delims= " %%# in ('tasklist ^| findstr /i test') do taskkill /f /im %%# /t
|
||||
) || ver >nul
|
||||
@@ -0,0 +1,104 @@
|
||||
name: Windows-GPU
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
clone-can-skip:
|
||||
type: string
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
BRANCH: ${{ github.base_ref }}
|
||||
ci_scripts: ${{ github.workspace }}\ci\windows
|
||||
ACTION_DIR: ${{ github.workspace }}\..\..\..
|
||||
WORKSPACE_DIR: ${{ github.workspace }}\..
|
||||
cache_dir: C:\action-cache
|
||||
SCCACHE_ROOT: C:\sccache
|
||||
no_proxy: "bcebos.com,apiin.im.baidu.com,gitee.com,aliyun.com,.baidu.com,.tuna.tsinghua.edu.cn"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
|
||||
jobs:
|
||||
check-bypass:
|
||||
name: Check bypass
|
||||
uses: ./.github/workflows/check-bypass.yml
|
||||
with:
|
||||
workflow-name: "win-openblas"
|
||||
secrets:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-and-test:
|
||||
name: Build and test
|
||||
needs: [check-bypass]
|
||||
if: ${{ needs.check-bypass.outputs.can-skip != 'true' && inputs.clone-can-skip != 'true' }}
|
||||
runs-on:
|
||||
group: win-openblas
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
PADDLE_VERSION: 0.0.0
|
||||
NIGHTLY_MODE: "OFF"
|
||||
WITH_UNITY_BUILD: "ON"
|
||||
WITH_CACHE: "OFF"
|
||||
WITH_TPCACHE: "OFF"
|
||||
WITH_SCCACHE: "ON"
|
||||
WITH_SHARED_PHI: "ON"
|
||||
FLAGS_enable_eager_mode: 1
|
||||
GIT_PR_ID: ${{ github.event.pull_request.number }}
|
||||
WITH_TESTING: "ON"
|
||||
PRECISION_TEST: "OFF"
|
||||
PYTHON_ROOT: C:\Python310
|
||||
CTEST_PARALLEL_LEVEL: 1
|
||||
GENERATOR: "Ninja"
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WITH_MKL: "OFF"
|
||||
WITH_GPU: "OFF"
|
||||
WITH_AVX: "OFF"
|
||||
MSVC_STATIC_CRT: "ON"
|
||||
ON_INFER: "ON"
|
||||
WIN_UNITTEST_LEVEL: 2
|
||||
CUDA_ARCH_NAME: "Auto"
|
||||
steps:
|
||||
- name: Download Paddle and clean env
|
||||
working-directory: ..
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
whoami
|
||||
cd
|
||||
rmdir /s/q %WORKSPACE_DIR%\Paddle
|
||||
python -m pip install wget
|
||||
python -c "import wget;wget.download('https://paddle-github-action.bj.bcebos.com/windows/PR/%PR_ID%/%COMMIT_ID%/Paddle.tar.zst')"
|
||||
zstd -d Paddle.tar.zst && tar -xf Paddle.tar
|
||||
del Paddle.tar Paddle.tar.zst
|
||||
call %ci_scripts%\clean_env.bat
|
||||
|
||||
- name: Config env
|
||||
run: |
|
||||
call %ci_scripts%\config_env.bat
|
||||
|
||||
- name: Build paddle
|
||||
run: |
|
||||
python -m pip install bce-python-sdk==0.8.74
|
||||
call %ci_scripts%\build.bat
|
||||
|
||||
- name: Test whl package
|
||||
run: |
|
||||
call %ci_scripts%\test_whl_package.bat
|
||||
|
||||
- name: Test paddle
|
||||
run: |
|
||||
call %ci_scripts%\test.bat
|
||||
|
||||
- name: Clean up dir
|
||||
if: always()
|
||||
run: |
|
||||
call %ci_scripts%\clean_env.bat
|
||||
if "%WITH_TESTING%"=="ON" (
|
||||
for /F "tokens=1 delims= " %%# in ('tasklist ^| findstr /i test') do taskkill /f /im %%# /t
|
||||
) || ver >nul
|
||||
@@ -0,0 +1,29 @@
|
||||
name: CI-Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [develop, release/**]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event.pull_request.number }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number }}
|
||||
COMMIT_ID: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
jobs:
|
||||
cancel:
|
||||
name: Cancel CI-Build for ${{ github.event.pull_request.number }}
|
||||
runs-on:
|
||||
group: APPROVAL
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
rm -rf * .[^.]*
|
||||
- name: Cancel CI-build
|
||||
run: |
|
||||
exit 0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user