DevTools Performance Trace Analysis
SkillProductivityLets your agent analyze Chrome performance traces to find slow renders, long tasks, and where CPU time goes.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the DevTools Performance Trace Analysis skill
About this capability
Use when analyzing a Chrome/Electron DevTools Performance trace export (.json) — slow renders, long tasks, jank, CPU sample attribution, "where is the time actually going".
What this skill tells your AI
The instructions your AI receives, as published by keybase/client in skill/electron-profile/SKILL.md and read by ahel’s review.
Parse DevTools Performance panel exports with Python scripts in scripts/ — no DevTools UI needed. A trace is one big JSON of traceEvents; a 400MB export loads in ~30s. The embedded sampling profile lives in Profile/ProfileChunk events.
Workflow
- Overview — processes, busiest renderer main thread, long tasks (with time offsets), X-event category totals:
python3 scripts/trace-overview.py <trace.json> [--long-ms 50] [--top 30] - Sample attribution — self time, inclusive time, and nearest-app-frame attribution from the CPU sampling profile. Use
--window(seconds, relative to first sample) to zoom into a long task found in step 1:python3 scripts/trace-samples.py <trace.json> [--window FROM_S TO_S] [--top 30]
Both auto-pick the busiest CrRendererMain; override with --pid/--tid. Both need scripts/tracelib.py alongside.
Interpreting results (dev builds especially)
Dev-build traces are ~85-90% React dev instrumentation, NOT app code. Absolute numbers are meaningless; prod is ~10x faster. For real numbers profile the prod bundle (see prod-bundles skill), or at minimum disable the React DevTools extension while recording.
| Signal | Meaning |
|---|---|
Huge run (:-1) self time, createTask, measure | React 19 dev component-performance tracks: console.createTask().run() inside runWithFiberInDEV/logComponentRender. Not app code. |
v8::Debugger::AsyncTaskRun dominating X-event totals | Debugger async-stack tracking (DevTools open). Dev artifact. |
| Effects firing twice back-to-back | StrictMode double-invoke. Dev only. |
| 90%+ samples with no app frame on stack | Expected in dev — instrumentation + framework internals. Judge the app-frame report's relative ranking, not totals. |
performSyncWorkOnRoot ≫ scheduler time in inclusive report | Most renders are sync (flushSync / discrete events), not concurrent. Structural signal — valid even in dev. |
pptr:internal frames | CDP automation harness driving the app, not app code (excluded from app-frame report). |
| Layout / Paint / GC / EventDispatch totals in overview | Real browser work — valid signal even in dev. Compare against script time. |
Judge structure, not magnitude in dev traces: sync-vs-concurrent split, Layout/Paint/GC share, which app components rank highest, burst patterns around long tasks.
Gotchas
- X-event name totals are nested-inclusive (parent contains child) — relative shape only, don't sum.
- Sample span < trace span is normal: sampling only covers the profiled window.
- App-frame attribution skips frames whose URL contains
node_modules— with Vite dev this automatically excludes React (node_modules/.vite/deps/...). --windowis relative to the first sample, not trace start; long-taskt=offsets from the overview are relative to trace start. They usually differ by <1s but eyeball the sample span line.- Trace timestamps are microseconds.
Signals
- GitHub stars
- 9k
- Forks
- 1k
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
electron-profile- Source
- github.com/keybase/client