- 图形学
【免费下载链接】skia
Skia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.
导读
本文围绕 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.go:tasks.json的生成器(入口见 gen_tasks.go),真正逻辑在 gen_tasks_logic/gen_tasks_logic.go;cfg.json、jobs.json:生成器的输入配置;tasks.json:最终产物,即仓库当前所有任务与作业的清单(约 7 万行 JSON);recipes.py与recipes/:在 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.json | gen_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.json与jobs.json,结合builder_name_schema等模块展开出每个 Job 对应的完整任务链,并对生成的 DAG 做环检测与孤儿任务检测(这也是--test模式的核心检查项),最终序列化输出tasks.json。
同时,infra_tests.py 是make -C infra/bots test/train背后真正的执行者,它依次运行三类测试:
- Python 单元测试(
unittest discover收集*_test.py); - Recipe 模拟测试(
recipes.py test,train 模式追加train参数); go run gen_tasks.go --test的 DAG 一致性校验。
cfg.json中还可以看到丰富的运行配置项,例如任务池("pool": "Skia")、项目名("project": "skia")、各类结果上传用的 GCS bucket(skia-infra-gm、skia-perf、skia-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声明依赖env、flavor、gold_upload、run、vars等模块,随后按属性开关(images、lotties、resources、skps、svgs)决定安装哪些测试资源并驱动 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 --train或make -C infra/bots train重新训练。
六、Isolate Files:按需传输仓库文件到机器人
Isolate 文件决定了触发 Swarming 任务时,仓库中的哪些部分会被传输到机器人上。Isolate 工具对每个文件做哈希,仅上传新增/变更的文件;机器人维护本地缓存,因此可以只下载自己没有的文件,大幅降低重复传输开销。
这套机制与gen_tasks_logic.go中定义的 CAS 常量一一对应——生成器会为不同任务类型(compile、test、perf、recipes、task-drivers、whole-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.
相关推荐
Skia 自动化测试体系全解:Swarming 任务调度、Try Job 与任务生成机制
Skia 自动化测试体系全解:Swarming 任务调度、Try Job 与任务生成机制 Skia( 当前仓库根目录 https://link.gitcode.
图形学DashSet使用指南:如何利用DashMap构建高性能并发集合
DashSet使用指南:如何利用DashMap构建高性能并发集合 DashSet是基于Rust的高性能并发集合,它是DashMap的轻量级包装,使用 作为值类型
软件架构SeaTunnel DAG 执行模型深度解析:从 LogicalDag 到 PhysicalVertex 的分布式任务编排
SeaTunnel DAG 执行模型深度解析:从 LogicalDag 到 PhysicalVertex 的分布式任务编排 SeaTunnel(Apache S
数据集成ETL大数据批处理流处理变更数据捕获
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考