ESC

Type to search the knowledge base.

Browser DevTools Performance Panel

Record main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.

intermediate4 min read
  • browser
  • devtools
  • performance
  • main-thread

The Performance panel answers: what occupied the main thread while the user waited? Lighthouse scores guess; a recording shows Recalculate Style, Layout, Paint, Evaluate Script, and long tasks.

Docs: Chrome Performance panel, Analyze runtime performance.

Capture a useful profile

  1. Enable Screenshots and Web Vitals markers when available.
  2. Start recording → reproduce the jank (click, type, scroll) → stop.
  3. Prefer a short focused interaction over a 30s mess.
  4. CPU 4× slowdown surfaces issues mid-tier phones feel.

Cold-load profiles differ from interaction profiles. For INP, record the actual click/tap path, not only initial load.

Anatomy

Region Meaning
Frames / FPS Dropped frames = jank
Main track Tasks on the main thread
Network Resources aligned in time
Timings FCP, LCP when instrumented
Bottom-up / Call tree Aggregated JS cost
Event log Ordered events

Long tasks (> ~50ms) block input and paint. Yellow/red bars are first suspects for poor INP.

Forced layout in the flame chart

// Bad: read geometry after writes in a loop
items.forEach((el) => {
  el.style.width = el.offsetWidth + 10 + 'px';
});

You will see Recalculate Style → Layout inside a loop. Fix: batch reads, then batch writes (or animate transform). See Avoiding layout thrashing.

Attribution for interactions

  1. Find the Event (click) on the main track.
  2. Measure input delay (main thread busy before handler).
  3. Measure handler duration.
  4. Measure presentation delay until next paint.

That maps to INP: delay → processing → next paint. See Event Timing for INP.

Marks you control

performance.mark('filter:start');
expensiveFilter(data);
performance.mark('filter:end');
performance.measure('filter', 'filter:start', 'filter:end');

Custom measures show up in the timeline and help separate framework cost from your code.

Filmstrip

Screenshots show when the UI actually changed. A long script with no visual update still hurts INP if it delays the next paint after input.

Workflow

  1. Reproduce with throttling.
  2. Identify longest tasks.
  3. Expand stacks to your functions first.
  4. Fix or yield; re-record.
  5. Confirm field metrics move — lab is directional.

Performance panel is not a heap snapshot; use Memory for leaks. GC pauses can appear as long tasks when allocation is wild.

Interview out-loud

“I record Performance, reproduce the interaction, find long tasks and forced layout, then split work or remove thrashing. Load-only Lighthouse doesn’t explain mid-session INP.”

Reading a click that “feels dead”

  1. Arm CPU 4× slowdown; start recording.
  2. Click the control once; wait for UI; stop.
  3. Find the Event: click — note the long task before processingStart if present (input delay).
  4. Expand the handler stack — is it your code or a third-party?
  5. Check whether the next paint occurs only after a massive style/layout on a large tree.

If the flame chart shows layout thrash, fix thrashing before micro-optimizing React memo. If it shows a 200ms third-party tag, gate the tag. Re-record after each change; don’t stack five “optimizations” without evidence.

Further depth

Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.

Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.

Further reading

Related guides