It's time for another quick update about the recent Quantum Flow work.
I want to start by shedding some light into the performance of synchronous IPC caused by JavaScript. Here is a breakdown report for data as of today similar to the previous ones. Let's look at the top 10 worst offenders:
- All of the ones with names starting with Addons: or Content: are e10s compatibility shims that we have been using to make non-e10s compatible add-ons work with Firefox. They essentially make synchronous XPCOM APIs work using sync IPC across process boundaries. This is by far the majority of the issue here, and it skews all sorts of performance measurements that we do on Nightly. We're soon going to make changes to Nightly to disable running non-e10s compatible extensions so that we get better performance data.
- The second one is AdblockPlus:Message which presumably comes from one of the the Adblock Plus extension variants. What's curious about this one is the super high count of the messages, the median time isn't that high. And that the submission percentage is 100%!!
- #9 is contextmenu.
Looking through more of these messages, there are a few more that stem from our code. It's a bit hard to spot everything due to everything being mixed together. After traditional style extensions aren't loaded any more a lot of these issues will go away but it also makes things difficult to evaluate when looking at the data. This is also solid practical data that can be used as input to API design in the future, on why some functionality such as sync IPC is very dangerous to be exposed at the API level in the first place! Moving to a more modern extension model is really good for performance from this perspective.
The next topic I wanted to discuss was the issue of the usage of timers in our code. Timers are terrible for responsiveness and are almost never what you want. We sometimes use them to lazify some work (do this part of the initialization in 10 seconds!) or to do some periodic background task (refresh this cache every second) but they cause a lot of problems due to the fact that they can execute at unpredictable times. From the perspective of improving the responsiveness of Firefox, if your goal is to keep the main thread as free as possible when the user's input events are about to be handled, the last thing you want is to start running one of these timers right before the user clicks or types or something like that. Gecko now supports the requestIdleCallback API which allows the caller to request a timer that only gets dispatched when the application is idle. Where possible, you should consider re-examining the timers in your areas of the code and consider using to idle dispatch where appropriate. Note that this API is currently only available to contexts where the Window object is available. Bug 1358476 is adding the functionality to nsThread and hopefully we can expose it to JSMs afterwards as well.
On to the list of the acknowledgements for the week. As usual, I hope I'm not forgetting anyone's names here!
- Kevin Jones’ heroic work on moving session restore to restore tabs using lazy-browsers finally landed. He tried out a nice idea to improve the performance of restoring a session as the Virtual Tabs add-on, and then he started to take a stab at converting the add-on into a patch for Firefox!
- Tim Taubert's work as of a few weeks ago around improving the performance of the session restore data collection times has heavily paid off so far. This chart speaks for itself.
- Ben Tian used a pref cache instead of reading preferences repeatedly, potentially incurring expensive hashtable lookups.
- Thomas Nguyen did the same for the URLClassifier code.
- Gijs Kruitbosch prevented reading the full MIME type info from the OS just to get the mimetype string for an extension. The former had proved to be very expensive.
- Dão Gottwald removed the FullZoomUI overhead when closing a window. He also removed an unnecessary layout flush from Window.outerWidth and outerHeight. This is the Oh No! Reflow add-on helping the Web! :-)
- Sam Foster removed a synchronous layout flush that used to occur every time a window would be activated/deactivated.
- Olli Pettay tracked down and fixed a memory leak regression caused by touch events which would result in many ghost windows, manifesting as long cycle collector pauses. This was a really tricky regression that took a few days to track down and it was caused by a simple programming mistake. Nika Layzell is working on a static analysis to ensure that this class of memory leaks will never happen, ever again, because we all have better things to do with our time than track bugs like this.
- Jon Coppeard enabled incremental sweeping of foreground JavaScript objects. These are objects with the JSCLASS_FOREGROUND_FINALIZE JSClass flag, the most common example includes the JS wrapper objects for WebIDL DOM objects.
- Marco Bonardo enabled high-res favicons and in the process won us ~30% improvement on the tp5n nonmain_normal_fileio benchmark.
- Tom Schuster enabled caching index values in JS strings, to optimize cases where JS strings such as “1” are used as an index into an array to speed up the string-to-int conversions.
- Steve Fink fixed a Gecko Profiler specific overhead that would inflate the cost of GCs artificially.
- Nicholas Nethercote fixed capturing startup profiles with the Gecko Profiler.
- Gerald Squelart removed another sync IPC used early during the startup of the content process.
- Samael Wang reworked tab ID calculation to rely on both processes agreeing on a formula rather than sync IPC.
- Florian Quèze improved the performance of the search engine URL generation in the ParamSubstitutions function. He also removed a synchronous layout flush that used to happen when opening the searchbar panel for the first time. He also removed the cost of a non-existent notification which apparently was taking 8% of _delayedStartup() in a profile. Last but not least, he mechanically replaced the usage of all (function(args){/code/}).bind(this) with the faster arrow functions from our chrome JS code.
- Kris Maglione prevented us from doing a synchronous layout flush when computing tab geometry.
- André Bargull enabled us to syntax-parse destructuring JS patterns. This optimization improves things for us right now for chrome JS code that uses the destructuring patterns feature.
- JW Wang made the channel loading click-to-play media marked as urgent priority.
- Andrea Marchesini removed some of the Blob related sync IPC messages as part of his PBlob refactoring.
- Mike Conley removed the reader mode promotion panel. This feature would cause a visible UI jank shortly after starting Firefox for the first time.
- Jan de Mooij moved ProxyValueArray inline instead of being dynamically allocated.
- Nicholas Hurley made the work under PredictorLearn() which gets called when opening Necko channels happen asynchronously.
- Chris H-C made several improvements to the INPUT_EVENT_RESPONSE_MS probe, most importantly making sure we don't get inflated results when the computer comes out of sleep mode.