


































@@ -1,12 +1,13 @@
11---
22name: openclaw-test-performance
3-description: Benchmark, diagnose, and optimize OpenClaw test runtime, import hotspots, CPU/RSS, and slow coverage paths.
3+description: Benchmark, diagnose, and optimize OpenClaw test and plugin-suite runtime, import hotspots, CPU/RSS, heap growth, and slow coverage paths.
44---
5566# OpenClaw Test Performance
778-Use evidence first. The goal is real `pnpm test` speed/RSS improvement with
9-coverage intact, not runner tuning by guesswork.
8+Use evidence first. The goal is real `pnpm test`, plugin-suite, and
9+plugin-inspector speed/RSS improvement with coverage intact, not runner tuning by
10+guesswork.
10111112## Workflow
1213@@ -21,6 +22,9 @@ coverage intact, not runner tuning by guesswork.
21222. Establish a baseline before changing code:
2223- Prefer `pnpm test:perf:groups --full-suite --allow-failures --output <file>`
2324 for full-suite ranking.
25+- For bundled plugin breadth, run the smallest relevant `pnpm
26+test:extensions:batch <plugin[,plugin...]>` or plugin-inspector command
27+ before jumping to the full extension sweep.
2428- For a scoped hotspot use:
2529`/usr/bin/time -l pnpm test <file-or-files> --maxWorkers=1 --reporter=verbose`
2630- For import-heavy suspicion add:
@@ -33,6 +37,8 @@ coverage intact, not runner tuning by guesswork.
3337 passed, capture that as harness/noise and verify the suspect file directly.
34384. Pick the next attack by return and risk:
3539- High return: one file/test dominates seconds or RSS and has a clear root.
40+- High leverage: one plugin or SDK barrel causes every plugin-inspector or
41+ extension-batch run to load broad runtime.
3642- Lower risk: static descriptors, target parsing, routing, auth bypass,
3743 setup hints, registry fixtures, or test server lifecycle.
3844- Higher risk: real memory/runtime behavior, live providers, protocol
@@ -44,6 +50,8 @@ coverage intact, not runner tuning by guesswork.
4450 and pure helpers over broad mocks.
4551- Reuse suite-level servers/clients when a fresh handshake is irrelevant.
4652- Keep schedulers/background loops off unless the test proves scheduling.
53+- In plugin paths, move static metadata into manifest/lightweight artifacts
54+ and keep runtime plugin loads behind explicit execution boundaries.
47556. Preserve coverage shape:
4856- Do not delete a slow integration proof unless the exact production
4957 composition is extracted into a named helper and tested.
@@ -57,13 +65,103 @@ coverage intact, not runner tuning by guesswork.
57659. Commit with `scripts/committer "<message>" <paths...>` and push when the
5866 user asked for commits/pushes. Stage only files touched for this attack.
596768+## Plugin-Suite Workflow
69+70+Use this section when perf work involves bundled plugins, plugin-inspector, SDK
71+barrels, package-boundary tests, or extension suites.
72+73+1. Map the suite shape first:
74+- source tests: `pnpm test extensions/<id>` or `pnpm test:extensions:batch <id>`
75+- package boundaries: `pnpm run test:extensions:package-boundary:canary` and
76+`pnpm run test:extensions:package-boundary:compile`
77+- all bundled source tests: `pnpm test:extensions`
78+- plugin import memory: `pnpm test:extensions:memory -- --json .artifacts/test-perf/extensions-memory.json`
79+- plugin-inspector/report work: keep report primitives in `plugin-inspector`;
80+ keep wrappers thin and collect peak RSS when the command supports it.
81+2. Start narrow, then widen:
82+- one plugin changed: run that plugin's tests and plugin-inspector slice.
83+- SDK/public barrel changed: add representative provider, channel, memory,
84+ and feature plugins.
85+- loader/runtime mirror changed: add package-boundary checks and build/package
86+ proof as needed.
87+- unknown shared plugin behavior: run `test:extensions:batch` groups before
88+`pnpm test:extensions`.
89+3. Treat plugin-inspector failures as product signals:
90+- JSON must parse.
91+- warnings/errors must be classified, not hidden.
92+- runtime capture should be quiet and config-tolerant.
93+- command output should include wall time, exit code, and peak RSS when
94+ available.
95+4. For broad or package-heavy plugin proof, use Blacksmith Testbox by default on
96+ maintainer machines. Warm once and reuse the same box:
97+- `blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90`
98+- `blacksmith testbox run --id <ID> "OPENCLAW_TESTBOX=1 pnpm test:extensions:batch <ids>"`
99+- stop the box when done.
100+5. If plugin performance is package-artifact sensitive, switch to
101+`openclaw-pre-release-plugin-testing` and Package Acceptance rather than
102+ trusting source-only timing.
103+104+## Metric Collection
105+106+Collect at least one stable metric before and after. Prefer the same machine and
107+same command. For Testbox comparisons, use the same `tbx_...` id when possible.
108+109+| Metric | Use for | Preferred source |
110+| --------------- | ---------------------------------- | --------------------------------------------------------------------------- |
111+| wall time | user-visible suite cost | `/usr/bin/time -l`, test wrapper duration, Testbox run time |
112+| Vitest duration | test body/import cost | Vitest output per file/shard |
113+| import duration | broad barrel/runtime loads | `OPENCLAW_VITEST_IMPORT_DURATIONS=1` |
114+| max RSS | memory pressure and OOM risk | `/usr/bin/time -l`, `pnpm test:extensions:memory`, wrapper memory summaries |
115+| CPU/user/sys | CPU-bound vs wait-bound split | `/usr/bin/time -l` locally, Testbox job timing when local CPU is noisy |
116+| heap snapshots | real leak vs retained module graph | `openclaw-test-heap-leaks` workflow |
117+118+Local scoped command with CPU/RSS:
119+120+```bash
121+timeout 240 /usr/bin/time -l pnpm test <file> --maxWorkers=1 --reporter=verbose
122+```
123+124+Plugin import memory profile:
125+126+```bash
127+pnpm build
128+pnpm test:extensions:memory -- --top 20 --json .artifacts/test-perf/extensions-memory.json
129+```
130+131+Targeted plugin import memory:
132+133+```bash
134+pnpm test:extensions:memory -- --extension discord --extension telegram --skip-combined
135+```
136+137+Heap/RSS escalation:
138+139+```bash
140+OPENCLAW_TEST_MEMORY_TRACE=1 \
141+OPENCLAW_TEST_HEAPSNAPSHOT_INTERVAL_MS=60000 \
142+OPENCLAW_TEST_HEAPSNAPSHOT_DIR=.tmp/heapsnap \
143+OPENCLAW_TEST_WORKERS=2 \
144+OPENCLAW_TEST_MAX_OLD_SPACE_SIZE_MB=6144 \
145+pnpm test
146+```
147+148+Use `openclaw-test-heap-leaks` when RSS keeps growing across intervals, workers
149+OOM, or the suspect command has app-object retention. Do not call RSS growth a
150+leak until snapshots or retainers support it.
151+60152## Common Root Causes
6115362154- Full bundled channel/plugin runtime loaded for static data.
63155- `getChannelPlugin()` fallback used when an already-loaded fixture or pure
64156 parser would suffice.
65157- Broad `api.ts`, `runtime-api.ts`, `test-api.ts`, or plugin-sdk barrels pulled
66158 into hot tests.
159+- SDK root aliases or package barrels pulling focused subpaths back into a broad
160+ plugin graph.
161+- Plugin-inspector loading runtime code just to render metadata, reports, or CI
162+ policy scores.
163+- Bundled plugin capture reusing real config/home state instead of synthetic,
164+ redacted, isolated state.
67165- Partial-real mocks using `importActual()` around broad modules.
68166- `vi.resetModules()` plus fresh imports in per-test loops.
69167- Test plugin registry seeded in `beforeAll` while runtime state resets in
@@ -72,6 +170,10 @@ coverage intact, not runner tuning by guesswork.
72170- Runtime/default model/auth selection paid by idle snapshots or fixtures.
73171- Plugin-owned media/action discovery triggered before checking whether args
74172 contain plugin-owned fields.
173+- Timings missing from `test/fixtures/test-timings.unit.json`, causing hotspot
174+ files to stay in shared workers.
175+- Parallel Vitest runs sharing `node_modules/.experimental-vitest-cache` without
176+ distinct `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH` values.
7517776178## Benchmark Commands
77179@@ -97,6 +199,25 @@ pnpm test:perf:groups --full-suite --allow-failures \
97199 --output .artifacts/test-perf/<name>.json
98200```
99201202+Extension batch:
203+204+```bash
205+pnpm test:extensions:batch <plugin[,plugin...]> -- --reporter=verbose
206+```
207+208+All extension tests:
209+210+```bash
211+pnpm test:extensions
212+```
213+214+Package-boundary plugin checks:
215+216+```bash
217+pnpm run test:extensions:package-boundary:canary
218+pnpm run test:extensions:package-boundary:compile
219+```
220+100221Reuse an existing Vitest JSON report:
101222102223```bash
@@ -107,28 +228,39 @@ pnpm test:perf:groups --report <vitest-json> \
107228## Verification
108229109230- Always run the targeted test surface that proves the change.
110-- Run `pnpm check` before commit unless the change is docs-only and the hook
111- handles it.
231+- For source changes, run `pnpm check:changed` before push; in maintainer
232+ Testbox mode run it in the warmed Testbox.
233+- For test-only changes, run `pnpm test:changed` or the exact edited tests.
112234- Run `pnpm build` when touching lazy-loading, bundled artifacts, package
113235 boundaries, dynamic imports, build output, or public surfaces.
236+- For plugin SDK/barrel/runtime changes, add `pnpm plugin-sdk:api:check` or
237+`pnpm plugin-sdk:api:gen` when the API surface may drift.
238+- For plugin-suite perf fixes, verify at least one representative plugin batch
239+ plus the changed gate; use Package Acceptance if the bug only exists in a
240+ packed artifact.
114241- If deps are missing/stale, run `pnpm install` and retry the exact failed
115242 command once.
116243- Use the report format:
117244118245```markdown
119-| Metric | Before | After | Gain |
120-| -------------- | -----: | ----: | ------------: |
121-| File wall time | `Xs` | `Ys` | `-Zs` (`P%`) |
122-| Max RSS | `XMB` | `YMB` | `-ZMB` (`P%`) |
246+| Metric | Before | After | Gain |
247+| -------------- | -----: | -----: | ------------: |
248+| File wall time | `Xs` | `Ys` | `-Zs` (`P%`) |
249+| Max RSS | `XMB` | `YMB` | `-ZMB` (`P%`) |
250+| CPU user/sys | `X/Ys` | `A/Bs` | explain |
123251```
124252125253## Handoff
126254127255Keep the final concise:
128256129257- Root cause.
258+- Suite/plugin scope.
130259- Files changed.
131-- Before/after numbers.
260+- Before/after wall, Vitest/import, CPU, and RSS numbers where available.
261+- Leak classification if memory was involved: real leak, retained module graph,
262+ or inconclusive.
132263- Coverage retained.
133264- Verification commands.
265+- Testbox ID or workflow URL for remote proof.
134266- Commit hash and push status.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。