Identifying the source of slow codepaths in the Chromium Profiler<!-- --> | <!-- -->Web Performance Tips

Identifying the source of slow codepaths in the Chromium Profiler

The Chromium Profiler produces incredibly useful visualizations via flamegraphs to help us understand what is consuming CPU time in thread tasks.

In this tip, we'll walk through how to map back to a codepath in your web application once you've found a region of interest in the profile.

Prerequisites

Step 1: Identify a Region in the Flamegraph

In your profiler UI, you should have a trace loaded of your web application.

For example, I've loaded up a trace that looks like this:

A screenshot of a trace loaded in the Chromium Profiler

Using my knowledge of flamegraph shapes, I notice that there's a high-frequency codepath being executed here:

A screenshot of a trace in the Chromium Profiler, with circled emphasis on some narrow repeated spikes

I am interested in what this high-frequency operation is in my application's code, so I can apply an optimization and reduce overall task time.

Step 2: Zooming to Region

Adjust your profiler selection to your region of interest.

In my case, I'm interested in one of those narrow spikes, so I'll go ahead and zoom into that:

A screenshot of a trace in the Chromium Profiler, zoomed into some narrow spikes.

Step 3: Selecting a Band

In the flamegraph of the spike, we see the o function at the tip of the spike, so that is where I'd likely start my investigation.

Production web apps utilize minification to reduce their payload size, so it's unlikely to see useful names in the profiler bands when tracing one.

In my case, I'd click the band of the o function, and reveal the script details in the Summary pane.

A screenshot in the Chromium Profiler of the o function selected.

Step 4: Select the Script

At the bottom, you'll see a blue link to the name of the script. Clicking this link will take you to the code file containing this function.

For example, if I click the clients-root-desktop-43f...js:27165, it will take me to that code file in the Sources pane.

A screenshot in the Chromium Profiler of the clients-root-desktop script in the Summary Pane.

Note: If you did not collect this profile yourself (i.e. it's been imported), then this won't work, but unfortunately, Chromium won't denote this when you try and click.

Step 5: Beautify in Sources

Once you have clicked your codepath, you'll get see the Sources pane open with a minified script.

In the bottom left, there's a very tiny button that will format this code nicely for you to inspect.

A screenshot in the Chromium Profiler of the minified Sources Pane.

Step 6: Observe Codepath

The codepath should be nicely formatted and you can inspect it:

A screenshot in the Chromium Profiler of the beautified sources in the Sources Pane.

Now we can see what our o function is actually doing!

If you or your team own the web application that you are profiling, the beautified-minified code should look familiar enough to map back to something in your codebase. If not, it could be a bundled dependency, so you may need to debug through the callstack to see how and when this code gets executed.

Step 7: Identify Inefficiencies

DOMParser.parseFromString

In this specific example, I see that o is being executed in high frequency. In addition, I can see that the o function is creating a new DOMParser object, and invoking parseFromString, which is a browser API, and often slow if run in high frequency:

A screenshot in the Chromium Profiler with the parseFromString called out in a flamegraph and in sources.

Loops and String Operations

I also see here that o invokes e, which invokes a lambda (the (anonymous) function), which invokes r and n:

A screenshot in the Chromium Profiler with the o, e, r, and n called out in a flamegraph and in sources.

Inspecting r and n, I see each of them is doing synchronous work, notably for loops and reduce with string trimming respectively. I scope to these function the same way I scoped to the o function in Step 4, except selecting r or n in the flamegraph.

A screenshot in the Chromium Profiler of n function in sources.

A screenshot in the Chromium Profiler of the r function in sources.

Both of these operations are synchronous, and although they are not heavy in isolation, the frequency at which they are run contributes to an overall bottleneck in this Task.

Conclusion

By utilizing flamegraphs and the technique we've outlined in this tip for code scoping, you can quickly identify which blocks of code are contributing to your CPU time on your thread.

Once you've identified a block of code in the Sources tab, you can map this back to your source code and apply an optimization!

Consider these tips:

That's all for this tip! Thanks for reading! Discover more similar tips matching Beginner and CPU.