Hello friends of gaia,
In bug 841972, we made the "real" startup time (as opposed to time to first paint) of the Music app about a second faster. How did we do that?
The first step of any performance work is to create a reproducible workload and reproducible measurement steps. Then gather baseline measurements, before any code changes are made. It seems obvious, but this allows you to measure if your changes actually improve what you're trying to improve.
The second step was to get a few profiles of the Music app starting up using the Gecko profiler [1]. An additional patch [2] was applied to get higher-resolution profile data. Generally, you want to use that patch when profiling short-lived events like startup, and *not* use the patch when profiling longer events like panning. The patch adds a lot of overhead (~10%) that can skew results.
A representative profile is [3]. It sometimes takes a bit of "art" to interpret these profiles, but in the case of the Music app there were a couple of obvious issues.
The samples in the range ~[4700, 4900] show Music "forcing sync reflows". The profiler UI shows a warning when this happens. Why is this sometimes bad? The reason is that Gecko is optimized to do expensive work like reflows in big batches, when needed. When web content forces gecko to do work on a different schedule, it can cause more work to be done than necessary.
The profile data shows a cropImage() function in Music causing these reflows. Inspection of the function showed that it was manually implementing the CSS rules |background-position: center; background-size: cover|. The reflows were being forced by that function when it read size values from the DOM. (This forces gecko to reflow synchronously if styles have changed.) Altering the Music app to use the native CSS support saved 300ms on startup.
The profile also shows a lot of work being related to image decoding. It's reasonable to guess that the amount of work done in startup to display images is proportional to the number of images. So we hypothesized that startup would be faster if we processed only the visible images first, and then later processed the hidden images.
This change was simple to make, and testing showed it improved startup by about a second.
What are the general guidelines we can extract from this specific work on the Music app?
1. Don't force gecko to do synchronous reflows if you can avoid it. (Sometimes it's not possible to avoid.) Relatedly, use CSS for implementing styling when possible, instead of using hand-written JS.
2. Prioritize work for user-perceived responsiveness. Users will "feel" like the app has loaded when the visible area stabilizes. They won't "feel" work done on hidden UI elements.
Cheers,
Chris
[1]
https://developer.mozilla.org/en-US/docs/Performance/Profiling_with_the_Built-in_Profiler#Profiling_Boot_to_Gecko_%28with_a_real_device%29
[2]
https://bugzilla.mozilla.org/attachment.cgi?id=706602
[3]
http://people.mozilla.com/~bgirard/cleopatra/#report=eca09de32d952dfe76869780237ca6a08f1db65e