news 2026/9/23 22:50:19

Apache TVM 持续集成体系全解析:Jenkins 与 GitHub Actions 协同工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache TVM 持续集成体系全解析:Jenkins 与 GitHub Actions 协同工作流

Apache TVM 持续集成体系全解析:Jenkins 与 GitHub Actions 协同工作流

【免费下载链接】tvmOpen deep learning compiler stack for cpu, gpu and specialized accelerators项目地址: https://gitcode.com/gh_mirrors/tvm7/tvm

导读

本篇文章以 Apache TVM 仓库中的 ci/jenkins/README.md 为核心骨架,系统讲解 TVM 如何在每个 Pull Request 与main分支提交上自动执行回归测试:Linux 侧全部由 Jenkins 承担(含 GPU 等加速硬件),Windows/MacOS 及各类 GitHub 自动化由 GitHub Actions 负责。读完本文,你将掌握 TVM 双 CI 平台的分工边界、Jenkinsfile模板的生成与再生成流程、Docker 镜像管理机制,以及ci/jenkinsci/scripts/jenkins目录中配套脚本的实际用途,能够直接在本仓库中定位相关配置并理解其工作原理。

一、TVM CI 总览:为什么需要两套 CI 平台

TVM 在每一个提交(包括所有开放的 Pull Request,以及apache/tvm仓库中的main等分支)上都会运行 CI 作业。这些作业对维持项目健康状态、防止破坏性改动合入至关重要。

从 ci/jenkins/README.md 的定义可以清楚看到两套平台的定位:

平台覆盖范围职责
Jenkins所有基于 Linux 的 CI 回归测试,包括 GPU 等加速硬件的测试承担绝大部分 merge-blocking(合入阻塞)测试
GitHub ActionsWindows 作业、MacOS 作业,以及各种基于 GitHub 的自动化补充 Jenkins 未覆盖的平台,并运行机器人流程

Jenkins 排除了那些针对云上不可用硬件(即无法在公有云环境获得的专用加速设备)的回归测试——这部分测试目前不在 TVM CI 中执行。值得注意的是,README 明确指出:通过 Jenkins 测试与通过剩余的 Windows/Mac 构建之间存在高度相关性,因此 Jenkins 是事实上的主 CI。

二、GitHub Actions:Windows / MacOS 与自动化机器人

GitHub Actions 负责的 Windows 与 MacOS 作业,以及各类 on-GitHub 自动化,均定义在 .github/workflows 目录下。该目录中实际包含以下工作流文件:

  • main.yml:主 CI 工作流,if: ${{ github.repository == 'apache/tvm' }}保证只在官方仓库触发,包含MacOSWindows两个 job。MacOS job 会执行 conda 构建、iOS RPC 构建、全平台最小测试集tests/python/all-platform-minimal-test、Metal 代码生成编译与运行测试;Windows job 则在windows-2019runner 上执行相应的 conda 构建与测试。工作流通过concurrency配置对同一 PR 的连续提交进行取消抢占,节省 CI 资源。
  • cc_bot.yml 与 tag_teams.yml:根据订阅的团队/主题自动 @ 相关人员。
  • tvmbot.yml:允许非 committer 在 CI 通过且获得批准后,通过 PR 评论触发合并(底层调用 github_tvmbot.py)。
  • ping_reviewers.yml:将已 @ 的人员自动添加为 reviewer,并在一周无活动后 ping 长期搁置的 PR(后者目前为 opt-in)。
  • update_last_successful_branch.yml:将最后一个通过 CI 的main提交推送到last-successful分支。
  • nightly_docker_update.yml 与 upload_ci_resource.yml:分别负责每日 Docker 镜像的自动更新与 CI 资源上传。

工作流的运行日志可在 GitHub Actions 页面查看。README 特别提醒:fork 仓库发来的 PR 中,对工作流文件的修改不会在 PR 中生效,需要在 fork 仓库中先自行测试,再把结果链接到 PR 描述中——这是调试 CI 改动时的常见陷阱。

三、Jenkins CI:Linux 主测试平台的架构

TVM 使用 Jenkins 在 branches 目录中的Jenkinsfile模板指定。以 CPU 作业为例,其模板 cpu_jenkinsfile.groovy.j2 展示了完整的流水线结构:

  • Prepare/Sanity Check:在CPU-SMALL-SPOT节点上执行init_git()(检出源码、合并最新 main、更新 submodule),并运行 git_skip_ci.py、git_change_docs.sh、should_run_slow_tests.py 等判断脚本,决定是否跳过 CI、是否仅文档变更、是否运行慢测试。
  • Build:通过 task_config_build_cpu.sh 生成 CMake 配置,再执行cmake_build构建;随后构建 standalone CRT、C++ 测试,并通过 s3.py 将libtvm.solibvta_fsim.socrttestcpptest等产物上传到 S3。
  • Test(分片并行):CPU 测试被拆成integration: CPU(4 个分片)、unittest: CPUfrontend: CPU等多个阶段,各阶段先通过s3.py下载构建产物,再运行 task_python_integration.sh、task_cpp_unittest.sh、task_python_vta_fsim.sh 等测试脚本,测试结束后通过junit指令收集build/pytest-results/*.xml结果。

ci/jenkins/generated目录可以看出,Jenkins 实际执行的流水线覆盖了 12 种平台/场景:armcortexmcpudockergpuhexagoni386lintminimalminimal_cross_isariscvwasm,每种对应一个*_jenkinsfile.groovy生成文件及其.j2模板。

四、Jenkinsfile的生成机制

本目录中的模板文件(*.groovy.j2)用于生成 Jenkins 执行 CI 作业所用的Jenkinsfile。整个机制的核心是 generate.py:

  1. 使用Jinja2模板引擎,加载 ci/jenkins/templates 下的所有*_jenkinsfile.groovy.j2模板;
  2. 从 data.py 导入data字典(包含 Docker 镜像标签、AWS 区域、需要 stash 的构建产物清单),并注入generated_time时间戳;
  3. 渲染结果写入 ci/jenkins/generated 目录(destination = GENERATED_DIR / source.stem);
  4. 通过difflib对比新旧内容,其中 change_type() 会识别仅改动 Docker 镜像名的 diff——这类改动不会更新生成文件头部的时间戳(除非使用--force)。

该脚本内置了防呆机制:生成文件头部带有// Generated at <timestamp>标记,用于确保Jenkinsfile的更新总是基于最新的main重放(rebase);.j2模板中则醒目地标注了"本文件由 generate.py 生成,请勿直接编辑,应修改模板后重新生成"。

重新生成Jenkinsfile的命令

README 给出了标准操作流程:

python3 -mvenv _venv _venv/bin/pip3 install -r ci/jenkins/requirements.txt _venv/bin/python3 ci/jenkins/generate.py

此外 generate.py 还支持两个命令行参数:

  • --force:始终覆盖时间戳,即使改动仅涉及 Docker 镜像名;
  • --check:只校验生成结果与磁盘上现有文件是否一致,不一致时打印 diff 并退出码 1——该模式常用于 CI 中防止有人绕过模板直接手改生成文件。

模板的组织结构

templates目录采用"公共基座 + 平台专属"的复用设计:

  • templates/utils/base.groovy.j2:公共头部,包含ci_lintci_gpuci_cpu等镜像变量、Jenkins UI 参数(<image>_param,用于在 UI 上临时覆盖默认镜像)、docker_run命令、max_time = 180超时、S3 bucket/prefix 配置,以及cancel_previous_build()调用。
  • templates/utils/Prepare.groovy.j2、Build.groovy.j2、Test.groovy.j2:分别封装准备、构建、测试阶段的公共逻辑。
  • templates/utils/macros.j2:定义核心宏,包括sharded_test_step(生成shard_run_<name>_<i>_of_<n>分片测试函数,注入TVM_NUM_SHARDS/TVM_SHARD_INDEX环境变量)、invoke_build(构建阶段,先尝试-SPOT抢占节点,失败则回退到常规节点)、invoke_tests(将全部分片测试函数放入parallel并行执行)、upload_artifacts/download_artifacts(封装 S3 上传下载)、junit_to_s3(测试结果上传 S3 并junit归档)。

数据驱动:Docker 镜像与构建产物

data.py 是流水线的数据源,定义了:

  • Docker 镜像表ci_arm(ARM 平台)、ci_cortexmci_cpuci_gpu(GPU 平台)、ci_hexagonci_i386ci_lintci_minimalci_riscvci_wasm,每个镜像带标签(如tlcpack/ci-cpu:20221013-060115-61c9742ea)与平台标识。该文件还可作为命令行工具使用(python data.py <image_name>),被 docker/dev_common.sh 用于按名查询镜像标签。
  • AWS 信息:默认区域us-west-2、ECR 地址dkr.ecr.us-west-2.amazonaws.com
  • files_to_stash(stash 清单):例如cpptestbuild/cpptest+ ninja 构建文件)、crttestbuild/crttest)、hexagon_apimicrotvm_template_projectsstandalone_crttvm_allvisiblebuild/libtvm_allvisible.so,HIDE_PRIVATE_SYMBOLS=ON 构建产物)、tvm_runtimelibtvm_runtime.so)、tvm_liblibtvm.so+ runtime)、tvm_multilib/tvm_multilib_tsim(含 VTA fsim/tsim 的完整编译产物)。

此外,docker-images.ini 提供了镜像标签的另一份配置清单(含ci_cortexmci_minimalci_riscv等条目),模板注释说明:"这些变量在运行时由 ci/jenkins/docker-images.ini 中的数据设置,更新镜像标签请修改该文件"。配套的 determine_docker_images.py、git_change_docker.sh、should_rebuild_docker.py 则负责判断一次提交是否触及 Docker 配置、是否需要触发镜像重建。

Docker 镜像的升级流程

模板头部注释(见 templates/utils/base.groovy.j2)记录了官方升级 Docker 环境的标准流程(需要 committer 权限):

  1. 提交 PR 升级仓库中的构建脚本;
  2. 构建新的 Docker 镜像;
  3. 以新版本号打标签并推送到二进制缓存;
  4. 在 Jenkinsfile 中更新版本号并提交 PR;
  5. 在该 PR 中修复新镜像版本带来的问题;
  6. 合入 PR,进入新版本;
  7. 将新版本标记为 latest;
  8. 定期在本地 worker 上清理旧版本。

这条流程解释了镜像标签为什么形如tlcpack/ci-cpu:20221013-060115-61c9742ea——时间戳加 git 短哈希,保证可追溯、可回滚。

五、配套支撑脚本:ci/scripts/jenkins

Jenkins 流水线中的 Groovy 代码大量调用 ci/scripts/jenkins 下的 Python/Shell 脚本,理解这些脚本就能读懂流水线的每个步骤:

  • git_skip_ci.py:根据 PR 改动文件判断是否跳过整个 CI(配合 git_skip_ci_globs.py 的 glob 规则);退出码 0 表示跳过。
  • git_change_docs.sh:判断是否仅文档变更(docs-only build),此类 PR 会跳过大部分构建/测试阶段以节省资源。
  • should_run_slow_tests.py:决定是否运行慢速测试,通过环境变量SKIP_SLOW_TESTS传递给测试阶段。
  • check_pr.py:PR 元数据校验,例如标题与 body 不能为空、标题不能以句点结尾等,是质量门禁的一部分。
  • s3.py:流水线产物/测试结果在 S3 桶tvm-jenkins-artifacts-prod下的上传与下载(prefix 为tvm/<branch>/<build_number>)。
  • pytest_ids.py 与 pytest_wrapper.py:pytest 用例 ID 提取与包装,支撑分片测试的用例划分。
  • retry.sh:网络类操作的失败重试封装。
  • open_docker_update_pr.py:与 nightly Docker 镜像自动更新配套,自动为镜像升级打开 PR。

六、CI 基础设施的归属与协作方式

虽然 TVM 的全部测试代码都存放在 apache/tvm 仓库内,但运行这些测试的 CI 基础设施由 TVM 社区捐赠。为了鼓励协作,TVM 的 CI 基础设施配置被存放在一个公开的 GitHub 仓库(tlc-pack/ci)中,社区成员被鼓励贡献改进。README 指出:基础设施的配置与相关文档都在该仓库中维护,这与本仓库内docker/ci/目录中的配置文件形成了"源码在 TVM 仓库、设施配置在基础设施仓库"的职责划分。

七、小结与排查路径速查

围绕本仓库,理解 TVM CI 可以归纳为一条主线:

  1. 平台分工:Jenkins 跑 Linux 全量回归(含 GPU),GitHub Actions 跑 Windows/MacOS 与机器人自动化;
  2. 流水线定义:编辑 ci/jenkins/templates 下的.j2模板 → 运行 generate.py 重新生成 ci/jenkins/generated 下的 Groovy 文件 → Jenkins 按生成文件执行;
  3. 环境数据:镜像标签统一维护在 data.py 与 docker-images.ini,构建产物清单在files_to_stash
  4. 执行细节:构建/测试/产物传输逻辑封装在 ci/scripts/jenkins 与 tests/scripts 下的脚本中,任何 CI 阶段失败,均可沿Jenkinsfile→ 对应task_*.sh/task_*.py的调用链快速定位。

若你要排查一次 CI 失败,推荐的顺序是:先看是哪个平台(Jenkins 还是 Actions)的哪个 stage 失败,再打开对应模板确认该 stage 调用的脚本,最后直接在 tests/scripts 中找到该脚本本地复现。这套"模板生成 + 数据驱动 + 脚本封装"的架构,也是大型开源项目搭建自托管 CI 时值得借鉴的设计范式。

【免费下载链接】tvmOpen deep learning compiler stack for cpu, gpu and specialized accelerators项目地址: https://gitcode.com/gh_mirrors/tvm7/tvm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 22:48:37

Flask绩效管理系统源码解析:40文件分层架构与二次开发实战

简介&#xff1a;这是一套基于Python与Flask框架开发的绩效管理系统设计源码&#xff0c;面向希望学习企业级Web开发实践的学生、开发者&#xff0c;以及需要快速搭建绩效管理平台的中小团队。系统围绕员工绩效考核、项目测试与月度报表等业务场景&#xff0c;将数据访问、业务…

作者头像 李华
网站建设 2026/9/23 22:46:51

ITD分解原理与实战:故障信号诊断如何识别轴承齿轮冲击特征

简介&#xff1a;ITD分解&#xff08;瞬时时间差分&#xff09;是机械故障诊断中常用的信号处理技术&#xff0c;能从复杂的振动或状态信号中分离出携带故障特征的不同分量&#xff0c;广泛用于旋转机械、轴承等设备的早期异常识别。这一MATLAB代码包面向故障诊断与信号处理学习…

作者头像 李华
网站建设 2026/9/23 22:46:13

抖音网页版登录入口在哪?右上角头像扫码登录全解析

1. 从“找不到入口”说起&#xff1a;这个问题的本质是什么“抖音网页版登录入口在哪”——这个问题看起来简单到不值一提&#xff0c;但如果你在搜索引擎里翻几页&#xff0c;会发现问的人远比想象中多。有人是在公司电脑上想摸鱼刷会儿视频&#xff0c;有人是想用大屏看直播更…

作者头像 李华
网站建设 2026/9/23 22:46:10

大型集团基础设施架构蓝图设计:BPIT运营模式与四级分层模型落地指南

简介&#xff1a;这份PPT是埃森哲大型集团管控信息化战略规划项目系列中的蓝图设计方案&#xff0c;聚焦基础设施架构与BPIT运营模式&#xff0c;面向企业信息化规划人员、架构师及集团IT管理者&#xff0c;用于解决多业务系统难集成、难共享、重复建设等管控难题。资源包共1个…

作者头像 李华
网站建设 2026/9/23 22:44:32

无人机巡维保障系统后端:状态机与轨迹数据处理实践

简介&#xff1a;基于Java语言的uav-patrol-backend巡维保障系统后端源码&#xff0c;面向无人机巡维业务的后端开发人员&#xff0c;提供了一套模块化、可扩展的服务端实现&#xff0c;可支撑无人机巡维任务管理、设备状态监控与数据上报等核心服务。项目包含51个文件、共93KB…

作者头像 李华
网站建设 2026/9/23 22:44:19

曼彻斯特与差分曼彻斯特编码:从原理推导到STM32实现

数字信号编码这块内容&#xff0c;我在做嵌入式通信和工业总线的时候踩过不少坑。最早接触曼彻斯特编码&#xff0c;是因为一个STM32项目里需要把传感器数据通过单根信号线传出去&#xff0c;同时还要让接收端能自己恢复时钟——当时试过NRZ编码&#xff0c;结果接收端时钟漂移…

作者头像 李华