Skia CI 基础设施深度解析:从任务 DAG 生成到 Swarming 执行与 Recipe 自动化
2026/9/23 22:01:06 网站建设 项目流程
  • 图形学

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.

项目地址:https://gitcode.com/gh_mirrors/ski/skia
点击查看免费下载

导读

本文围绕 Skia 仓库的 infra/bots 目录 展开,系统讲解 Skia 如何借助 Swarming、Recipe 与任务 DAG 实现"每个 commit 自动跑 CI"的基础设施链路。读完本文,你将掌握任务(Task)与作业(Job)的关系、tasks.json的生成机制、如何用sk try触发 tryjob、如何本地运行与训练 Recipe,以及 Assets、Isolate、CT 等辅助模块的职责。

一、infra/bots 目录概览:一套以"任务"为中心的 CI 骨架

infra/bots是 Skia 持续集成基础设施的核心目录,它并不包含图形渲染代码,而是定义了"仓库里每个提交都会运行哪些自动化工作"的完整描述。目录核心组成包括:

  • gen_tasks.gotasks.json的生成器(入口见 gen_tasks.go),真正逻辑在 gen_tasks_logic/gen_tasks_logic.go;
  • cfg.jsonjobs.json:生成器的输入配置;
  • tasks.json:最终产物,即仓库当前所有任务与作业的清单(约 7 万行 JSON);
  • recipes.pyrecipes/:在 Swarming 任务内执行具体工作的脚本框架;
  • recipe_modules/:供 Recipe 复用的共享模块;
  • assets/:机器人运行所需的版本化资产与配套脚本;
  • tools/CT目录:基础设施辅助工具与 Cluster Telemetry 支持。

从源码结构看,这套体系把"定义 CI"与"执行 CI"分离:开发者只编辑输入文件,再由生成器产出机器可读的tasks.json交给调度器。

二、Tasks 与 Jobs:任务 DAG 的两级抽象

原文档明确指出,本目录中的文件定义了一个任务 DAG,在每次 Skia commit 时运行:

  • Task(任务):一个小的、自包含的执行单元,通过 Swarming 在机器池中的某台机器上运行。任务之间可以串联成链,例如"一个任务编译测试二进制、另一个任务真正运行它们"。
  • Job(作业):一组相关任务的集合,用于刻画 DAG 的某个子区块,例如作为 try job 使用。每个 Job 都是 DAG 的一个入口点。

从 tasks.json 的生成结果可以印证这一设计——文件顶层包含"jobs"字段,每个 Job 以任务名为键,映射到自己的任务列表;而任务之间通过依赖关系构成 DAG。例如典型的构建作业Build-*与测试作业Test-*、性能作业Perf-*之间,就是"先编译、后运行"的链式依赖。

任务命名即元数据

Skia 的任务名本身携带丰富的维度信息,例如Test-Mac14-Clang-MacMini9.1-GPU-AppleM1-arm64-Debug-All,依次编码了:测试类型、操作系统(Mac14)、编译器(Clang)、机器型号(MacMini9.1)、渲染后端(GPU-AppleM1)、CPU 架构(arm64)、构建类型(Debug)以及测试范围(All)。这种"名字即配置"的约定由 recipe_modules/builder_name_schema 模块负责解析——Recipe 运行时从任务名推导出期望的行为,而无需额外传递大量参数。

三、tasks.json 的生成机制:改配置、跑生成器、再提交

tasks.json是任务的权威清单,但它永远不要手工编辑,而必须通过gen_tasks.go与下列输入文件生成:

输入文件职责
cfg.jsongen_tasks.go的基础配置信息
jobs.json全部待运行 Job 的清单,增删 bot 时编辑此文件

生成与校验命令

无论修改了gen_tasks.go、上述 JSON 文件,还是修改了 assets,都需要重新生成tasks.json

$ go run infra/bots/gen_tasks.go

或使用封装的 Makefile 目标:

$ make -C infra/bots train

生成器还提供测试模式,执行一致性检查并确认tasks.json未被意外改动(防止手工编辑混入):

$ go run infra/bots/gen_tasks.go --test
$ make -C infra/bots test

从源码看生成器做了什么

gen_tasks.go 本身只有十余行,真正的生成逻辑位于 gen_tasks_logic/gen_tasks_logic.go:它读取cfg.jsonjobs.json,结合builder_name_schema等模块展开出每个 Job 对应的完整任务链,并对生成的 DAG 做环检测与孤儿任务检测(这也是--test模式的核心检查项),最终序列化输出tasks.json

同时,infra_tests.py 是make -C infra/bots test/train背后真正的执行者,它依次运行三类测试:

  1. Python 单元测试(unittest discover收集*_test.py);
  2. Recipe 模拟测试(recipes.py test,train 模式追加train参数);
  3. go run gen_tasks.go --test的 DAG 一致性校验。

cfg.json中还可以看到丰富的运行配置项,例如任务池("pool": "Skia")、项目名("project": "skia")、各类结果上传用的 GCS bucket(skia-infra-gmskia-perfskia-coverage)、金像图哈希地址,以及no_upload列表(ASAN、MSAN、TSAN、Coverage 等配置的任务不上传结果)、按用途区分的多个 service account。而 gen_tasks_logic.go 头部则定义了各平台默认操作系统、机器规格(小机n1-highmem-2双核、中机n1-standard-1616 核、大机n1-highcpu-6464 核)以及不同平台上的 Bazel 缓存目录等常量,可见 DAG 生成时会根据 Job 名字段自动挑选 OS 与机器类型。

四、新增 Job 后如何提前验证:sk try 与 tryjob

新增一个 Job 后,你通常会想在落地前先跑一次看看能否成功。但要注意:由代码改动生成的 Gerrit CL 不会自动运行新 Job,它也不会立刻出现在 Gerrit UI 的可选 tryjob 列表中。

此时需要借助 SK CLI 工具。如果本地还没有该工具,先从 Skia 目录获取:

$ ./bin/fetch-sk

触发 tryjob 前必须先登录 LUCI 认证:

$ luci-auth login

随后即可用sk try以本次改动为内容发起指定 Job:

$ ./bin/sk try [name of job]

例如要运行Test-Mac14-Clang-MacMini9.1-GPU-AppleM1-arm64-Debug-All

$ ./bin/sk try Test-Mac14-Clang-MacMini9.1-GPU-AppleM1-arm64-Debug-All

执行后,该改动对应的 Gerrit review 页面就会展示该 Job 的状态,方便在合入前完成验证。

五、Recipes:Swarming 任务内的执行框架

Recipes 是 Skia 基础设施在 Swarming 任务内部执行工作的框架,主要元素如下:

元素说明
recipes.py运行与测试 Recipe 的入口脚本
recipes/每类任务的入口点,例如编译或运行测试
recipe_modules/被多个 Recipe 复用的共享模块
.recipe_deps/跨仓库依赖的同步目录,recipes.py会自动把依赖同步进来

本地运行一条 Recipe

recipes/README.md 给出了本地执行方法(<workdir>是本地工作目录,recipe 名不带.py后缀):

$ python infra/bots/recipes.py run --workdir=/tmp/<workdir> <recipe name without .py> key1=value1 key2=value2 ...

每条 Recipe 可能有自己的必需属性,需要在命令行中以key=value形式传入。

模拟测试与训练(re-train)

修改 Recipe 后,一般需要重新训练模拟测试,让期望文件(.expected/下的 JSON)反映最新的步骤序列:

$ python infra/bots/recipes.py test train

或:

$ cd infra/bots; make train

这些测试会为每条 Recipe 生成期望文件,展示"给定一组输入时应该执行哪些步骤"。改动 Recipe 时要特别留意这些文件的 diff,确保变更产生了预期效果。以 recipes/test.py 为例,其DEPS声明依赖envflavorgold_uploadrunvars等模块,随后按属性开关(imageslottiesresourcesskpssvgs)决定安装哪些测试资源并驱动 DM 测试——这正是"Recipe 作为入口点、模块承担共享逻辑"的典型结构。

共享模块清单

recipe_modules/README.md 列出了各模块职责:

  • builder_name_schema:从任务(旧称 builder)名推导期望行为;
  • core:大多数 Recipe 的起点,负责 setup 与 sync 步骤;
  • ct:Cluster Telemetry 共享工具;
  • flavor:允许调用方指定高层命令,由具体 flavor 模块处理平台细节;
  • infra:共享基础设施工具;
  • run:运行命令的工具;
  • swarming:运行 Swarming 任务的工具;
  • vars:Skia Recipes/模块使用的公共全局变量。

每个模块通常包含:api.py(模块主体)、__init__.py(声明DEPS依赖)、example.py(演示用法并承载覆盖测试)。修改模块后同样需要python infra/bots/infra_tests.py --trainmake -C infra/bots train重新训练。

六、Isolate Files:按需传输仓库文件到机器人

Isolate 文件决定了触发 Swarming 任务时,仓库中的哪些部分会被传输到机器人上。Isolate 工具对每个文件做哈希,仅上传新增/变更的文件;机器人维护本地缓存,因此可以只下载自己没有的文件,大幅降低重复传输开销。

这套机制与gen_tasks_logic.go中定义的 CAS 常量一一对应——生成器会为不同任务类型(compiletestperfrecipestask-driverswhole-repo等)指定不同的 CAS 隔离目标,从而精确控制每个任务携带的输入集。

七、Assets:版本化的机器人资产

assets/目录管理基础设施使用的各类工件,并附带创建/上传/下载它们的脚本。任何机器人用到的资产发生变化时,都必须重新运行gen_tasks.go,使新版本号进入tasks.json。仓库中可以看到大量真实资产目录,如android_ndk_linux/clang_linux/go/mesa_intel_driver_linux/skp/等,每个目录遵循统一结构。

资产目录结构

按 assets/README.md,每个资产子目录包含:

  • VERSION:资产的当前版本号;
  • (可选)create.py:创建资产的脚本,由用户实现,被sk asset upload调用;
  • (可选)create_and_upload.py:用户实现的便捷脚本,封装sk asset upload

资产按版本号命名存储在 Google Storage 中。

资产操作示例

以下命令需要 google.com 账号并已执行gcloud auth application-default login完成认证。

新增一个资产并上传初始版本:

$ sk asset add myasset Do you want to add a creation script for this asset? (y/n): n $ sk asset upload --in ${MY_ASSET_LOCATION} myasset $ git commit

新增一个可自动化创建的资产:

$ sk asset add myasset Do you want to add a creation script for this asset? (y/n): y Created infra/bots/assets/myasset/create.py; you will need to add implementation before uploading the asset. $ vi infra/bots/assets/myasset/create.py (implement the create_asset function) $ sk asset upload myasset $ git commit

更新一个资产:

(update the create.py script) $ sk asset upload myasset (假设上一条命令已更新 infra/bots/assets/myasset/VERSION, 按 infra/bots/README 重新生成 tasks.json:) $ make -C infra/bots train $ git commit

八、Tools 与 CT

  • Tools:目录内还有各类基础设施相关工具(例如 isolate 与 CIPD 二进制),服务于整体流水线。
  • CT(Cluster Telemetry):提供在 Cluster Telemetry 中运行 Skia 任务的辅助脚本,用于在大量真实网页样本上开展大规模测试与性能数据采集。

结语

Skia 的 CI 基础设施以"输入文件 → 生成器 →tasks.json→ Swarming 调度 → Recipe 执行"为主链路:开发者通过编辑 jobs.json 与 cfg.json 声明 CI 意图,由 gen_tasks.go 生成可校验的任务 DAG;任务在 Swarming 池内由 Recipe 驱动执行,Isolate 与 Assets 分别解决文件传输与资产版本化问题。理解这条链路后,无论是新增一个 Job、修改一条 Recipe,还是更新一个资产,都能遵循"改输入 → 跑生成器 → 检查 diff → 提交"的规范流程,安全地演进 Skia 的自动化测试体系。

  • 图形学

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.

项目地址:https://gitcode.com/gh_mirrors/ski/skia
点击查看免费下载

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询