Skip to content

Commit 76ba919

Browse files
branchseerclaude
andcommitted
style: format performance.md tables with oxfmt
Align markdown table columns per oxfmt formatting rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0862a93 commit 76ba919

1 file changed

Lines changed: 58 additions & 55 deletions

File tree

performance.md

Lines changed: 58 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ Timestamps are relative to process start (microseconds).
4141

4242
### Breakdown (6 invocations, vibe-dashboard, Ubuntu)
4343

44-
| Stage | Time from start | Duration |
45-
|---|---|---|
46-
| argv0 processing | 37-57μs | ~40μs |
47-
| Runtime resolution start | 482-684μs | ~500μs |
48-
| Node.js version selected | 714-1042μs | ~300μs |
49-
| LTS alias resolved | 723-1075μs | ~10μs |
50-
| Version index cache check | 1181-1541μs | ~400μs |
51-
| Node.js version resolved | 1237-1593μs | ~50μs |
52-
| Node.js cache confirmed | 1302-1627μs | ~50μs |
53-
| **oxc_resolver start** | **3058-7896μs** ||
54-
| oxc_resolver complete | 3230-8072μs | **~170μs** |
55-
| Delegation to Node.js | 3275-8160μs | ~40μs |
44+
| Stage | Time from start | Duration |
45+
| ------------------------- | --------------- | ---------- |
46+
| argv0 processing | 37-57μs | ~40μs |
47+
| Runtime resolution start | 482-684μs | ~500μs |
48+
| Node.js version selected | 714-1042μs | ~300μs |
49+
| LTS alias resolved | 723-1075μs | ~10μs |
50+
| Version index cache check | 1181-1541μs | ~400μs |
51+
| Node.js version resolved | 1237-1593μs | ~50μs |
52+
| Node.js cache confirmed | 1302-1627μs | ~50μs |
53+
| **oxc_resolver start** | **3058-7896μs** | |
54+
| oxc_resolver complete | 3230-8072μs | **~170μs** |
55+
| Delegation to Node.js | 3275-8160μs | ~40μs |
5656

5757
### Key Observations
5858

@@ -67,11 +67,11 @@ Measured from NAPI-side Chrome traces (frm-stack project).
6767

6868
The NAPI `run()` function is first called at **~3.7ms** from Node.js process start:
6969

70-
| Event | Time (μs) | Notes |
71-
|---|---|---|
72-
| NAPI `run()` entered | 3,682 | First trace event from NAPI module |
73-
| `napi_run: start` | 3,950 | After ThreadsafeFunction setup |
74-
| `cli::main` span begins | 4,116 | CLI argument processing starts |
70+
| Event | Time (μs) | Notes |
71+
| ----------------------- | --------- | ---------------------------------- |
72+
| NAPI `run()` entered | 3,682 | First trace event from NAPI module |
73+
| `napi_run: start` | 3,950 | After ThreadsafeFunction setup |
74+
| `cli::main` span begins | 4,116 | CLI argument processing starts |
7575

7676
This means **Node.js startup + ES module loading + NAPI binding initialization takes ~3.7ms**.
7777

@@ -112,13 +112,13 @@ From Chrome trace, all times in μs from process start:
112112

113113
The **`load_user_config_file`** callback (which calls back into JavaScript to load `vite.config.ts` for each workspace package) dominates the task graph loading time:
114114

115-
| Config Load | Duration | Notes |
116-
|---|---|---|
117-
| First package | **164ms** | Cold import: requires JS module resolution + transpilation |
118-
| Second package | **12ms** | Warm: shared dependencies already cached |
119-
| Third package | **3.4ms** | Warm: nearly all deps cached |
120-
| Fourth package (different deps) | **741ms** | Cold: imports new heavy dependencies |
121-
| Subsequent packages | **3-5ms** each | All warm |
115+
| Config Load | Duration | Notes |
116+
| ------------------------------- | -------------- | ---------------------------------------------------------- |
117+
| First package | **164ms** | Cold import: requires JS module resolution + transpilation |
118+
| Second package | **12ms** | Warm: shared dependencies already cached |
119+
| Third package | **3.4ms** | Warm: nearly all deps cached |
120+
| Fourth package (different deps) | **741ms** | Cold: imports new heavy dependencies |
121+
| Subsequent packages | **3-5ms** each | All warm |
122122

123123
**For frm-stack (10 packages), total config loading: ~930ms** — this is the single largest cost.
124124

@@ -139,31 +139,31 @@ The `js_resolver` callback (which locates the test runner binary via JavaScript)
139139

140140
### Session Init Timing Comparison
141141

142-
| Stage | frm-stack (10 packages) | Notes |
143-
|---|---|---|
144-
| Session init | ~60μs | Minimal setup |
145-
| load_package_graph | ~4ms | Workspace discovery |
146-
| load_user_config_file (all) | **~930ms** | JS callbacks, dominant cost |
147-
| handle_command + resolve | ~1.4ms | Tool binary resolution |
148-
| **Total before task execution** | **~936ms** | |
142+
| Stage | frm-stack (10 packages) | Notes |
143+
| ------------------------------- | ----------------------- | --------------------------- |
144+
| Session init | ~60μs | Minimal setup |
145+
| load_package_graph | ~4ms | Workspace discovery |
146+
| load_user_config_file (all) | **~930ms** | JS callbacks, dominant cost |
147+
| handle_command + resolve | ~1.4ms | Tool binary resolution |
148+
| **Total before task execution** | **~936ms** | |
149149

150150
## Phase 4: Task Execution (vibe-dashboard)
151151

152152
### Spawn Timing (First Run — Cold)
153153

154-
| Command | Spawn 1 (setup) | Spawn 2 (execution) | Total |
155-
|---|---|---|---|
156-
| `vp fmt` | 1.05s (977 reads, 50 writes) | 1.00s (163 reads, 1 write) | ~2.1s |
157-
| `vp test` | 0.96s (977 reads, 50 writes) | 5.71s (4699 reads, 26 writes) | ~6.7s |
154+
| Command | Spawn 1 (setup) | Spawn 2 (execution) | Total |
155+
| -------------- | ---------------------------- | ----------------------------- | ----- |
156+
| `vp fmt` | 1.05s (977 reads, 50 writes) | 1.00s (163 reads, 1 write) | ~2.1s |
157+
| `vp test` | 0.96s (977 reads, 50 writes) | 5.71s (4699 reads, 26 writes) | ~6.7s |
158158
| `vp run build` | 0.95s (977 reads, 50 writes) | 1.61s (3753 reads, 17 writes) | ~2.6s |
159159

160160
### Spawn Timing (Second Run — Cache Available)
161161

162-
| Command | Spawn 1 (setup) | Spawn 2 (execution) | Total | Delta |
163-
|---|---|---|---|---|
164-
| `vp fmt` | 0.95s (977 reads, 50 writes) | 0.97s (167 reads, 3 writes) | ~1.9s | -0.2s |
165-
| `vp test` | 0.95s (977 reads, 50 writes) | 4.17s (1930 reads, 4 writes) | ~5.1s | **-1.6s** |
166-
| `vp run build` | 0.96s (977 reads, 50 writes) | **cache hit (replayed)** | ~1.0s | **-1.6s** |
162+
| Command | Spawn 1 (setup) | Spawn 2 (execution) | Total | Delta |
163+
| -------------- | ---------------------------- | ---------------------------- | ----- | --------- |
164+
| `vp fmt` | 0.95s (977 reads, 50 writes) | 0.97s (167 reads, 3 writes) | ~1.9s | -0.2s |
165+
| `vp test` | 0.95s (977 reads, 50 writes) | 4.17s (1930 reads, 4 writes) | ~5.1s | **-1.6s** |
166+
| `vp run build` | 0.96s (977 reads, 50 writes) | **cache hit (replayed)** | ~1.0s | **-1.6s** |
167167

168168
### Key Observations
169169

@@ -175,11 +175,11 @@ The `js_resolver` callback (which locates the test runner binary via JavaScript)
175175

176176
vite-task implements a file-system-aware task cache at `node_modules/.vite/task-cache`.
177177

178-
| Command | First Run | Cache Run | Cache Hit? | Savings |
179-
|---|---|---|---|---|
180-
| `vp fmt` | 2.1s | 1.9s | No ||
181-
| `vp test` | 6.7s | 5.1s | No | -1.6s (OS cache) |
182-
| `vp run build` | 2.6s | 1.0s | **Yes** | **-1.6s** (1.19s from task cache) |
178+
| Command | First Run | Cache Run | Cache Hit? | Savings |
179+
| -------------- | --------- | --------- | ---------- | --------------------------------- |
180+
| `vp fmt` | 2.1s | 1.9s | No | |
181+
| `vp test` | 6.7s | 5.1s | No | -1.6s (OS cache) |
182+
| `vp run build` | 2.6s | 1.0s | **Yes** | **-1.6s** (1.19s from task cache) |
183183

184184
**Only `vp run build` was cache-eligible.** Formatting and test commands are not cached (side effects / non-deterministic outputs).
185185

@@ -250,34 +250,37 @@ T+940ms Task execution starts (child process spawn)
250250

251251
## Summary of Bottlenecks
252252

253-
| Bottleneck | Time | % of overhead | Optimization opportunity |
254-
|---|---|---|---|
255-
| vite.config.ts loading (cold) | **164-741ms** per package | **99%** | Cache config results, lazy loading, parallel loading |
256-
| Spawn 1 (pnpm/setup) | **~1s** || Persistent process, avoid re-resolving |
257-
| load_package_graph | **~4ms** | <1% | Already fast |
258-
| Session init | **~60μs** | <0.01% | Already fast |
259-
| Global CLI overhead | **~5ms** | <0.5% | Already fast |
260-
| Node.js + NAPI startup | **~3.7ms** | <0.4% | Already fast |
261-
| oxc_resolver | **~170μs** | <0.02% | Already fast |
262-
| js_resolver callback | **~1.25ms** | <0.1% | Already fast |
253+
| Bottleneck | Time | % of overhead | Optimization opportunity |
254+
| ----------------------------- | ------------------------- | ------------- | ---------------------------------------------------- |
255+
| vite.config.ts loading (cold) | **164-741ms** per package | **99%** | Cache config results, lazy loading, parallel loading |
256+
| Spawn 1 (pnpm/setup) | **~1s** | | Persistent process, avoid re-resolving |
257+
| load_package_graph | **~4ms** | <1% | Already fast |
258+
| Session init | **~60μs** | <0.01% | Already fast |
259+
| Global CLI overhead | **~5ms** | <0.5% | Already fast |
260+
| Node.js + NAPI startup | **~3.7ms** | <0.4% | Already fast |
261+
| oxc_resolver | **~170μs** | <0.02% | Already fast |
262+
| js_resolver callback | **~1.25ms** | <0.1% | Already fast |
263263

264264
**The single most impactful optimization would be caching or parallelizing `load_user_config_file` calls.** The first cold load takes 164ms, and when new heavy dependencies are encountered, loads can take 741ms. For a 10-package monorepo, this accumulates to ~930ms of config loading before any task runs.
265265

266266
## Inter-Process Communication
267267

268268
vite-task uses Unix shared memory (`/dev/shm`) for parent-child process communication during task execution:
269+
269270
- Creates persistent mapping at `/shmem_<hash>`
270271
- Maps memory into address space for fast IPC
271272
- Cleaned up after spawn completion
272273

273274
## Known Issues
274275

275276
### Windows: Trace files break formatter
277+
276278
When `VITE_LOG_OUTPUT=chrome-json` is set, trace files (`trace-*.json`) are written to the project working directory. On Windows, `vp fmt` picks up these files and fails with "Unterminated string constant" because the trace files contain very long PATH strings.
277279

278280
**Recommendation**: Add `trace-*.json` to formatter ignore patterns, or write trace files to a dedicated directory outside the workspace.
279281

280282
### NAPI trace files empty for some projects
283+
281284
The Chrome tracing `FlushGuard` stored in a static `OnceLock` is never dropped when `process.exit()` is called. Fixed by adding `shutdownTracing()` NAPI function called before exit (commit `72b23304`). Some projects (frm-stack) produce traces because their exit path differs.
282285

283286
## Methodology

0 commit comments

Comments
 (0)