news 2026/9/8 16:55:20

ClickHouse performance.ci API 参考:基于 REST 接口与 Dashboard 的 PR 性能回归分析指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse performance.ci API 参考:基于 REST 接口与 Dashboard 的 PR 性能回归分析指南

ClickHouse performance.ci API 参考:基于 REST 接口与 Dashboard 的 PR 性能回归分析指南

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

在 ClickHouse 开源仓库的日常开发中,评估一个 PR 是否引入性能回归,需要回答一个核心问题:这个性能结果是真实的、还是噪声/偶发、抑或是 master 历史上已知的波动?ci-api.md 正是为回答该问题而编写的performance.ciAPI 与 Dashboard 操作参考——它系统性地覆盖了 Run 发现、Run 概览、置信度、趋势/历史、覆盖率/PR 交集、火焰图、master 状态统计以及 CI 产物兜底等全部数据通道。阅读完本文,你将掌握以performance.ci.clickhouse.com/api/v1为基址的完整 HTTP 调用模式,并能结合仓库内的辅助脚本 perf_api.py 与判定规则 verdict-rules.md,对任意 PR 的性能结果给出有据可查的结论。

数据源优先级:先看 Dashboard/API,再看历史与产物

该参考文档是 perf-comparison 技能(SKILL.md)的组成部分。技能层面对数据源规定了严格的优先级,理解这一点才能正确使用本文的各个 API:

  1. performance.ci API/Dashboard 优先:用于当前 PR 的 Run 列表、变更行清单(changed-row inventory)、置信度、查询详情、趋势/历史图、覆盖率交集与 flamegraph-diff。
  2. ClickHouse Play(default.checks表):当需要对每一行变更统计"过去 30 天 master 上同样测试/查询出现slower/faster/unstable的次数"时使用。
  3. CI 产物/日志:仅在 Dashboard/API 无法提供根因数据时兜底,例如 server 日志、raw trace、raw ProfileEvents TSV、精确二进制版本/build ID。
  4. 本地perf.py:仅在显式提供 old/new 二进制并做本地验证时使用,且必须声明"不等价于 CI"。

这种"证据阶梯"(evidence ladder)的设计保证了每个结论都建立在最可靠的数据源上,raw 产物永远只是 artifact fallback evidence,不能反过来覆盖 Dashboard 的分类结果。

API 基础:基址与 Run 发现

所有接口共用一个基址:

BASE="https://performance.ci.clickhouse.com/api/v1"

查找某个 PR 的全部性能 Run

PR=104350 curl -fsS "$BASE/runs?q=$PR" | jq .

返回的items[]中每个元素代表一次完整的性能对比 Run,文档要求重点关注以下身份与摘要字段:

字段含义
identity.runIdRun 的唯一标识,后续所有/runs/$RUN_ID/...接口的参数
identity.prNumber关联的 PR 编号
identity.oldSha基线(master/参考)二进制 commit SHA
identity.newSha候选(被测试 PR)二进制 commit SHA
identity.runTimeRun 的执行时间
arches本次 Run 覆盖的架构(如amdarm
changedQueries判定为"已变更"的查询数
slowdownQueries变慢查询数
speedupQueries加速(改善)查询数
unstableQueries高噪声/不稳定查询数

重要约定:搜索可能返回超出预期的结果,必须始终用identity.prNumber == PR二次过滤。辅助脚本中对应的过滤逻辑可参考 perf_api.py 的fetch_pr_runs()

实测中观察到的 API 陷阱

参考文档专门记录了 live testing 中发现的四条 caveat,直接决定数据如何解读:

  • unstableQueries[]可能包含高噪声/高阈值行,即使汇总卡片显示Unstable queries: 0。它们应被当作 flakiness/噪声上下文,除非同时超过阈值,否则不应视为 changed rows。
  • fileSet=intersecting无交集文件时,totals.intersectingFiles可能被省略,此时回退用len(files)作为零交集计数。
  • 趋势响应中的selectedRunPoint.value可能是标记用的0,该 PR 的真实测量值应以 query detail 的 old/new 值为准。
  • Flamegraph 端点即使在查询确实变更时也可能返回 404——缺少 flamegraph 数据不代表任何方向,既不能证明有变化也不能证明是噪声。

Run 概览:一次 Run 的完整对比清单

拿到runId后,首先获取该 Run 的概览。通过metrics参数可以控制返回哪些指标维度,惯例为client_time,real_time,cpu_time,memory

curl -fsS "$BASE/runs/$RUN_ID?metrics=client_time,real_time,cpu_time,memory" | jq .

值得使用的顶层结构:

  • slowdowns[]—— 判定变慢的对比行
  • speedups[]—— 判定改善的对比行
  • unstableQueries[]—— 高噪声/高阈值行
  • testSummaries[]—— 各测试摘要
  • assets[]reports[]—— 关联的产物与报告

ComparisonRow 字段

每一条变更对比行的核心字段如下:

字段含义
test性能测试名(对应tests/performance/*.xml的测试文件基名)
queryIndex测试内的查询序号
queryDisplayName查询展示名
metric指标名(client_time/real_time/cpu_time/memory等)
arch架构(amd/arm
oldValue基线测量值
newValue候选测量值
diffPercent变化百分比
statThreshold统计判定阈值
direction方向(slowdown/speedup)
severity严重度
confidence置信度信息

数值单位陷阱:在已观察到的示例中,API 的diffPercentstatThreshold小数/分数形式返回——例如0.232表示约+23.2%。不确定展示格式时,应按分数处理并在展示时转换为百分比。这一点在 perf_api.py 的change_pct()中同样被注释为"Observed API values are fractional"。

判断一行是否超过阈值,参考脚本采用abs(diffPercent) + 1e-6 >= abs(statThreshold)(容忍二进制/十进制舍入误差),见 perf_api.py。

Confidence:置信度如何把 raw change 转化为可对外表述的证据

Confidence 模块回答"这一行变更到底可信多少"。它可以按 Run 或按单个 Test 拉取:

# Run 级置信度 curl -fsS "$BASE/runs/$RUN_ID/confidence?metrics=client_time,real_time,cpu_time,memory" | jq . # Test 级置信度(更常用) curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/confidence?metrics=client_time,real_time,cpu_time,memory" | jq .

使用规范(写入报告时必须遵守):

  • 始终汇报confidence.tierconfidence.reason(当存在时)。
  • 模块细节使用modules[].titlemodules[].statusmodules[].interpretation,以及有用的modules[].rows[]事实。
  • 严禁M1:downgrade, M2:neutral这类 Dashboard 内部简写直接写进报告——那只是内部代号,不是面向评审的结论。辅助脚本在 perf_api.py 中会对 speedup 行做措辞校正(不打印 slowdown/regression 语义)。
  • 对 speedup 行要格外小心:当前 tier 名称/原因可能以 slowdown 为导向,不要在加速行上打印confirmed_regression;只有当周边证据支持时才称之为 stable speedup/change。

推荐的对外表述示例:

tier=noise; reason=change is smaller than recent-history adaptive threshold; History Adaptive Threshold downgraded because observed 47.2% < adaptive 94.8%.

Test 与 Query 详情:定位到具体查询与火焰图资产

从 Run 概览定位到可疑的(test, queryIndex, metric, arch)组合后,下钻到最细粒度:

# 单个 Test 详情 curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST?metrics=client_time,real_time,cpu_time,memory" | jq . # 单个 Query 详情(最常用) curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/queries/$QUERY_INDEX?metrics=client_time,real_time,cpu_time,memory" | jq .

Query detail 是证据收集的核心入口,用于采集:

  • queryText—— 实际执行的 SQL 文本;
  • 该查询的全部 metric rows(跨 arch/方向);
  • flamegraphAssets—— 火焰图资产引用;
  • report links。

结合 perf_api.py 的cmd_query()实现可以看到,脚本正是通过该端点过滤 metric 与 arch 后输出"匹配的 metric 行"表格,并据此进一步拼接 confidence/trend/history/coverage/flamegraph-diff 参数。

Trend 与 History:用历史分布判断"越界"还是"噪声"

单次 PR Run 的数值没有意义,必须放进历史分布中解读。文档提供两个互补接口:

# 选定 Run 附近的趋势 curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/trend?metric=$METRIC&queryIndex=$QUERY_INDEX&arch=$ARCH" | jq . # 更长历史 curl -fsS "$BASE/history/$TEST/$QUERY_INDEX?metric=$METRIC&arch=$ARCH" | jq .

可用结构

  • points[]/centerTrend[]:正常散布与选定 Run 的上下文;
  • changePoints[]:已知的历史跳变点;
  • periodComparisons[]:较大的历史区间变化。

报告必须满足的摘要形状

趋势/历史部分仅给 min/max 是不合格的。规范的摘要必须包含:

  1. 说明 points 覆盖的时间段;
  2. 给出分位数而不仅是 min/max:p05/p25/p50/p75/p95
  3. 展示近期窗口的散布,例如最近 30 个点及其时间跨度;
  4. 把选定 Run 的 old/new 值分别与p50p95对比;
  5. 对 change points 去重,列出最近相关条目的日期/方向/SHA。

例如 verdict-rules.md 中给出的合格措辞模板:

History center trend: 976 points over 2026-04-24 → 2026-06-15; all p05/p50/p95 = ...; recent 30 points over 22.7h p05/p50/p95 = ...; candidate is 3.06x p95.

对应的辅助实现见 perf_api.py:percentile()计算线性插值分位数,summarize_points()自动生成"全量分布 + 最近 30 点分布",selected_value_context()计算选定行相对 p50/p95 的倍数;change points 的去重与排序在change_points_summary()中完成。

解读规则

  • 选定 Run 远超出近期 p95 且多次 PR Run 重复出现 → 证据更强;
  • 选定 Run 落在近期正常散布内 → 很可能噪声/不稳定;
  • master 近期存在已知 change point → 该 PR 可能只是在继承 master 自身的波动,而非它引起的变化。

Coverage / PR 交集:判断"测试是否执行了 PR 修改的代码"

Coverage 接口回答的问题是这个 perf test 有没有执行到 PR 触碰的代码,它不能证明因果关系,只能评估 PR/测试关系的 plausible(合理性):

curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/coverage?fileSet=intersecting" | jq .

fileSet支持的其他取值:

fileSet=pr # PR 触碰的文件 fileSet=covered # 测试覆盖的文件 fileSet=all # 全部

关键字段:

  • coverageAvailablemessage
  • totals.touchedFiles(PR 触碰文件数)、totals.coveredFiles(测试覆盖文件数)、totals.intersectingFiles(交集数)
  • files[].pathfiles[].statusfiles[].patchfiles[].coverageRanges[]

辅助脚本 perf_api.py 在totals.intersectingFiles缺失时自动用len(files)兜底,与文档 caveat 一致。当 coverage 不可用时,可以退回到gh pr diff结合查询文本人工判断相关子系统。

Flamegraphs:从采样栈增量定位热点

文档强调:面向评审者的链接应首先指向 UI 的 query 页面(该页面内含 Flamegraphs 卡片):

https://performance.ci.clickhouse.com/runs/$RUN_ID/tests/$TEST/queries/$QUERY_INDEX

只有需要机器可读的栈/增量时才使用 raw API。

单侧 collapsed stacks

curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/queries/$QUERY_INDEX/flamegraph?metric=$METRIC&arch=$ARCH&side=candidate&traceType=CPU" | jq -r .collapsed

side可取candidate(被测试 PR 侧)或基线侧;配合arch指定架构。

差分火焰图数据

curl -fsS "$BASE/runs/$RUN_ID/tests/$TEST/queries/$QUERY_INDEX/flamegraph-diff?metric=$METRIC&arch=$ARCH&traceType=CPU" | jq .

Flamegraph diff 的字段为stackbaselineSamplescandidateSamples

traceType 语义

traceType含义
CPU计算时间
REAL_TIME墙钟时间:适合观察等待、锁、I/O、调度器噪声
MEMORY内存相关的采样(如可用)

建议的摘要表格

Leaf/subsystemBaseline samplesCandidate samplesDeltaInterpretation

根因声明约束:不能仅因为某个 frame 有 samples 就声称根因,它必须与 metric/query 匹配,且与 PR 修改的 plausibility 吻合。评审可用的火焰图证据必须包含:① 精确的 UI query-page 链接(优先);② 仅在有价值时附 raw API 链接;③ 顶部采样增量表格;④ 与查询关联的简短解读;若无数据则明确写no frames returned/not available

30 天 Master 状态计数:通过 ClickHouse Play 的default.checks

Dashboard/API 偏重图表与趋势;当需要"同一测试/查询在 master 上 30 天内出现过多少次slower/faster/unstable"这类直接计数时,走 ClickHouse Play 的default.checks表。该表记录了每次 master 性能检查的状态。

推荐直接使用封装好的 helper:

python3 scripts/perf_api.py master-checks --pr "$PR" --limit 50

等价的 HTTP + SQL 查询模式:

curl -fsS 'https://play.clickhouse.com/?user=explorer' --data-binary @- <<'SQL' SELECT replaceRegexpOne(test_name, '::(new|old)$', '') AS test, countIf(test_status = 'slower') AS slower_count, countIf(test_status = 'faster') AS faster_count, countIf(test_status = 'unstable') AS unstable_count, count() AS total_runs FROM default.checks WHERE pull_request_number = 0 AND check_name LIKE '%Performance%arm%' AND check_start_time >= now() - INTERVAL 30 DAY AND test_name IN ('fixed_hash_table_parallel_merge #1::new') GROUP BY test FORMAT JSONEachRow SQL

注意关键过滤条件:

  • pull_request_number = 0:只统计 master 自身运行;
  • check_name LIKE '%Performance%arm%':与待分析行保持同架构
  • test_name需写成'<test> #<queryIndex>::new'形式;
  • 时间窗INTERVAL 30 DAY--days参数控制(默认 30)。

计数结果用于分类:new in PRrarely on masterflaky/slower on masterunstable on masternew improvementfixes known master regression。具体分类规则可在 perf_api.py 的classify_with_master_counts()中看到:例如unstable >= 5或比例 >1% 判为 "unstable on master";slowdown 行在 master 上 slow 比例 >1% 或次数 ≥3 判为 "flaky/slower on master",1~2 次判为 "rarely slower",master 总样本 ≥50 且从未出现则判为 "new in PR — investigate"。

TSV/raw 产物清单:Dashboard 缺失时的次选证据

当 Dashboard/API 无法提供所需 artifact 级数据(例如某分片、某 run 的原始逐次运行值)时,使用 raw TSV。可用数据源包括:

  • all-query-metrics.tsv(raw,按当前 CI 列序、无表头);
  • fetch_perf_report.py --tsv输出(带命名字段)。

两者按 per-shard 行提供:old/new(raw 文件中叫left/right)、difftimes_changestat_thresholdtestquery_index、查询展示文本;fetch_perf_report.py --tsv额外携带archshardis_changedis_unstabledirection

使用 helper 解析:

python3 scripts/perf_api.py tsv-inventory --tsv pr_${PR}_amd.tsv pr_${PR}_arm.tsv --limit 20

解析器 perf_api.py 同时支持命名 TSV 与无表头的 rawall-query-metrics.tsv(当前 CI 列序定义在RAW_ALL_QUERY_METRICS_COLUMNS),并且能透明解压 zstd/gzip 压缩的文本产物(与 CI 对超过阈值文本产物做 zstd 压缩的策略一致,见read_text_maybe_compressed())。判定规则复刻自 compare.sh 中的:

  • changed_failabs(diff) > changed_threshold && abs(diff) >= stat_threshold,默认changed_threshold = 0.15
  • unstable_fail:非 changed 且stat_threshold > unstable_threshold(默认0.25)。

边界:TSV 行只是 artifact fallback evidence,不得用来推翻 Dashboard 的分类结论

Artifact/日志兜底:需要根因时的最终落点

当 Dashboard/API 无法解释"为什么"时,下载 CI 产物。文档给出清晰的产物地图:

产物用途
logs.tar.zst/job.log.zstJob 上下文、server 配置、警告/错误、机器争用
left/server.logright/server.log精确的 old/new 二进制 revision、build ID、启动设置、查询执行计时、后台活动
report/stacks.left.tsvreport/stacks.right.tsv每个查询的 symbolized collapsed stacks(CPU/Real/Memory),优先于*-trace-log.tsv
analyze/tmp/{test}_{queryN}.tsv每次运行的 raw profile events,Dashboard 只显示汇总指标时使用
预构建的.svgflamegraphsDashboard flamegraph-diff 缺失或不完整时使用

注意:*-trace-log.tsv并不随logs.tar.zst一起发布,且只包含query_id, trace, trace_type, size(原始地址、无符号)。这些 trace/addresses 类文件的产生逻辑可以对照 compare.sh 中的get_profiles()——它只 dumpsystem.trace_log的四列并把符号解析任务交给独立的*-addresses.tsv使用顺序必须是:优先 Dashboard flamegraph/query API,仅在需要 raw logs、raw traces、精确 build 元数据或 Dashboard 未 profile 的查询/run 时才回退到产物。

实战集成:把 API 组合成一份可评审的性能结论

单独的接口只是数据,真正的价值在于如何组合成结论。建议按以下工作流使用本文接口:

  1. Run 发现与身份核对GET /runs?q=$PR,过滤prNumber,记录oldSha/newSha/arch/runTime
  2. 变更行全量盘点GET /runs/$RUN_ID分离slowdowns/speedups/unstableQueries三张表,且改善行必须与回归行一起列出pr-inventory命令会自动输出Top likely signal/Top likely noise/Top improvements摘要层);
  3. 重复性检查:同一(test, queryIndex, metric, arch)跨多个 PR Run 是否反复出现同向变化,方向是否翻转;
  4. 置信度取证:按 test 拉confidence,翻译 tier/reason 为自然语言证据;
  5. 历史/趋势定位:用 trend/history 分位数判断是否越界;
  6. master 计数分类master-checks给出new in PR/flaky/unstable/fixes known regression等标签;
  7. 覆盖率与火焰图coverage?fileSet=intersecting判断相关性,UI query 页的 Flamegraphs 卡片定位热点;
  8. 产物兜底:必要时解包logs.tar.zstserver.log核对构建与计时细节。

所有步骤都有现成命令封装在 perf_api.py 中:runspr-inventoryrun/changesquerypr-query-historymaster-checkstsv-inventory。各判定标签的取舍标准(real regressionlikely noiseneeds rerununstable testreal improvementlocal-only evidencenot enough evidence)以及禁止/推荐的报告措辞,均在 verdict-rules.md 中有完整定义。

报告措辞红线

  • 不得用"dashboard 表说 slower 所以是 regression"这类一句式结论;
  • 不得输出M1:downgrade, M2:neutral这类未解释的内部代号;
  • 历史部分不得只写min/max/median/last,必须给出分位数与时间窗;
  • 新 Run 数据出来后被推翻的旧测量必须显式声明"被更新的结果取代",而不是直接展示旧表;
  • 火焰图表述必须落到"顶部采样增量 + 与查询/PR 的关系",而不是笼统的"flamegraph diff exists and contains relevant samples"。

延伸阅读

  • perf-comparison/SKILL.md:本 API 参考所属的技能总入口,定义核心原则、证据阶梯与数据源优先级;
  • verdict-rules.md:判定标签与报告措辞的权威规则;
  • local-perf.md:本地perf.py与可选 server 启动、数据集、profile 流程(当 CI 证据不足需本地复现时使用);
  • perf_api.py:上述全部 API 的 stdlib-only 封装实现;
  • test_perf_api.py:对 TSV 解析与 compare.sh 判定规则一致性的回归测试;
  • compare.sh:性能对比 CI 的底层实现(阈值判定、profile 采集、change 确认机制);
  • perf.py:性能测试执行脚本,本地复现与 CI 均依赖它。

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

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

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

冻融循环与氯离子侵蚀耦合下的混凝土耐久性数值模拟

这几年在北方沿海、盐渍土地区跑项目&#xff0c;混凝土耐久性病害里最让人头疼的组合就是冻融循环和氯离子侵蚀同时出现。单独做冻融试验或单测氯离子扩散&#xff0c;结果往往偏乐观&#xff0c;现场却早早出现顺筋裂缝和表层剥落。原因在于这两个过程根本就不是简单叠加&…

作者头像 李华
网站建设 2026/9/8 16:53:35

Windows消息机制详解:从硬件事件到窗口过程的完整链路

刚把Windows系统的启动流程和进程调度捋清楚没多久&#xff0c;我又一头扎进了消息机制。这个知识点我老早就想整理成笔记&#xff0c;但一直觉得它既抽象又琐碎&#xff1a;网上能找到的资料要么停留在“给你一段WinMain抄一下”&#xff0c;要么就直接上MFC/消息循环源码&…

作者头像 李华
网站建设 2026/9/8 16:52:33

传感器实战解析:从原理到选型与信号处理

传感器这东西&#xff0c;干我们这行的天天跟它打交道&#xff0c;但真要说“懂”它&#xff0c;很多人其实是懵的。你问一个刚入行的工程师“传感器是啥”&#xff0c;他能给你背出“将非电量转换为电量的器件”这种教科书答案&#xff1b;但你问他“为什么你的称重数据老是漂…

作者头像 李华
网站建设 2026/9/8 16:51:11

YOLO模型的量化训练(QAT) vs 训练后量化(PTQ):精度与工程复杂度的权衡

引言:边缘部署的“最后一公里”困局 把YOLO模型部署到边缘设备上,是所有计算机视觉工程师都会面临的“最后一公里”难题。FP32模型在Jetson Nano、树莓派或RK3588上跑起来,推理延迟动辄几十甚至上百毫秒,内存占用几百兆,实时检测基本是奢望。 量化技术因此被推上日程。但…

作者头像 李华
网站建设 2026/9/8 16:50:08

团队AI编程工具选型实测:7款工具免费版与协作方案横向对比

今年年初我就开始琢磨团队AI编程工具的选型问题。那时候组里的情况很典型&#xff1a;个人开发者各用各的插件&#xff0c;有人偷偷用免费的AI编程工具&#xff0c;有人自己充了订阅&#xff0c;代码风格越来越乱&#xff0c;预算也没个统一口径。更要命的是&#xff0c;团队协…

作者头像 李华