<< All versions

Skill v1.0.0

currentAutomated scan100/100
keybase/client/electron-profile
──Details
PublishedOctober 22, 2026 at 10:33 PM
Content Hashsha256:2b112aae4470c293...
Git SHA369cec4e9b92
──Files
Files (1 file, 3.2 KB)
SKILL.md3.2 KBactive
SKILL.md · 47 lines · 3.2 KB

version: "1.0.0" name: electron-profile description: 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".


DevTools Performance Trace Analysis

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

  1. Overview — processes, busiest renderer main thread, long tasks (with time offsets), X-event category totals:

``bash python3 scripts/trace-overview.py <trace.json> [--long-ms 50] [--top 30] ``

  1. 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:

``bash 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.

SignalMeaning
Huge run (:-1) self time, createTask, measureReact 19 dev component-performance tracks: console.createTask().run() inside runWithFiberInDEV/logComponentRender. Not app code.
v8::Debugger::AsyncTaskRun dominating X-event totalsDebugger async-stack tracking (DevTools open). Dev artifact.
Effects firing twice back-to-backStrictMode double-invoke. Dev only.
90%+ samples with no app frame on stackExpected in dev — instrumentation + framework internals. Judge the app-frame report's relative ranking, not totals.
performSyncWorkOnRoot ≫ scheduler time in inclusive reportMost renders are sync (flushSync / discrete events), not concurrent. Structural signal — valid even in dev.
pptr:internal framesCDP automation harness driving the app, not app code (excluded from app-frame report).
Layout / Paint / GC / EventDispatch totals in overviewReal 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/...).
  • --window is relative to the first sample, not trace start; long-task t= offsets from the overview are relative to trace start. They usually differ by <1s but eyeball the sample span line.
  • Trace timestamps are microseconds.
All versions