One of the common types of feedback we get about Firefox for Android is that it’s slow. Other browsers get the same feedback and it’s an ongoing struggle. I mean, is anything ever really fast enough?
We tend to separate performance into three categories: Startup, Page Load and UX Responsiveness. Lately, we have been focusing on the Page Load performance. We separate further into Objective (real timing) and Subjective (perceived timing). If something “feels” slow it can be just as bad as something that is measurably slow. We have a few testing frameworks that help us track objective and subjective performance. We also use Java, JavaScript and C++ profiling to look for slow code.
To start, we have been focusing on anything that is not directly part of the Gecko networking stack. This means we are looking at all the code that executes while Gecko is loading a page. In general, we want to reduce this code as much as possible. Some of the things we turned up include:
- Writing extra and/or redundant page information to the history database
- Saving session restore information too frequently
- Looking up Android system proxy information was slow
- Drawing unused view backgrounds
- Animating the pageload spinner consumed a lot of CPU cycles
- Extra messaging between the Java UI and Gecko
- Opportunities for predictive networking hints
Some of these were small improvements, while others, like the proxy lookups, were significant for “desktop” pages. I’d like to expand on two of the improvements:
Predictive Networking Hints
Gecko networking has a feature called Speculative Connections, where it’s possible for the networking system to start opening TCP connections and even begin the SSL handshake, when needed. We use this feature when we have a pretty good idea that a connection might be opened. We now use the feature in three cases:
- When a touch occurs on a link in web content, we speculatively connect to the HREF. Technically, we need to wait before really opening the link to make sure you didn’t really start panning the page or start a double-tap.
- When starting to type a URL in the titlebar, we load the current set of search engines. We speculative connect to the default search engine, since it’s somewhat probable that you will perform a search.
- When typing into the titlebar, Firefox tries to use domain autocompletion and searches your history for recent URLs. Both the current auto-completed URL and the top-most search result are speculatively connected.
Animating the Page Load Spinner
Firefox for Android has used the animated spinner as a page load indicator for a long time. We use the Android animation framework to “spin” an image. Keeping the spinner moving smoothly is pretty important for perceived performance. A stuck spinner doesn’t look good. Profiling showed a lot of time was being taken to keep the animation moving, so we did a test and removed it. Our performance testing frameworks showed a variety of improvements in both objective and perceived tests.
We decided to move to a progressbar, but not a real progressbar widget. We wanted to control the rendering. We did not want the same animation rendering issues to happen again. We also use only a handful of “trigger” points, since listening to true network progress is also time consuming. The result is an objective page load improvement the ranges from ~5% on multi-core, faster devices to ~20% on single-core, slower devices.
The progressbar is currently allowed to “stall” during a page load, which can be disconcerting to some people. We will experiment with ways to improve this too.
Install Firefox for Android Nightly and let us know what you think of the page load improvements.