This tool is new in Firefox 34.
The columns in the sampling profiler were expanded and renamed in Firefox 35: this page describes the new column names.
The Performance tool is the replacement for the JavaScript sampling profiler. It includes an updated version of the sampling profiler, but adds a frame rate timeline to help gauge responsiveness. We intend to add more features in future releases.
Opening the Performance tool
You can launch the Performance tool by selecting "Performance" from the "Web Developer" menu. You'll find the "Web Developer" menu under the "Tools" menu on Linux and OS X, and directly under the "Firefox" menu on Windows. Alternatively, Shift + F5 will open the tool.
Creating profiles
To start recording a new profile click the stopwatch icon. Click it again to finish recording. The profile will immediately be opened. You can save the profile as a JSON file and import saved profiles. The sidebar on the left lets you switch between multiple open profiles.
Analysing profiles
A profile looks something like this:
It consists of four main sections layered horizontally:
- a set of breadcrumbs that you can use to zoom in and out
- a frame rate timeline
- a timeline for platform code execution
- the detailed output of the JavaScript sampling profiler
The frame rate timeline
The frame rate timeline gives you an overview of the browser's responsiveness in the period covered by the profile.
A frame encapsulates the work the browser needs to do in order to repaint in response to some event. For example, if moving the mouse over some page element triggers some JavaScript that changes the element's appearance, and that triggers a reflow and a repaint, then all this work needs to be completed in that frame. If it takes too long for the browser to process the frame, then the browser will appear unresponsive (janky).
The Performance tool takes a timestamp when the browser finishes a frame, and uses this to keep track of the frame rate:
The x-axis is time over the profile period, and there are three annotations: the target frame rate (always 60 frames per second), the average frame rate, and the lowest frame rate.
Platform code execution
This gives you an overview of code execution in the period covered by the profile. As with the frame rate timeline, the x-axis represents time over the profiling period, and the samples are laid out as vertical bars in the order they were taken, left to right:
The height of each bar represents the depth of the call stack at this point.
The Performance tool examines the call stack and figures out the sorts of things the JavaScript code is doing, and divides the bar into colors accordingly:
Network | Sending and processing network requests and responses |
JIT | JavaScript code compilation |
GC | Garbage collection |
Inputs & events | Events such as mouse or DOM events |
Styles | Parsing CSS |
Graphics | Includes handling reflows and repaints as well as WebGL |
Storage | Most often this is IndexedDB |
Gecko | Everything that doesn't fit into any of the other categories |
Hovering over the color key for a given category fades all the other categories:
This view lines up with the frame rate timeline, so you may be able to correlate slow frame rates with particular JavaScript operations.
Note that this shows everything the platform is doing, not just your own code.
JavaScript sampling profiler
The profiler periodically samples the state of the JavaScript engine, and records the stack for the code executing at the time the sample was taken. Statistically, the number of samples taken in which we were executing a particular function corresponds to the amount of time the browser is spending executing it, so you can identify bottlenecks in your code.
For example, consider a program like this:
function doSomething() { var x = getTheValue(); x = x + 1; // -> A (from the top level) logTheValue(x); } function getTheValue() { return 5; // -> B (from doSomething()) } function logTheValue(x) { // -> C (from doSomething()) // -> D (from doSomething()) // -> E (from the top level) console.log(x); } doSomething(); logTheValue(6);
Suppose we run this program with the profiler active, and in the time it takes to run, the profiler takes five samples, as indicated in the inline comments above.
Four are taken from inside doSomething()
. Of those, A
is directly inside doSomething()
. B
is inside getTheValue()
, and C
and D
are inside logTheValue()
. Finally, the program makes a call to logTheValue()
from the top level, and we get a sample there, too. So the profile would consist of five stack traces, like this:
Sample A: doSomething() Sample B: doSomething() > getTheValue() Sample C: doSomething() > logTheValue() Sample D: doSomething() > logTheValue() Sample E: logTheValue()
This obviously isn't enough data to tell us anything, but with a lot more samples we might be able to conclude that logTheValue()
is the bottleneck in our code.
Profile structure
The sampling profiler's details pane looks something like this:It presents the samples collected as a table.
Samples |
The number of samples that were taken in which the corresponding "Function" appeared in the call stack. For example, given the profiling example above, the corresponding "Samples" and "Functions" columns would look like: 4 doSomething() 2 > logTheValue() 1 > getTheValue() 1 logTheValue() Note that |
Function | This includes the function name, source file, line number and domain that served the file. Clicking on the file name takes you to that file in the Debugger. |
Total Cost | A direct translation of the "Samples" column into a percentage. |
Self Cost |
The "Samples" column includes not only samples that were taken while the JavaScript engine was executing this function, but also samples taken while executing functions called by this function. For example, in the example above we record 4 samples for "Self Cost" is the number of samples taken while the JavaScript engine was actually executing this function, translated into a percentage. In the example above, the "Self Cost" for |
Total Time |
A statistical estimate of the amount of time spent inside the function, given the number of samples that were taken in it. This value is derived from "Samples" but is not a direct translation, because we don't always take samples at exactly the right time, so we attempt to correct for this irregularity. |
Self Time |
A statistical estimate of the amount of time spent executing the function, exclusive of any functions called by this function. Just as "Total Time" is not a direct translation of "Samples", so "Self Time" is not a direct translation of "Self Cost". |
For a deeper look into the way the sampling profiler presents data, see this walkthrough of a profile.
Inverting the call tree
New in Firefox 36
By default, the profiler shows you the call tree from the root to the leaves, like a normal call stack. That is, from each top-level function to the functions it calls, then to the functions they call, and so on:
4 doSomething() 2 > logTheValue() 1 > getTheValue() 1 logTheValue()
This seems logical as it's the temporal order in which the stack is built up, and it's also conventional to represent a call stack in that way. However, often the places where you're spending time are deep in the call tree. So when you look at a profile you'll often click through many higher-level functions with a low "Self Cost", and it can be hard to see the places you're actually spending most of the time.
From Firefox 36 there's a new checkbox in the profiler labeled "Invert Call Tree". If you select this option, the profiler:
- makes a list of all functions with a Self Cost greater than zero: that is, functions which were actually executing when the sample was taken
- orders the list by the number of samples taken while in that function
- for each entry in the list, shows the call stack backwards to the top-level function.
This is usually a more effective way to highlight where your code is spending its time.
Zooming in
Clicking on a row highlights all the samples in the timeline view in which this function appears:If you hover over a row you'll see a magnifying glass at the right-hand end of it. Clicking the magnifying glass makes that row the root: that is, it presents the entire profile as if only that row and the rows underneath it exist:
Note that this also zooms in on the section of the profile in which these samples were taken.
Zooming in
If you click and drag in either the frame rate timeline or the sampling profiler timeline, then:
- a section of the timeline is highlighted
- the sampling profiler details view now shows only samples that were recorded in that section
- you'll see a "+" appear in the toolbar at the top:
Click the "+", and the highlighted section is expanded to fill the timeline. The toolbar at the top now shows the section as a separate breadcrumb:
You can switch between the complete profile and the section using the breadcrumbs. You can also zoom in on a subsection within the section, and that will then appear as a third breadcrumb in the toolbar: