CANN Runtime 可选组件分阶段上库与回退实践:从编译单元准备到目标产品隔离
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
本篇指南聚焦 CANN / runtime 仓库中“将某个 Runtime API 可选组件从目标产品中隔离出去”时的分步骤上库与回退方法论。它以三步 PR(自适应准备 → 工厂解耦 → 目标产品隔离)为核心骨架,规定每一步的稳定目标、包含项与不包含项、验收标准、独立回退方式以及聚合分支的正确用法,并结合仓库内 ApiImplMbuf / arch5162 的真实实现(如 api_impl_mbuf_stub.cc、arch5162.cmake)给出源码级佐证。读者读完后,将掌握在不破坏支持产品行为、不丢失公开 ABI 的前提下,把“不支持某组件”落实为“源文件不进入目标产品”的完整可验证实施路径。
1. 三步上库的整体设计与步骤关系
把“裁剪某个可选组件”从一次性大改拆成可独立验证、可独立回退的小步,是本次上库策略的核心。默认采用以下三步,其中第一步是否产生代码 PR 由模块特性决定,后两步为基本固定的通用模式:
| 步骤 | 稳定目标 | 是否固定实现 |
|---|---|---|
| 1. 自适应准备 | 形成可独立裁剪的编译单元 | 否;可拆文件、提公共能力、收敛注册依赖或直接跳过 |
| 2. 工厂解耦 | 公共 Runtime 不感知具体实现,所有平台行为不变 | 基本固定 |
| 3. 产品隔离 | 目标产品停编译组件,ABI 桩返回不支持 | 基本固定 |
依赖关系必须由依赖图证明,不能凭感觉假设。例如 Mbuf 案例中,第一步(PR4264,拆分 driver 编译单元)与第二步(PR4265,Runtime 工厂解耦)可以独立合入,但这只是该模块被验证过的结论,不是其他模块的默认结论。第三步始终依赖第二步,以及第一步中确有必要的准备。
从仓库现状看,Mbuf 组件已经走完了这条路径:api_impl_mbuf_stub.cc 提供了目标产品侧的IsImplMbufSupported() == false、CreateImplMbufAndGet() == nullptr与DestroyImplMbuf(),而支持产品仍走 api_c_mbuf.cc →ApiMbuf::Instance()→ 具体实现的原始链路,正是“分步骤隔离”落地后的典型形态。
2. 第一步 PR:自适应准备
第一步只解决一个问题:让组件形成可以单独加入或移除的编译单元。
- 包含:模块特有的源文件拆分或依赖收敛,以及所有产品/UT CMake 同步。
- 不包含:Runtime 工厂重构、目标产品能力关闭、ABI 桩。
- 验收:所有产品能力和调用链不变,独立 CI 通过。
- 回退:单独回退该 PR,即可恢复原编译单元布局。
若无需改动,则不创建空 PR,改为在方案中提供“可直接移除专属文件”的证据(例如专属源文件已存在、依赖已闭合、target 可单独移除)。
Mbuf 案例中,该步把NpuDriver::Mbuf*方法从混合职责的npu_driver_queue.cc原样移动到npu_driver_mbuf.cc(仓库中该文件现位于 src/runtime/driver/npu_driver_mbuf.cc),并让所有原正式/UT target 同时编译新文件。该步骤不修改 C API 路由,不修改 Runtime 创建方式,目标产品此时仍编译并支持 Mbuf。Mbuf 建议的分支和提交为:
refactor/api-mbuf-driver-split refactor: split NpuDriver Mbuf implementation其他模块按实际障碍命名,不复用driver-split标题——第一步的具体动作必须按模块特性决定,不能机械复制 Mbuf。
3. 第二步 PR:工厂解耦
第二步是通用稳定模式,目标是让公共 Runtime 只依赖抽象契约,不再感知具体实现类型。
- 包含:能力入口、抽象工厂、具体分配/日志下沉、Runtime 抽象调用和失败 UT。
- 不包含:任何产品返回不支持、CMake 删除组件源文件、C API 桩。
- 验收:所有原支持产品继续创建组件,普通与目标产品编译/UT/链接通过。
- 回退:单独恢复公共 Runtime 直接创建具体实现的旧逻辑。
仓库中ApiImplMbuf解耦后的工厂契约清晰可见(api_impl_mbuf_stub.cc):
bool IsImplMbufSupported() { return false; } ApiMbuf* CreateImplMbufAndGet() { return nullptr; } void DestroyImplMbuf(ApiMbuf*& apiImplMbuf) { apiImplMbuf = nullptr; }与之对应,公共入口 api_c_mbuf.cc 只通过ApiMbuf::Instance()拿到抽象实例,不再直接new/sizeof具体类型;同时通过COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT)将驱动侧的不支持错误码统一映射为对外 ABI 错误码。这一步是行为保持型重构:本阶段所有平台仍返回支持并创建原实现,避免把结构重构与能力变化放在同一 PR。
建议分支和提交:
refactor/api-<component>-runtime-decouple refactor: decouple Runtime from ApiImpl<Component>4. 第三步 PR:目标产品隔离
第三步真正把“目标产品不支持该组件”落实为源文件不进入目标产品。它必须基于前置步骤实际合入后的最新origin/master重新执行。
- 包含:目标平台能力关闭、目标 CMake 删除源文件、公开 C API 桩、平台 UT 和设计文档更新。
- 不包含:支持产品行为调整、无关模块裁剪、第一步/第二步已合入内容。
- 验收:目标对象文件缺失、ABI 集合一致、not-support UT、支持产品 UT、链接和全 CI 通过。
- 回退:优先单独回退本 PR,即可恢复目标产品组件能力;前两步可保留。
在 arch5162(不使用 Mbuf 的目标平台)构建配置 arch5162.cmake 中可以看到隔离后的形态:api_c_mbuf.cc作为17 个 stub 的 weak real provider编译进目标库,api_impl_mbuf_stub.cc(而非真实实现api_impl_mbuf.cc)进入libruntime_api_impl_src_files,同时借助arch5162_unsupported_runtime_api.def(src/runtime/cmake/arch5162_unsupported_runtime_api.def)与generate_runtime_api_stubs生成统一的 API 桩;目标库链接选项保持-Wl,--no-undefined与-Wl,--gc-sections,并用-Wl,-Bsymbolic保证桩语义不被意外覆盖。支持产品则继续走原链路,不经过平台不支持桩。
建议分支和提交:
refactor/<target>-api-<component>-isolation refactor: isolate Api<Component> from <target>5. 聚合分支:验证手段,不是交付方式
前置 PR 尚未合入时,可维护一个包含完整三步的聚合分支,用于证明最终编译、行为、ABI 和体积收益。但聚合分支不能替代分步骤 PR,其正确用法如下:
- 先判断第一步与第二步是否存在技术依赖。
- 可独立时,两者分别基于
master验证和提交。 - 有依赖时,第二步必须等待第一步实际合入,再基于最新
master提交。 - 前两步实际合入后,将第三步重放到最新
master。 - 确认第三步 diff 只剩目标平台差异、桩、UT 和必要文档,再运行完整 CI。
不要把尚未合入的前置提交永久保留在第三步 PR 中并宣称已完成拆分。第三步合入前应重放,使其最终 diff 只保留目标平台差异、ABI 桩、UT 和文档。
6. 冲突处理与回退
每次前置 PR 合入后,后续步骤需要与主线保持同步,推荐流程:
- 获取最新
origin/master。 - 在隔离 worktree 中重放后续单提交。
- 按 hunk 解决 CMake、平台 API 和 Runtime 生命周期冲突。
- 重新检查 diff 边界和单提交历史。
- 完整重跑本地验证和线上 CI。
故障回退顺序通常为:第三步 → 第二步 → 第一步。若第一步与第二步经证明独立,则只回退引入问题的步骤,不做捆绑回退。每一步都应支持“单独回退该 PR 即恢复原状”,这是分步上库可被接受的前提。
7. PR 描述与上库纪律
按仓库当前模板(.gitcode/PULL_REQUEST_TEMPLATE.zh-CN.md)填写 PR,并至少说明:
- 本步骤解决的单一问题及不包含项;
- 与前后步骤的技术依赖和推荐合入顺序;
- 支持产品行为等价、目标产品不支持语义;
- ABI、对象缺失、链接、大小和 UT 证据;
- 实际本地命令和线上流水线 ID;
- 独立回退方式。
代码变化后立即更新线上 PR 描述并回读确认。CI 失败修复后,替换过期验证结论,不保留“计划通过”式表述——只有实际结束且目标任务成功的流水线才能写成通过,警告、跳过和不可读日志要单独记录。推送和创建/更新 PR 前,读取仓库gitcode-prSkill 与 .gitcode/PULL_REQUEST_TEMPLATE.zh-CN.md,并且只在用户明确授权后执行线上写操作。
8. 配套参考:方法与验证矩阵
本指南是runtime-api-component-isolationSkill 的提交规范部分,与以下仓库文档配套使用,可获取更完整的实施细节:
- method.md:建立调用链、编译单元和产品矩阵,判断组件是否适合隔离,以及第一/二/三步的设计边界。
- mbuf-case.md:PR4264 / PR4265 / PR4254 验证出的 Mbuf 完整案例,以及“可迁移”与“不可机械复用”的假设清单。
- risk-and-validation.md:风险矩阵与验证矩阵,覆盖 ABI、链接、CMake、生命周期、静态副作用、体积、覆盖率与回退等 12 个风险域,并给出
nm -D、ldd -r、runtime.cc.o.d依赖检查等常用证据命令。
这三份文档与本指南共同构成一套“分析 → 实施 → 验证 → 分步上库与回退”的完整闭环,适用于需要把ApiXxx/ApiImplXxx从特定芯片或构建 target 中编译隔离出去的任何 Runtime 可选组件。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考