首页
/ Flutter 基准性能看板(Dashboards)使用指南:在 Skia Perf 中检索与解读框架与引擎基准测试数据

Flutter 基准性能看板(Dashboards)使用指南:在 Skia Perf 中检索与解读框架与引擎基准测试数据

2026-09-06 18:17:58作者:钟日瑜

Flutter 项目在 CI 与真机 DeviceLab 上持续运行大量性能基准测试(benchmark),并将结果汇总到性能看板中供开发者追踪回归与验证优化。本文以仓库内 Dashboards.md 为骨架,完整讲解 Flutter 看板体系的总览入口、如何使用两份 Skia Performance 数据源精确检索某一基准测试的历史曲线,并逐个剖析数据集参数(sub_result、branch、config、originId、test、unit)的真实含义;最后结合 devicelab 的源码,揭示"测试结果 JSON 中的每个 key 如何变成 Skia Perf 中的一个 sub_result"这条完整数据链路。读完本文,你将能够熟练定位任意框架/引擎基准的走势、理解看板上每个字段的来源,并能在仓库中追溯相关数据的生成与上传代码。

一、Flutter 看板体系总览:从哪个入口开始

Flutter 工程效能(EngProd)团队将各种 CI、构建、测试状态类仪表盘汇总在一个索引页中,总入口为 https://flutter-dashboard.appspot.com/。该入口聚合了多种用途的子看板,常见的一类就是本文后续重点讲解的 Flutter DeviceLab 构建/任务状态看板(路径形如 /#/build),它展示了真机任务(tasks)在 CI 上的最新状态、通过率、logs 链接与构建产物。这些任务即 devicelab 中运行的真机测试,也被称为"tasks",相关索引文档统一收录于 docs/infra/README.md(Dashboards、Autorollers、Flutter-Framework-Gardener-Rotation 等团队文档在此均可找到入口)。

理解这个总览入口很有必要,因为后面要用的"数据文件(timeline)下载"、"某次提交的构建页"等能力都挂在 /#/build 视图上,而性能曲线则存放在另一套独立的 Skia Perf 系统中。

二、Skia Performance Dashboard:框架与引擎两份数据源

Skia Perf 是负责存储与绘制性能时间序列的可视化系统。Flutter 为其提供两类数据来源,对应两个彼此独立的数据集:

数据源 覆盖范围 数据来源
https://flutter-flutter-perf.skia.org/e/ 由运行 flutter/flutter(框架仓库)测试得出的基准 框架仓库的 devicelab / CI 基准测试任务
https://flutter-engine-perf.skia.org/e/ 由 flutter/engine(引擎仓库)测试得出的基准 引擎仓库的基准测试任务

因此,在查询之前应当先判断目标基准测试归属于框架侧还是引擎侧。例如 flutter_gallery__transition_perf 这类基于 dev/benchmarks/macrobenchmarks 的 e2e 性能任务属于框架仓库数据,应在 flutter-flutter-perf 中检索;而引擎源码树内的纯引擎 benchmark(见 engine/src/flutter/benchmarking 等目录)则上报到 flutter-engine-perf。

三、逐条查询某个具体基准测试:完整操作步骤

每份数据集(dataset)本质上是一组"日期/数值"对,并关联一组参数,这些参数包括被测分支(branch)、基准测试名("test")、具体指标值名("sub_result")等。当你想查看某条特定指标随时间的变化曲线时,按下列步骤在 Skia Perf 中组合筛选条件:

  1. 在页面上点击 Query
  2. 弹出对话框,此时 "Filter" 文本输入框处于聚焦状态。在框内输入你记忆中基准测试名称的片段(用于模糊过滤候选列表)。
  3. 在列表框中点击 "test" 项,界面会出现第二个列表框。
  4. 从第二个列表框中选择你关心的那条具体测试。
  5. 重新聚焦 "Filter" 文本框,输入你关心的具体数据点名称(即 sub_result 名称片段)。
  6. 点击列表框中的 "sub_result" 项。
  7. 选择你关心的具体 sub_result。
  8. 点击 "Time Range",再点击 "Date Range"
  9. 点击 "Begin" 文本框旁的日历图标来选择开始日期(不要直接键入日期,直接输入会触发已知 bug,导致范围不生效)。
  10. 选择你关心的开始日期。
  11. 点击 "Plot" 绘制曲线。

绘制完成后,可以使用键盘上的 WASD 键来平移 X 轴(时间轴),便于查看曲线在某一区间的细节走势。这一套筛选流程的实质,就是"先锁定 test → 再锁定 sub_result → 再锁定时间范围",后面讲到的数据集参数会帮助你理解为什么筛选层级如此组织。

四、数据集参数详解:sub_result / branch / config / originId / test / unit

一份数据集的全部参数如下表所示,其中大部分来自每次任务上报指标时附带的一组"标签(tags)":

参数 含义与取值说明
sub_result 该测试提供的具体数据流名称。测试可在一个 JSON map 中产出多个数据点,map 中的每一个 key 都会成为 Skia Perf 系统中的一个 sub_result
branch 被测分支,即该次运行所在的 git 分支
config 固定为 "default"
originId 固定为 "devicelab";只有从旧数据库迁移过来的历史数据才标记为 "legacy-flutter"
test 执行采集数据的测试任务的名称
unit 理论上为数据采集时的单位(因此每个 sub_result 只应关联一种单位);实际上该参数经常不准确

几个易误解点需要特别说明:

  • sub_resulttest 是两层概念。一个 test(如 complex_layout_scroll_perf)在一次运行中会产出多个数值指标(如 average_frame_build_time_millis90th_percentile_frame_build_time_millis),每个指标各自是一条独立的曲线(一个 sub_result)。所以查询时要先选中 test,再从中挑选 sub_result。
  • unit 参数仅供参考。按官方文档原话,它"在实践中经常不正确"(in practice this parameter is often incorrect),因此判断指标含义时请以测试代码中该 key 的实际定义为准,不要盲信 unit 字段显示的数值单位。
  • originId 用于区分新旧两套数据管道。凡是历史从旧数据库迁移而来的数据都被标记为 legacy-flutter,其余新采集数据均为 devicelab,可用于在查询时排除或对比历史遗留数据。

五、从源码看参数如何产生:JSON 结果如何变成 sub_result

文档中"每个 key 成为一个 sub_result"的机制,可以在仓库源码中得到直接印证。这条链路分为三步:任务产出数据 → 结果序列化上报 → Cocoon/Skia Perf 解析为带标签的数据点。

第一步:任务以 JSON map 形式汇报成功结果。 task_result.dartTaskResult.success(data, benchmarkScoreKeys: ...) 接受一个 Map<String, dynamic>? data,其中的 benchmarkScoreKeys 声明"data 中哪些 key 是会上报到 Cocoon 的分数",且构造时会逐一校验:key 必须真实存在于 data 中,且对应值必须是 num 类型,否则直接抛错。也就是说,最终会成为 sub_result 的每一个 key 在任务端就已受严格类型约束。

第二步:基准任务把运行时采集的指标写入该 map。 例如 perf_tests.dart 中的某个 e2e 性能任务,会把 janky_countaverage_abs_jerkdropped_frame_count 等指标连同后缀(如 _with_resampler_90Hz)写入 result map,最后以 TaskResult.success(result, benchmarkScoreKeys: result.keys.toList()) 返回——data 中每个 key 即刻成为待上报的候选 sub_result。devicelab 中几乎每个性能任务都遵循同一模式(如 gallery.dartweb_benchmarks.dart 等均调用 TaskResult.success(...) 并显式给出 benchmarkScoreKeys)。

第三步:CI 把结果文件转换为 Skia Perf 指标点。 upload_metrics.dart 定义了 upload-metrics 命令,接收 --results-file--commit-time--task-name--benchmark-tags 四个参数。真正负责转换的是 metrics_center.dart 中的 parse(),其典型输入形如:

{
  "CommitBranch": "master",
  "CommitSha": "abc",
  "BuilderName": "test",
  "ResultData": {
    "average_frame_build_time_millis": 0.4550425531914895,
    "90th_percentile_frame_build_time_millis": 0.473
  },
  "BenchmarkScoreKeys": [
    "average_frame_build_time_millis",
    "90th_percentile_frame_build_time_millis"
  ]
}

parse()BenchmarkScoreKeys 中的每个 key 生成一个 MetricPoint,并附带一组与本文第四节的参数一一对应的标签(见 metrics_center.dart):

  • kGithubRepoKey + kGitRevisionKey:标识仓库与提交哈希;
  • branch:取 resultsJson['CommitBranch'],即 Skia Perf 中的 branch 参数;
  • kNameKey(值取 taskName):即 Skia Perf 中的 test 参数;
  • kSubResultKey(值取当前 scoreKey):即 Skia Perf 中的 sub_result 参数。

额外的一组 benchmarkTags(如 archdevice_typehost_type 等,见 metrics_center.dart 注释示例)会被合并进标签,用来在前端进一步细分"同一任务在不同机型/架构/宿主上的运行结果"。由此可以清楚看到:文档第四节的 testsub_resultbranch 三个参数,正是上述 tags 在看板前端的直接呈现。

MetricPoint 随后由 upload() 批量写入 GCS 桶(见 metrics_center.dart),Skia Perf 会抓取该目录下的全部文件,且对重复条目具有鲁棒性。文件命名按 taskName 拼上 arch/host_type/device_type 生成,例如 complex_layout_scroll_perf__timeline_summary_values.json(见 metricFileName),同一 task 在不同平台上运行也会落到不同文件名,避免相互覆盖。

六、配套实战:从构建看板找到某个基准的 timeline 数据

性能曲线看板解决"看趋势",而定位某一次具体提交的原始 trace 则需要回到构建看板。官方配套文档 How-to-download-a-timeline-from-a-benchmark.md 给出了在 flutter-dashboard.appspot.com/#/build 上提取某基准单次运行原始数据的流程:

  1. 在右上角齿轮设置中按 "Task Name" 搜索你关心的基准任务;
  2. 点击列表列头的相关图标;
  3. 点击你关心的提交对应的 build 链接,进入构建详情页;
  4. 展开该构建的 "log links" 步骤;
  5. 下载其中的 "timeline.json" 文件。

该 timeline.json 即该次运行采集到的完整时间线 trace,是离线做逐帧分析、与本地复现结果做 diff 的重要素材。若需本地复现某个失败的 devicelab 基准,可按 devicelab/README.mdReproducing broken builds locally 一节的说明,git checkout 对应版本后用 bin/run.dart -t <task名>(如 -t flutter_gallery__transition_perf)本地运行同款任务。

七、使用注意事项与实用提示汇总

结合 Dashboards.md 与仓库实际,汇总如下几条易踩坑点:

  • 日期选择务必使用日历控件:在 "Begin" 文本框直接键入日期会触发已知 bug,导致 Date Range 不生效,应点击旁边的日历图标选择。
  • 曲线平移用键盘:Skia Perf 图表支持用 W、A、S、D 键平移 X 轴,比反复拖拽时间轴更精确。
  • unit 字段不可全信:它经常与实际不符,判断指标物理含义请回到产出该数据的测试源码,以 TaskResult.success 的 data key 定义为准。
  • 区分框架/引擎两份数据源:框架仓库基准查 flutter-flutter-perf.skia.org,引擎仓库基准查 flutter-engine-perf.skia.org,二者的 devicelab/CI 任务归属不同。
  • originId 提示数据新旧:标记为 legacy-flutter 的是旧数据库迁移而来的历史数据,与当前 devicelab 管道产生的数据在口径上可能不完全一致,做长周期对比时需留意。
  • 新基准上报的前置条件:若你在 devicelab 中新增性能任务并希望其指标进入看板,须通过 TaskResult.success(data, benchmarkScoreKeys: [...]) 显式声明待上报 key(且值必须为 num),再由 CI 调用 upload-metrics 命令上传,详见 task_result.dartupload_metrics.dart

总之,Flutter 性能看板是一个"devicelab 任务采集指标 → JSON 结果上传 Cocoon/Skia Perf → 前端以 test/sub_result/时间范围组织查询"的完整链路。掌握本文的查询操作与参数语义,再结合 metrics_center.dart 等源码,你既能熟练检索任意基准曲线,也能理解每个数据点背后在仓库中的真实来源,从而更可靠地定位性能回归。

登录后查看全文
热门项目推荐
相关项目推荐