mcpField
C
chat-perf

chat-perf

github.com/microsoft测试与质量194.4k139 次安装今天更新
代码仓库

关于 chat-perf

面向 VS Code 聊天界面开发者的性能测试工具,可基准测试模拟聊天场景,并比较不同构建或版本。它同时测量渲染、响应耗时和内存,并提供单独的内存泄漏检查。

主要功能

  1. 01模拟聊天场景并测量性能
  2. 02比较构建或版本基线
  3. 03采集渲染与响应耗时指标
  4. 04分析堆增长和 DOM 节点变化
  5. 05支持 CI 回归检测

适用场景

  1. 01评估聊天界面代码改动
  2. 02比较两个 VS Code 构建
  3. 03在 CI 中检测性能回归
  4. 04检查多轮聊天的内存泄漏

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/vscode --skill chat-perf

安装后在 Claude Code 中输入/chat-perf确认已加载。

详细介绍

聊天性能测试

适用场景

  • 修改聊天渲染代码(chatListRenderer.ts、chatInputPart.ts、Markdown 渲染)前后
  • 更改流式响应管线或 SSE 处理时
  • 修改聊天组件中的 disposable/lifecycle 模式时
  • 比较两个 VS Code 版本的性能时
  • 在 CI 中为涉及聊天 UI 代码的 PR 设置门禁

快速开始

# Run perf regression test (compares local dev build vs VS Code 1.115.0):
npm run perf:chat -- --scenario text-only --runs 3

# Run all scenarios with no baseline (just measure):
npm run perf:chat -- --no-baseline --runs 3

# Compare two local builds (apples-to-apples):
npm run perf:chat -- --build /path/to/build-A --baseline-build /path/to/build-B --runs 5

# Build a local production package and compare against a release:
npm run perf:chat -- --production-build --baseline-build 1.115.0 --runs 5

# Run memory leak check (10 messages in one session):
npm run perf:chat-leak

# Run leak check with more messages for accuracy:
npm run perf:chat-leak -- --messages 20 --verbose

性能回归测试

脚本: scripts/chat-simulation/test-chat-perf-regression.js npm: npm run perf:chat

通过 Playwright Electron 启动 VS Code,打开聊天面板,发送一条带有模拟 LLM 响应的消息,并测量耗时、布局和渲染指标。默认情况下,会下载 VS Code 1.115.0 作为基线,对其进行基准测试,然后对本地开发构建进行基准测试并进行比较。

并非总是需要基线。 基线仅用于比较(检测回归)。如果你只想获取当前构建的数据——分析单项改动、捕获跟踪记录/堆快照,或迭代测试场景——请传入 --no-baseline,完全跳过基线的下载和基准测试(运行时间大约减半)。基线比较能将原始测量结果转化为通过/失败判定;没有基线时,你仍能获得全部指标,只是没有判定结果。

主要标志
标志默认值说明
--runs <n>5每个场景的运行次数。次数越多,结果越稳定。CI 中建议使用 5 次以上。
--scenario <id> / -sall要测试的场景(可重复指定)。参见 common/perf-scenarios.js。
--build <path|ver> / -blocal dev要测试的构建。接受路径或版本(1.110.0、insiders、提交哈希)。
--baseline <path>—与之前保存的基线 JSON 文件进行比较。
--baseline-build <path|ver>1.115.0要作为基线进行基准测试的版本或本地路径。
--no-baseline—完全跳过基线,只测量测试构建(无需下载、无需比较,速度约快 2 倍)。仅需原始数据而不需要回归判定时使用。
--save-baseline—将结果保存为新基线(需要 --baseline <path>)。
--resume <path>—恢复之前的运行,并增加迭代次数以提高置信度。
--threshold <frac>0.2回归阈值(0.2 = 慢 20% 时标记)。
--production-build—通过 gulp vscode 构建本地捆绑包,以便与发布基线比较。
--no-cache—忽略缓存的基线数据,始终重新运行。
--force—跳过构建模式不匹配确认提示。
--ci—CI 模式:将 Markdown 摘要写入 ci-summary.md(隐含 --no-cache、--heap-snapshots、--cleanup-diagnostics)。
--heap-snapshots—每次运行后获取堆快照(速度较慢;在 --ci 模式下自动启用)。
--gc-object-stats—仅用于 GC 深入分析。 启用 V8 gc_stats 跟踪(每次 GC 都转储各类型的堆对象)。⚠️ 会破坏所有耗时指标——请求过程中发生一次主要 GC 就会增加约 550 ms,因此切勿用于基准测试。默认关闭;内存分析时优先使用堆快照。
--cleanup-diagnostics—删除堆快照、CPU 配置文件和跟踪记录以节省磁盘空间。运行期间仅保留最近一次运行的文件;比较后会删除未发生回归场景的文件。在 --ci 模式下自动启用。
--setting <k=v>—为所有构建设置 VS Code 设置覆盖项(可重复指定)。
--test-setting <k=v>—仅为测试构建设置 VS Code 设置覆盖项。
--baseline-setting <k=v>—仅为基线构建设置 VS Code 设置覆盖项。
--verbose—输出每次运行的详细信息,包括响应内容。
比较两个远程构建
# Compare 1.110.0 against 1.115.0 (no local build needed):
npm run perf:chat -- --build 1.110.0 --baseline-build 1.115.0 --runs 5
比较两个本地构建版本

--build 和 --baseline-build 都接受 VS Code 可执行文件的本地路径。这使你能够对任意两个构建版本进行公平比较:

# Compare two dev builds (e.g. feature branch vs main):
npm run perf:chat -- \
  --build .build/electron/Code\ -\ OSS.app/Contents/MacOS/Code\ -\ OSS \
  --baseline-build /path/to/other/Code\ -\ OSS.app/Contents/MacOS/Code\ -\ OSS \
  --runs 5

# Compare two production builds:
npm run perf:chat -- \
  --build ../VSCode-darwin-arm64-feature/Code\ -\ OSS.app/Contents/MacOS/Code\ -\ OSS \
  --baseline-build ../VSCode-darwin-arm64-main/Code\ -\ OSS.app/Contents/MacOS/Code\ -\ OSS \
  --runs 5

本地路径基准版本不会缓存(构建版本可能会在两次运行之间发生变化)。版本字符串基准版本会缓存,以便重复使用。

构建模式和不匹配检测

该工具根据可执行文件路径将构建版本分为三种模式:

模式来源特征
dev.build/electron/(本地开发)未打包的源代码、VSCODE_DEV=1、NODE_ENV=development。内存和启动开销较高。
production../VSCode-<platform>-<arch>/(通过 gulp vscode 构建)已打包的 JS,无开发标志。符合发布版本的特征,但使用本地源代码。
release.vscode-test/(通过 @vscode/test-electron 下载)官方发布的构建版本。

当测试构建版本和基准构建版本的模式不同时(例如 dev 与 release),该工具会显示警告并提示确认。使用 --force 或 --ci 可跳过提示。

使用 --production-build 会通过 gulp vscode 构建本地打包版本,以便与 release 基准版本进行公平比较。这样既能消除开发模式的开销,又能测试本地更改。

# Production build vs release baseline (fair comparison):
npm run perf:chat -- --production-build --baseline-build 1.115.0 --runs 5
设置覆盖

使用 --setting、--test-setting 和 --baseline-setting 可向启动的实例注入 VS Code 设置。这适用于对实验性功能进行 A/B 测试:

# Enable a feature for the test build only:
npm run perf:chat -- --test-setting chat.experimental.incrementalRendering.enabled=true --runs 3

# Compare two builds with different settings:
npm run perf:chat -- \
  --baseline-build "../vscode2/.build/electron/Code - OSS.app/Contents/MacOS/Code - OSS" \
  --baseline-setting chat.experimental.incrementalRendering.enabled=true \
  --test-setting chat.experimental.incrementalRendering.enabled=false \
  --runs 3

# Set a value for both builds:
npm run perf:chat -- --setting chat.mcp.enabled=false --runs 3

优先级:对于相同的键,--test-setting / --baseline-setting 会覆盖 --setting。值会自动解析:true/false 会转换为布尔值,数字会转换为数字,其他值均保留为字符串。

恢复运行以提高可信度

当结果超过阈值但统计显著性不足时,该工具会打印 --resume 提示。使用它可向现有运行中添加更多迭代:

# Initial run with 3 iterations — may be inconclusive:
npm run perf:chat -- --scenario text-only --runs 3

# Add 3 more runs to the same results file (both test + baseline):
npm run perf:chat -- --resume .chat-simulation-data/2026-04-14T02-15-14/results.json --runs 3

# Keep adding until confidence is reached:
npm run perf:chat -- --resume .chat-simulation-data/2026-04-14T02-15-14/results.json --runs 5

--resume 会加载之前的 results.json 及其关联的 baseline-*.json,为两个构建版本各运行 N 次迭代,合并 rawRuns,重新计算统计数据,并重新进行比较。更新后的文件会原地写回。你可以多次恢复运行,样本会逐步累积。

统计显著性

回归检测使用 Welch's t-test,以避免嘈杂测量结果造成误报。只有当某项指标既超过阈值又具有统计显著性(p < 0.05)时,才会标记为 REGRESSION。否则会报告为 (可能是噪声 — p=X,不显著)。

在典型方差(cv ≈ 20%)下,需要:

  • 每个构建版本 n ≥ 5,才能以 95% 的置信度检测到 35% 的回归
  • 每个构建版本 n ≥ 10,才能可靠地检测到 20% 的回归

报告的置信度等级:high(p < 0.01)、medium(p < 0.05)、low(p < 0.1)、none。

退出码
  • 0 — 所有指标均在阈值范围内,或虽超过阈值但统计显著性不足
  • 1 — 检测到统计显著的回归,或所有运行均失败
场景

场景定义在 scripts/chat-simulation/common/perf-scenarios.js 中,并通过 registerPerfScenarios() 注册。分为三类:

  • 仅内容 — 纯流式响应(例如 text-only、large-codeblock、rapid-stream)
  • 工具调用 — 包含工具调用的多轮场景(例如 tool-read-file、tool-edit-file)
  • 多轮用户对话 — 包含用户后续提问和思考块的多轮对话(例如 thinking-response、multi-turn-user、long-conversation)

运行 npm run perf:chat -- --help 可查看已注册场景 ID 的完整列表。

收集的指标
  • 时间: 首个令牌耗时、完成耗时、渲染完成耗时(包括打字机动画)
  • 渲染: 布局次数、布局耗时(ms)、样式重新计算次数、强制重排、长任务(>50ms)、长动画帧次数和耗时
  • 内存: GC 前后的堆内存、GC 后的堆内存变化(仅供参考,单次请求的结果波动较大)
  • 扩展宿主: 通过 CDP inspector 获取 GC 前后的堆内存及其变化
回归触发指标与信息性指标

只有以下指标会触发回归失败(当其超过阈值且具有统计显著性时):

  • timeToFirstToken、timeToComplete — 用户感知延迟
  • layoutDurationMs — 跟踪记录中的总布局耗时(实际布局开销)
  • forcedReflowCount — 强制同步布局总是不利的
  • longTaskCount — 主线程卡顿

以下指标会报告,但仅供参考(不会导致 CI 失败):

  • longAnimationFrameCount — 长动画帧数量;该指标噪声较大且由合成器驱动,因此会跟踪以便观察趋势,但不会作为门槛。实际卡顿由 longTaskCount / layoutDurationMs 把关。
  • layoutCount — 布局操作数量;CSS 动画会使其数值偏高(由合成器驱动,开销低)。某个构建版本可能执行更多但开销更低的布局,因此应以 layoutDurationMs 而非此计数作为门槛。
  • recalcStyleCount — 样式重新计算次数;CSS 动画会使其数值偏高(由合成器驱动,开销低)
  • timeToRenderComplete — 包含打字机动画的尾部时间
  • 内存/堆指标 — 对单次请求基准测试而言噪声太大
统计数据

结果使用基于 IQR 的异常值剔除和中位数(而非平均值)来处理启动抖动。报告变异系数(cv)——低于 15% 表示稳定,高于 15% 时会发出 ⚠ 警告。基线对比会对原始运行值使用 Welch's t 检验,以在标记回归前判断其是否具有统计显著性。建议至少运行 5 次,以获得稳定结果。

内存泄漏检查

脚本: scripts/chat-simulation/test-chat-mem-leaks.js npm: npm run perf:chat-leak

启动一个 VS Code 会话,依次发送 N 条消息,在每条消息之间强制执行 GC,并测量渲染进程堆和 DOM 节点数量。使用样本进行线性回归,计算每条消息的增长率,并将其与阈值进行比较。

主要标志
标志默认值描述
--messages <n> / -n10要发送的消息数量。数量越多,斜率越准确。
--build <path|ver> / -b本地开发版要测试的构建版本。
--threshold <MB>2每条消息的最大堆增长量,单位为 MB。
--setting <k=v>—设置 VS Code 设置覆盖项(可重复指定)。
--verbose—打印每条消息的堆/DOM 计数。
测量内容
  • 堆增长斜率(MB/条消息)——对强制 GC 后的堆样本进行线性回归。泄漏会表现为持续的正斜率。
  • DOM 节点增长(节点/条消息)——用于捕捉元素未清理的渲染泄漏。正常的聊天会对旧消息进行虚拟化处理,因此节点数量会趋于稳定。
结果解读
  • 0.3–1.0 MB/msg — 正常(V8 内部开销、字符串驻留)
  • >2.0 MB/msg — 可能存在泄漏,请检查被保留的对象
  • 第一条消息之后 DOM 节点数量保持稳定 — 正常(聊天列表虚拟化正常工作)
  • DOM 节点数量线性增长 — 渲染泄漏,请检查可释放资源的清理情况

CI 运行与回归定位

性能和泄漏检查通过 .github/workflows/chat-perf.yml 工作流在 CI 中运行(每日定时触发 workflow_dispatch,并支持手动触发)。每次运行都会将当前 main 作为测试构建版本,与固定的发布基线进行基准测试(来自 config.jsonc,例如 1.122.0)。由于基线固定,各次每日运行中某项指标的测试中位数会描绘 main 随时间的变化轨迹,这使你能够通过二分查找确定回归或不稳定情况发生的时间。

查找和查看历史运行记录
# List recent runs (most recent first) — note the run IDs and dates
gh run list --workflow chat-perf.yml -R microsoft/vscode --limit 30 \
  --json databaseId,status,conclusion,createdAt,headBranch \
  --jq '.[] | [.databaseId, (.conclusion//.status), .createdAt, .headBranch] | @tsv'

# See a run's per-job results
gh run view <run-id> -R microsoft/vscode --json jobs \
  --jq '.jobs[] | [.name, (.conclusion//.status)] | @tsv'

# Trigger a run manually against any ref/version:
gh workflow run chat-perf.yml -R microsoft/vscode --ref main \
  -f test_build=<branch|sha|version> -f baseline_build=<version>
每次运行的构件(及保留期限——这对较早的运行记录很重要)
构件内容保留期限
chat-perf-summary统一的 ci-summary.md:判定结果、各指标中位数 ± 标准差、逐次运行的原始数据表30 天
perf-results-<group>下方所有内容,另加跟踪记录、CPU 配置文件、堆快照(体积较大)30 天
leak-results泄漏日志 + chat-simulation-leak-results.json30 天
perf-summary-<group>results.json(完整的逐次运行指标,包括 rawRuns)+ baseline-*.json1 天
# List a run's artifacts + whether they've expired
gh api repos/microsoft/vscode/actions/runs/<run-id>/artifacts \
  --jq '.artifacts[] | [.name, .expired] | @tsv'

# Download the human-readable summary (best first stop; survives 30 days)
gh run download <run-id> -R microsoft/vscode -n chat-perf-summary
定位指标回退 / 变得不稳定的时间点
  1. 按日期二分查找。 从覆盖该时间段的多次运行中提取 chat-perf-summary/ci-summary.md。逐次比较可疑指标和场景运行的测试中位数(及 ±stddev)——指标开始跳变的那一天,就是 main 发生变更的时间。指标呈现双峰分布(例如,原始运行列显示两个簇,如 ~250 / ~900)是不稳定的特征;稳定的偏移则是真正的回归。
  2. 确认问题真实存在,而非测量噪声。 检查每次运行的原始表格(位于 ci-summary.md 中)——较高的 ±stddev / 双峰值意味着少数异常运行拉动了中位数,而不是出现了普遍的变慢。
  3. 深入分析原因。 下载慢速运行对应的 perf-results-<group>(其中包含每次运行的 trace.json),检查慢速时间窗口中占主导的内容。发现 gc_stats 产物的技巧:计算两个 code/chat/* 标记(例如 willCollectInstructions → didCollectInstructions)之间主线程 RunTask 的持续时间总和——如果该窗口的忙碌时间约为 0%,说明这是异步等待或 GC 暂停,而非实际工作;接着查看该窗口中持续时间最长的 X 阶段事件(MajorGC、Layout 等)。
  4. 在本地重现可疑提交以精确二分查找:npm run perf:chat -- --build <sha> --baseline-build <ver> --runs 7(也可以直接比较两个提交:--build <shaA> --baseline-build <shaB>)。

提示:perf-summary-*(包含机器可读的 results.json 和 rawRuns)会在 1 天后删除,因此对于较早的运行,请依赖 chat-perf-summary(原始表格,保留 30 天),或从 perf-results-* 中提取 results.json(同样保留 30 天)。

架构

scripts/chat-simulation/
├── common/
│   ├── mock-llm-server.js    # Mock CAPI server matching @vscode/copilot-api URL structure
│   ├── perf-scenarios.js     # Built-in scenario definitions (content, tool-call, multi-turn)
│   └── utils.js              # Shared: paths, env setup, stats, launch helpers
├── config.jsonc              # Default config (baseline version, runs, thresholds)
├── fixtures/                 # TypeScript fixture files used by tool-call scenarios
├── test-chat-perf-regression.js
└── test-chat-mem-leaks.js
模拟服务

模拟 LLM 服务端(common/mock-llm-server.js)实现了来自 @vscode/copilot-api 的 DomainService 的完整 CAPI URL 结构:

  • GET /models — 返回模型元数据
  • POST /models/session — 返回包含 available_models 和 session_token 的 AutoModeAPIResponse
  • POST /models/session/intent — 模型路由器
  • POST /chat/completions — 返回与场景匹配的 SSE 流式响应
  • Agent、会话、遥测和令牌端点

copilot 扩展通过 IS_SCENARIO_AUTOMATION=1 模式连接到此服务,并使用 overrideCapiUrl 和 overrideProxyUrl 设置。必须禁用 vscode-api-tests 扩展(--disable-extension=vscode.vscode-api-tests),因为它会注册重复的 copilot 供应商,从而阻止真实扩展注册语言模型提供程序。

添加场景
  1. 使用 common/mock-llm-server.js 中的 ScenarioBuilder API,在 common/perf-scenarios.js 的相应对象(CONTENT_SCENARIOS、TOOL_CALL_SCENARIOS 或 MULTI_TURN_SCENARIOS)中添加新条目
  2. registerPerfScenarios() 会自动注册该场景——无需手动更新 ID 列表
  3. 运行:npm run perf:chat -- --scenario your-new-scenario --runs 1 --no-baseline --verbose

相关技能

  • heap-snapshot-analysis — 当性能回归或泄漏检查发现内存增长较高时,使用 heap-snapshot-analysis 技能深入分析。它可以解析 .heapsnapshot 文件、比较前后快照、对对象差异分组,并追踪保留路径,以找出导致已释放对象仍然存活的原因。chat-perf 泄漏检查用于测量整体堆斜率;heap-snapshot-analysis 则用于找出导致问题的具体对象。
  • auto-perf-optimize — 用于启动 VS Code、运行场景,并在进行底层分析前自动捕获堆快照或 CPU 配置文件。

评论

支持 Markdown