⚡ Web performance

The DevTools Performance panel: reading a profile step by step

How to record a profile in Chrome DevTools, read tracks, flame charts and long tasks, and get from a slowdown to the line of code responsible for it.

Lighthouse and Core Web Vitals reports tell you what is slow; the Performance panel in Chrome DevTools tells you why. It records everything the browser does over a span of time, from network requests to the execution of every JavaScript function, from style calculation to painting pixels. At first sight the screen is intimidating, but learning to read just a few parts of it is enough to diagnose most problems.

Preparing a reliable recording

A useful measurement needs a few precautions:

  1. an incognito window or clean profile: browser extensions run code in the page and pollute the profile;
  2. CPU throttling: in the panel settings you can slow the CPU down 4 or 6 times to approximate a mid-range phone. A problem invisible on a powerful laptop becomes obvious;
  3. network throttling, if you are studying loading;
  4. screenshots enabled, to see what appears on screen at each moment.

To analyse loading, use the button that reloads the page and records until it finishes. For an interaction, start recording, perform the action, for example opening a menu, and stop right after: short recordings are much easier to read.

The main tracks

The profile is organized in horizontal rows, called tracks, sharing the same timeline:

Track What it shows
Screenshots Page thumbnails over time
Network Requests, like a compact waterfall
Frames Frames produced and frames dropped
Interactions User interactions and their duration
Timings Markers such as FCP, LCP and custom measures
Main All main-thread work
Workers and other threads Work done off the main thread

The Main track is where you spend most of your time.

Reading the flame chart

In the Main track, work is drawn as a flame chart: each bar is an activity, its width is the duration and the bars beneath it are the functions called by the one above. At the top are tasks, the browser's units of work; below are events, functions and sub-functions.

Tasks longer than 50 milliseconds have a red triangle in the corner and a hatched area highlighting the excess. They are the first to look at, because during a long task the page cannot respond to the user.

Colours help you find your way: yellow for scripting, purple for style calculation and layout, green for painting and compositing. A task that is mostly purple points to a CSS or DOM problem, not a JavaScript one.

From task to cause

The method I use in my work is always the same:

  1. I find the long task closest to the problem, for example right after the click in the Interactions track;
  2. I select it and read the Summary pane, which splits the time by category;
  3. I go down the flame chart to the widest bars at the bottom: those are the functions really consuming the time;
  4. I select the function and, in the detail pane, find the file and line, clickable to open the source;
  5. if it is a third-party script, the domain name gives it away immediately.

For an aggregate view, use the tabs at the bottom:

  • Bottom-Up lists functions sorted by self time, that is excluding sub-calls: it reveals the functions that cost the most wherever they are called from;
  • Call Tree shows the call tree from the top, useful for understanding which event handler started the work;
  • Event Log lists activities in chronological order.

In Bottom-Up you can also group by domain or by file, getting each third party's share of time in one go.

Patterns to recognize

Some patterns come up often:

  • many purple bars alternating with yellow ones in a loop: forced reflows, i.e. reads of DOM geometry after changes. DevTools flags them with a warning on the layout entry;
  • a single huge yellow block at startup: evaluation of a very large JavaScript bundle or a framework's hydration;
  • long Recalculate Style bars after a click: a class change on an element high in the hierarchy forcing styles to be recalculated for the whole page;
  • frequent garbage collection work: excessive creation of temporary objects, sometimes a sign of a memory leak.

Custom measures

To follow specific portions of your own code, the User Timing API lets you create markers that appear in the Timings track:

performance.mark('filter-start');
applyFilters();
performance.mark('filter-end');
performance.measure('Applying filters', 'filter-start', 'filter-end');

The measure appears as a bar with its own name, aligned with main-thread work, and it can also be collected from real users with a PerformanceObserver.

Saving and sharing

A profile can be exported to a file and reopened later, or sent to a colleague. It is the best way to document a problem: instead of "the menu is slow", you hand over the recording with the offending task already identified.

In short

  • Record in a clean profile, with CPU throttling and short recordings.
  • The Main track shows main-thread work as a flame chart.
  • Tasks with the red triangle are the first to analyse.
  • Go down to the widest bars at the bottom and open the file and line from the detail pane.
  • Use Bottom-Up for the costliest functions and User Timing for custom measures.
MM
Marco Marzaduri

Marco Marzaduri works in cybersecurity, digital forensics and web development. A computer science graduate, he combines rigorous technical analysis with attention to the people who use technology.

Read also