Differential Revision: https://phabricator.services.mozilla.com/D115420
7.3 KiB
TimerFirings Loggings
TimerFirings logging is a feature built into Gecko that prints a line of data for every timer fired. This is useful because timer firings are a major cause of wakeups, which can cause high power consumption.
Note: The power profiling overview is worth reading at this point if you haven't already. It may make parts of this document easier to understand.
Invocation
TimerFirings logging uses Gecko's own logging mechanism, and so is able to be used in any build. Set the following environment variable to enable it.
NSPR_LOG_MODULES=TimerFirings:4
Output
Once enabled, TimerFirings will print one line of logging output per timer fired. It's best to redirect this output to a file.
The following sample shows the basics of this output.
-991946880[7f46c365ba00]: [6775] fn timer (SLACK 100 ms): LayerActivityTracker
-991946880[7f46c365ba00]: [6775] fn timer (ONE_SHOT 250 ms): PresShell::sPaintSuppressionCallback
-991946880[7f46c365ba00]: [6775] fn timer (ONE_SHOT 160 ms): nsBrowserStatusFilter::TimeoutHandler
-991946880[7f46c365ba00]: [6775] iface timer (ONE_SHOT 200 ms): 7f46964d7f80
-1340643584[7f46c365ec00]: [6775] obs timer (SLACK 1000 ms): 7f46a95a0200
Each line has the following information.
- The first two values identify the thread. This is not especially useful.
- The next value is the process ID (pid). This is useful in a multi-process scenario.
- Next is the timer kind, one of
fn
(function),iface
(interface) orobs
(observer), which are the three kinds of timers that Gecko supports. - Then comes the function kind, one of
ONE_SHOT
(a single-use timer),SLACK
orPRECISE
(repeating timers of differing precision). - Then comes the timer period, measured in milliseconds.
- Finally there is the identifying information for the timer. Function timers have an informative label. Interface and observer timers only have an address, which is less useful, but they are uncommon enough that this usually doesn't matter much.
The above example shows only timers from C++ within Gecko. There are
also timers for setTimer
or setInterval
calls in JavaScript code, as
the following sample shows.
-991946880[7f46c365ba00]: [6775] fn timer (ONE_SHOT 0 ms): [content] chrome://browser/content/tabbrowser.xml:1816:0
711637568[7f3219c48000]: [6835] fn timer (ONE_SHOT 100 ms): [content] http://edition.cnn.com/:5:7231
711637568[7f3219c48000]: [6835] fn timer (ONE_SHOT 100 ms): [content] http://a.visualrevenue.com/vrs.js:6:9423
These JS timers are annotated with [content]
and show the JavaScript
source location where they were created. They can come from chrome code
within Firefox, or from web content.
The informative labels are only present on function timers that have had their creation site annotated. For unannotated function timers, there are three possible behaviours.
First, on Mac the code uses dladdr
to get the name immediately, and
the output will look like the following.
2082435840[100445640]: [81190] fn timer (ONE_SHOT 8000 ms): [from dladdr] gfxFontInfoLoader::DelayedStartCallback(nsITimer*, void*)
Second, on Linux the code uses dladdr
to get the symbol library and
address, which can be post-processed by tools/rb/fix_stacks.py
. The
following two lines show the output before and after being
post-processed by that script.
2088737280[7f606bf68140]: [30710] fn timer (ONE_SHOT 16 ms): [from dladdr] #0: ???[/home/njn/moz/mi1/o64/dist/bin/libxul.so +0x2144f94]
2088737280[7f606bf68140]: [30710] fn timer (ONE_SHOT 16 ms): [from dladdr] #0: mozilla::RefreshDriverTimer::TimerTick(nsITimer*, void*) (/home/njn/moz/mi1/o64/layout/b
Third, on other platforms dladdr
is not implemented or doesn't work
well, and the output will look like the following.
711637568[7f3219c48000]: [6835] fn timer (ONE_SHOT 16 ms): ???[dladdr is unimplemented or doesn't work well on this OS]
The ???
indicates that the function timer lacks an explicit name, and
the comment within the square brackets explains why the fallback
mechanism wasn't used.
If an unannotated timer function appears frequently it is worth
explicitly annotating it so that it will be usefully identified on other
platforms. (Running on Mac or Linux is obviously necessary to learn the
timer function's name.) This is done by initializing it with
initWithNamedFuncCallback
or initWithNameableFuncCallback
instead of
initWithNameCallback
.
Post-processing
TimerFirings logging quickly produces thousands of lines of output. This
output needs post-processing for it to be useful. If the output is
redirected to a file called out
, then the following command will
pull out the timer-related lines, count how many times each unique line
appears, and then print them with the most common ones first.
cat out | grep timer | sort | uniq -c | sort -r -n
The following is sample output from this command.
204 801266240[7f7c1f248000]: [7163] fn timer (ONE_SHOT 50 ms): [content] http://widgets.outbrain.com/outbrain.js:20:330
135 -495057024[7f74e105ba00]: [7108] fn timer (ONE_SHOT 4 ms): [content] https://self-repair.mozilla.org/en-US/repair/:7:13669
118 801266240[7f7c1f248000]: [7163] fn timer (ONE_SHOT 100 ms): [content] http://a.visualrevenue.com/vrs.js:6:9423
103 801266240[7f7c1f248000]: [7163] fn timer (ONE_SHOT 50 ms): [content] http://static.dynamicyield.com/scripts/12086/dy-min.js?v=12086:3:3389
94 801266240[7f7c1f248000]: [7163] fn timer (ONE_SHOT 50 ms): [content] https://ad.double-click.net/ddm/adi/N7921.1283839CADREON.COM.AU/B9038144.122190976;sz=300x600;click=http://pixel.mathtag.com/click/img?mt_aid=2744535504761193354&mt_id=1895890&mt_adid=148611&mt_sid=973379&mt_exid=9&mt_inapp=0&mt_uuid=353d5460-19f6-4400-9bbd-d0fcc3bcf595&mt_3pck=http%3A//beacon-apac-hkg1.rubiconproject.com/beacon/t/d1f9921d-4e47-448f-b6ba-36cae1c31b65/&redirect=;ord=2744535504761193354?:83:0
94 801266240[7f7c1f248000]: [7163] fn timer (ONE_SHOT 160 ms): nsBrowserStatusFilter::TimeoutHandler
92 -495057024[7f74e105ba00]: [7108] fn timer (ONE_SHOT 160 ms): nsBrowserStatusFilter::TimeoutHandler
The first column shows how many times the particular line appeared.
It is sometimes useful to pre-process the output by stripping out certain parts of each line before doing this aggregation step, for example, by inserting one or more of the following commands into the command pipeline.
sed 's/^[^:]\+: //' # strip thread IDs
sed 's/\[[0-9]\+\] //' # strip process IDs
sed 's/ \+[0-9]\+ ms//' # strip timer periods
The following is the previous sample output with all three of these commands added into the pipeline.
204 fn timer (ONE_SHOT): [content] http://widgets.outbrain.com/outbrain.js:20:330
186 fn timer (ONE_SHOT): nsBrowserStatusFilter::TimeoutHandler
138 fn timer (ONE_SHOT): [content] https://self-repair.mozilla.org/en-US/repair/:7:13669
118 fn timer (ONE_SHOT): [content] http://a.visualrevenue.com/vrs.js:6:9423
108 fn timer (SLACK): LayerActivityTracker
104 fn timer (SLACK): nsIDocument::SelectorCache
104 fn timer (SLACK): CCTimerFired