How are we improving Firefox snap performance? Part 1
by Oliver Smith on 26 May 2022
Ubuntu Desktop aims to deliver an open source operating system, available to everyone that just works for whatever they need. With Ubuntu 22.04 LTS, we believe we’ve come closer than ever to achieving that goal. However, as always, there are still a number of areas we want to improve to deliver the highest quality user experience. One of those areas is our default browser, Firefox, which transitioned to being distributed as a snap with Ubuntu 21.10.
To understand this decision, I want to focus on the ‘just works’ part of my opening statement. The Firefox snap offers a number of benefits to daily users of Ubuntu as well as a range of other Linux distributions. It improves security, delivers cross-release compatibility and shortens the time for improvements from Mozilla to get into the hands of users.
Currently, that decision has trade-offs when it comes to performance, most notably in Firefox’s first launch after a system reboot. A part of this is due to the inherent nature of sandboxing, however we feel there is still significant opportunity to improve start-up times across the board. We want to share the results of some of those investigations today, as well as highlight some recent meaningful changes in this area
This is an ongoing journey, and this blog article will be the first in a series as we update you on our progress.
Ultimately, the real test will be how you, the user, experience these updates as they land. At the end of this post, we’ve put together some tools to help you keep track of the snap performance on your own machines.
For a deeper dive into the topics raised on this post, check out our recent Ubuntu Desktop Team Indaba, which was dedicated to discussing the Firefox snap experience
Let’s dive right in.
Why did we choose to make Firefox a snap?
This decision was made in collaboration with Mozilla based on the quality of life improvements that snap delivers:
- Confinement: snaps add an extra security layer on top of the browser’s already-robust sandboxing mechanism. The browser sandbox protects the browser against malicious code, whilst the snap confinement protects the user from the browser acting in ways that it shouldn’t.
- Effortless updates: browsers receive frequent updates and, with the snap, users are able to receive security patches from Mozilla more quickly than with other software distribution methods.
- Authenticity: Whilst Canonical builds the snap, it is published and maintained by Mozilla. This is Firefox straight from the source, directly to users, without the overhead of keeping build dependencies up to date.
- Cross-release compatibility: If your distro runs snapd, it can run the Firefox snap, from Ubuntu to the official flavours and beyond. It also means that older releases get the latest updates without additional maintenance.
Let’s talk about performance
We can divide our performance analysis into three specific areas:
- Cold start performance: This refers to the time taken when Firefox is booted for the first time after a system restart (or in the worst-case scenario after a completely fresh install). This is where the Firefox snap performance is most noticeable and is our primary area of focus. Whilst a cold start will be the least frequent action for typical users, first impressions matter!
- Warm start performance: This is Firefox startup on subsequent runs. Since the cold start caches a lot of data, this is a lot faster and much closer to our expected performance.
- Runtime performance: This represents performance during active usage of Firefox whilst it’s running. We’ve recently introduced some fixes that have significantly improved this experience, detailed later in the post.
Our current focus is on the cold start performance and we’ve been following a similar approach to our work on the Chromium snap to isolate the root causes.
Cold Start Performance
What do we mean by cold start?
When we talk about “cold start” we mean without any libraries loaded into memory. Essentially running Firefox right after a reboot, where the profile already exists on disk.
What do we mean by cold – purge?
A “cold start after purge” means without any caches, nothing in memory, and no profile created. When an app initialises, various things are created in memory and on disk and a ‘cold – purge’ is essentially the worst-case scenario. This is basically what you have after a fresh install of Ubuntu, but we can simulate that by purging the snap and rebooting
In practice this is done by running:
sudo snap remove --purge firefox
This removes the snap and all snap data, including your Firefox profile and caches
Reboot and login. Then run:
sudo snap install firefox
Click the Firefox icon and wait for the window to appear to get your cold – purge time.
Example Benchmarks
2019 Dell XPS 13 stable – rev 1377 (s) | Thinkpad X240 stable – rev 1377 (s) | Pi 400 (SD card) stable – rev 1381 (s) | |
---|---|---|---|
Cold – Purge | 7.67 | 15.07 | 38.23 |
Cold | 3.09 | 15.16 | 22.92 |
Warm | 0.86 | 1.39 | 8.11 |
Analysis
With these benchmarks established, we started profiling the cold – purge start under various configurations, including:
- Different releases of the Firefox snap
- The unconfined (or ‘unsnapped’) Snap
- The unsquashed snap
- Different AppArmor profiles
- Both the Firefox deb and tarball
- A range of hardware configurations, from 4GB Raspberry Pi 4s to laptops and high-end PCs with a mixture of Intel, AMD and NVIDIA GPUs.
From this we were able to measure and compare:
- Where the CPU was being used
- Active threads
- Disk I/O
- Files created in the cache directory
- GPU acceleration
Takeaways
Based on these tests, we identified a number of culprits for the slower startup (in order of estimated impact).
Squashfs seeking
The snap is packed into a compressed squashfs which can create a bottleneck on more resource-constrained systems like the Raspberry Pi. For Firefox, which is quite heavy on the I/O during startup, this creates noticeable overhead as it searches for files in the squashfs. We’re investigating improving the ordering of content in the squashfs to improve seek times.
Software rendering
Something we identified whilst testing on the Raspberry Pi was that the current Firefox snap fails to determine which GPU driver it should use in its glxtest program. This causes Firefox to start up with the software renderer, adding significant overhead to shader compilation time. This was also observed on AMD GPUs.
Good news! A fix for this has now landed in upstream snapd.
Extension handling
Firefox creates a copy of all extensions that are bundled with the firefox package to a user-specific directory upon first start for each user. This is done by going through each extension and copying them block-by-block. In the snap, we bundle 98 language packs which unfortunately take quite a while to copy into the user directory. Especially because the language-packs are read from a compressed squashfs image.
Font and icon handling
When Firefox is confined, significant time is spent discovering all possible icon themes, font configurations and available fonts. This is not done when running unconfined, where Firefox simply loads what it needs instead.
These four issues are our current areas of focus when it comes to cold starts. We will add tracking bugs and updates to these sections going forward so you can follow our progress.
Additional improvements
Future blogs will dive further into other areas of Firefox snap performance, but in the meantime, we wanted to share two additional updates.
Improved runtime performance
With the release of Firefox 100.0 we enabled PGO and LTO. This has made significant improvements to runtime performance and is available in the current release. It also has some impact on startup times.
Native messaging
Beyond performance, native messaging has been our most significant outstanding issue to resolve. Native messaging enables a number of key features such as 2FA devices and GNOME extensions.
We have implemented a new XDG Desktop Portal to support this which is already in 22.04 as a distro patch that we are working to upstream. This portal is also useful for other packaging systems like flatpak as well as snap.
The integration with Firefox is also currently in review and expected to land next month.
If you are experiencing any other bugs or issues, please report them on the Mozilla meta-bug.
Create your own benchmarks
Whilst we’ve attempted to portray our performance improvements in this post as transparently and fairly as possible, we know that there’ll always be folks who want to see the data for themselves, on their own hardware. To that end, we’ve collected a suite of options for users to run their own benchmarks.
Our very own Marco ‘3v1n0‘ Trevisan has created a handy GNOME extension, the Applications Startup Time Measure, to avoid you wearing out your stopwatch.
To get it you first need to install the GNOME Extension Manager:
sudo apt install gnome-shell-extension-manager
Then open extension-manager, navigate to “Browse” and search for “startup”:
Choose ‘Install’ and that’s it. Now every application you launch (limited to launching via application icons) will display how long the application took to go from start to shown on-screen.
For side by side comparisons with the original snap that launched with Ubuntu 22.04 you can also switch to this channel:
sudo snap refresh --channel=latest/stable/jammy-release
Finally, if you want to go more in-depth, you can always add the Firefox Profiler to Firefox and share your insights.
Let us know your results in the ‘Known issues with the Firefox Snap?’ Discourse thread, and keep us updated over time as new improvements roll out.
Some tips on reporting benchmarks
- List the Firefox version being tested, and add comparisons if needed to help with deltas
- List your OS and release version (we’d love numbers from a wide range of distributions)
- Provide hardware info to help us gauge the specs of the machine
- Split by cold (and cold – purge) vs warm starts
- Take multiple readings to get a sense of the average
UPDATE: You can now continue the story in Part 2.