You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b6e660f
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
### Added
11
11
-**`traceperf run`:** starts an app with `traceperf/auto`, sends concurrent traffic (`--path`, `-c`, `-d`/`-n`, `--method`; warm-up requests first), then prints statistics and explanations. Without `--path`, use the app yourself and press Ctrl-C. Works with a script (`traceperf run server.js`) or any command (`traceperf run -- npm start`). `--html`, `--output`, `--json`.
12
+
-**Fix suggestions:** findings now say what to change (`fix` in `explain()` / `--json`, a `fix:` line in text, under each finding in HTML): `Promise.all` for sequential awaits, `WHERE id IN (...)` / DataLoader for N+1, the async API for `pbkdf2Sync`, `readFileSync` and Sync zlib, a worker thread or chunking for hot loops, `EXPLAIN ANALYZE` for a dominant query.
12
13
-**Evidence links in the HTML report:** the report now opens with the findings ("Why it was slow"); click one to highlight its time range on the flame chart (no scripts, works from disk). Each finding carries `evidence: { start, end, labels }` in `explain()` and `--json` output.
13
14
-**Known-slow example apps** (`examples/slow-apps/`): one planted cause each; a test checks that `explain` names it.
14
15
-**Blocking code is named even when untracked:**`traceperf run` (and `TRACEPERF_PROFILE_BLOCKING=1` with `traceperf/auto`) samples the CPU during the synchronous part of blocking calls, and `explain` names the function and line (`CPU time: buildReport (server.js:10) 100%`). Native work is named by the calling app function (`hashPassword → pbkdf2Sync`), code V8 inlined into its caller is credited to the inlined function, and garbage-collection pauses are reported as such.
expect(explain([seq]).find(f=>f.kind==='sequential')!.fix).toBe("if they don't depend on each other, start them together: await Promise.all([loadUser(), loadOrders()])");
return`move the CPU work in ${at} off the request path: a worker_threads Worker (e.g. a pool like piscina), split it into chunks with setImmediate, or cache its result`;
380
+
}
381
+
case'sequential': {
382
+
constnames=labels.slice(0,3);
383
+
if(!names.every(n=>/^[\w.$]+$/.test(n)))return`if they don't depend on each other, start them together with Promise.all instead of awaiting each in turn`;
384
+
return`if they don't depend on each other, start them together: await Promise.all([${names.map(n=>`${n}()`).join(', ')}${labels.length>3 ? ', ...' : ''}])`;
385
+
}
386
+
case'repeated': {
387
+
constlabel=labels[0]||'';
388
+
returnSQL.test(label)
389
+
? `load them in one query: WHERE id IN (...) (or = ANY($1) in Postgres), or your ORM's include/join; then match results in memory`
390
+
: `make one batched call instead of one per item (a bulk API, or DataLoader to collect the calls of one tick)`;
391
+
}
392
+
case'dominant':
393
+
// Outside tracked code: the message says what to do; waited: the blocking finding has the fix
394
+
if(f.message.includes('outside any tracked call')||f.message.includes('waiting for blocking code'))returnundefined;
395
+
returnSQL.test(labels[0]||'')
396
+
? `check this query's plan (EXPLAIN ANALYZE) and indexes, or cache its result`
397
+
: `that is where the time goes: track or profile inside ${labels[0]||'it'} next`;
? `<h2>Why it was slow</h2>\n<ol class="findings">\n${findingItems}\n</ol>\n<p class="meta">Click a finding to highlight its time range on the flame chart.</p>`
0 commit comments