How to Improve Extension Startup Performance

Mozilla is fighting poor performance in Firefox on many fronts. Firefox 3.6 was already a significant improvement over 3.5, and Firefox 4 promises to be lightning fast.

However, Firefox is already pretty fast. Seriously. If you download and install Firefox and run it on a clean profile, it should open quickly and be very responsive. Having a large history and bookmarks database can slow things down a bit, but I think we all know why many of us wait multiple seconds for Firefox to open: add-ons. Specially extensions.

Performance hasn’t really been a big concern for add-on authors. I know that when I test my add-on in my test profile, the slowdown is almost imperceptible. But once you have 5 or 6 add-ons installed, you realize how their combined weight can be very detrimental to user experience. We should care about add-on performance, and very soon we’ll have to.

Dietrich began the add-on performance conversation with his post Firefox, Extensions and Performance, and now with the help of Heather Arthur, we have a modified Talos system measuring the startup performance for the most popular extensions. We think this system should eventually be integrated into AMO, so that we can have a performance dashboard that allows authors to compare their own add-on performance to a global average, or maybe a series of standards we set. But for the moment we’ll be doing things by hand.

I spent some time last week contacting the authors of the add-ons with the most impact on startup times, and the response has been very positive so far. Since I didn’t want to just tell authors to “see what you can do”, I spent some time analyzing their code to identify the most probable reasons for the slowdowns. After a while some patterns began emerging, and I realized that improving startup performance for extensions is not very hard, and can be summed up as a couple of simple guidelines.

I also realized that I was just as guilty with my add-on, and that I needed to work on improving its startup performance. I spent the weekend working on it, and the results were very surprising.

Case Study: Fire.fm

Fire.fm is not the most complex of add-ons, but it does have a wide variety of features and some very complex flows and logic. I knew that there were several areas for improvement, but I was skeptical about the real impact those improvements would have. I thought I could shave off a few milliseconds, but not much more.

First, I needed a testing environment. Measuring Startup provides a very easy method. I tested on Mac OS X 10.6.3, and my testing produced these figures:

Firefox 3.6.4, clean profile: 703.1 ms

Firefox 3.6.4, with Fire.fm 1.4.4: 919.2 ms

So, the latest version of my add-on added more than 210 ms to startup time, an increase of about 30%. Needless to say, I wasn’t happy. 5 add-ons like Fire.fm in a user’s profile would probably increase startup time more than one second! It was unacceptable.

I had several ideas on what I should fix, and the one that I though would help the most involved changing the startup flow significantly, so I left that one for last. I began with the easy ones, which basically consisted on loading a number of modules and variables only until they were needed.

When I was done with that, I decided to take a break before tackling the more difficult tasks, and I decided to test again. Startup time was down to 800 ms! I didn’t expect that at all. Making the simplest of changes had produced a very clear difference, and I still wasn’t done. So, with this new motivation, I spent some time rethinking the startup flow (quite a headache for this particular add-on), and after making it work I ended up with this:

Firefox 3.6.4, with Fire.fm 1.4.5 (dev): 760 ms

The new build was adding only 57 ms to startup time, about 8% of overhead.

Wow. And I’m not even done. There are still some fine-tuning to do that will probably reduce that number a little more. I hope to release 1.4.5 very soon now that I see the significant difference that it will make to thousands of users. This is something I should have done long ago.

Guidelines

OK, so now let’s get to the real meat of this post: what can extension developers do to improve startup performance in their add-ons? Here are my recommendations:

Do not load or run code before it’s needed. Add-ons can have extra features that are only available depending on user preferences, and others have most of their features depend on a user being logged in to a service. Don’t load at startup something you won’t need at the time. This leads to guideline #2:

JavaScript Code Modules. Use them. JSM provide the cleanest way to separate JS into modules that can be loaded on request, unlike chrome scripts which are generally loaded with the overlay at startup, and also unlike XPCOM components which will always be loaded at startup (Edit: removed completely incorrect statement). Keep as much of your code in JSM, make it as modular as you can, and only load modules as you require them. If your add-on is too simple for JSM, don’t worry about it. There’s still one more thing you can do.

Do as little as possible in your load handler. Most add-ons have a load event listener in the main overlay that runs their startup functions. Ask yourself: is there anything I can’t run 100 ms or even 500 ms later? If there is, just use an nsITimer or the setTimeout function to delay running this code . The Firefox window will be able to load sooner and your startup code will run almost instantaneously afterward, in parallel with the loading of the homepage or the saved tab session. The browser will now load faster, and your code will still load at startup for all practical purposes.

I think most non-trivial add-ons can greatly improve their startup times by following these simple guidelines. All add-on authors should take the time to review them and see if there’s anything else they can do to help Firefox load with as little overhead as possible. Add-on performance is increasingly important for us, and it will probably become part of our code quality requirements in the near future. Act now, and help us make Firefox 4 the greatest browser ever!

I’d like it if my Firefox could tap into the performance metrics on AMO so that I can use that to weigh whether I want to uninstall some addons, or whine to their authors. I used to have very few and now I have 25 of them.

One of the most obvious and also most overlooked things that reap the best rewards of all: simply do less, period. Eyeing feature lists hard and coming up with stuff to eject from a bloated feature set, making your total weight just simply far less can pay off astoundingly.

It is of course the hardest to make happen, but if you can, start in that end. It can be a great win in terms of coding joy as well.

On a similar note, cutting backwards compat with Firefox 1.5, 2 or even 3.0, and making use of the less horrible APIs more modern Firefoxes come with, like FUEL, if it does all you need: major gains to be made.

I don’t know much about the state and practicality of going JetPack SDK already, but I expect the same will at some point apply there.

More add-on developers will, if posts like this one lead the way and explain the benefits, new idioms and ways of doing what is easier to do today than a few years ago when this baggage started piling up.

For point 3: It would be _very_ useful if there’s an event, in every XUL document (not just in browser.xul!), that is guaranteed to fire after the window is displayed. Making everybody use their own timeout (and therefore adding _more_ work to the startup path as each timer costs something) is… sort of a silly workaround when you have identified it as being a good fix for startup problems. More platform hooks like that that Firefox doesn’t necessarily have to use (though could – see delayedStartup) makes it easier for extension developers do the right thing, and everybody wins

This is an incredibly important issue for retaining Firefox users… (that and namespacing to avoid conflicts).

I just added the following at the referenced blog:

“Code modules of course offer great potential, e.g., for loading classes just once. This should also help extensions speed up opening of extension dialogs. However, debugging these is a pain for the same reason that it is an advantage–if it only loads once, one can’t change some code and see it work again. If the feature at https://bugzilla.mozilla.org/show_bug.cgi?id=481603 were added, developers could refresh a module’s code programmatically when they are debugging.”

XPCOM components aren’t normally loaded at startup! If they are, then this is because someone else is loading them (for instance if they are in the one of the startup categories, or if you have just installed/enabled/disabled/uninstalled an extension, in which case the current component manager needs to load all components once in order to update compreg.dat).

I don’t think it is responsible to use the word ‘lightening’ when discussing Firefox performance.

Nor do I think think responsible to dismiss existing Firefox issues such as the still-debatable memory management issues and instead throw a large amount of the blame on extension authors.

Ask yourself this: how easy is it to build an application that does relatively little, call it fast, then when people add the extensions **necessary** to make Firefox as usable as other browsers are **natively**, blame those extensions.

If the quality of extension code was really a performance bottleneck (as you seem to infer) then take the most popular extension code, optimise it and include it in the default Firefox release.

Why for instance should one man have to work all alone to make Firefox the tabbed browsing experience it should be natively? AFAIK this is how the Tab Mix Plus author works.

To expect volunteer developers to take the heat for lack of responsiveness of the host application is a bit like a prison guard walking on a freshly washed floor and then telling the prisoner to wash it again.

@pd:
I said Firefox 4 promises to be lightning fast. Unless you can see into the future, I don’t understand your claim at all.

Proper memory management is something that the Firefox team took very seriously for 3.6, and will surely continue to improve on 4 and later. Who’s dismissing these issues? This blog post is about *startup* performance. How does memory management play any role in this?

Assigning developer time to improving extension code is *exactly* what this blog post and the messaging I’ve been doing are about. I’m a developer, and I’m trying to help.

Finally, it’s silly to just pick popular add-ons and embed them into Firefox. There are hundreds of them, and most of them wouldn’t be useful to a majority of users. Even if I love Tree Style Tab, I don’t see why I would impose such a complex add-on on everyone.

You are completely ignoring the data and just complaining about a bunch of tangential issues.

Well, this is about startup performance and I am thankful for your useful recommendations.

Performance certainly is a crucial point of improvement for the upcoming Firefox release. For this reason I like to subscribe @pd’s request for continued improvement of memory management with much(!) more priority. I believe everything else should be negligible.

At work I daily need open (and close) several hundreds of websites in tabs for research reasons. Firefox slows down continuously according to the growing memory requirement which increases every time up to ~1.3 GigaByte when finally Firefox gets unusable. This is the same without addons as well as on different machines or OS. I suggest to google for ‘Firefox’ and ‘slow’ and read some of the many related user complaints.

@Johan Sundström: yes, finding the right feature set without going overboard is quite a challenge, specially when you’re completely in charge of a project…

@Mook: I know! I was thinking the same thing today. I don’t think having a few timers is such a big burden, but it sucks to ask all developers to workaround something we could fix in Firefox and other apps.

I thought I replied to this already, but it looks like the comment was lost in the ether. I managed to get this working on Windows using Python and Cygwin. I’ll update the wiki page with more information very soon.

Btw, while it is great that efforts are made to reduce start-up time across extensions and improve the experience as a whole for add-on users, I think we also have to battle the myth held by some users that more add-ons automatically means noticeably slower start-up times since many extensions just add a very light overlay.

Maybe extensions could even get certified as being light-weight on load? Or those which have been thoroughly checked for avoiding potential namespacing issues (from IDs to globals to events, etc.)? I think the idea of additional certifications could meet the need of allowing safe extensions through, but allowing there to gradually build up higher standards than mere safety.

For point 3: It would be _very_ useful if there’s an event, in every XUL document (not just in browser.xul!), that is guaranteed to fire after the window is displayed. Making everybody use their own timeout (and therefore adding _more_ work to the startup path as each timer costs something) is… sort of a silly workaround when you have identified it as being a good fix for startup problems. More platform hooks like that that Firefox doesn’t necessarily have to use (though could – see delayedStartup) makes it easier for extension developers do the right thing, and everybody wins

a recently run into a major problem in my browser it no longer shows the file and edit menu, I no longer have a place to type in a URL! It has also taken away my bookmarks menu. So as you can see I am having a very bad day any help would be appreciated
my info;
Albert Wagnercire-fx@comcast.net

It would be cool if overlaying the extension’s XUL itself could be deferred. I am already using plenty of setTimers on startup (QuickFolders – Thunderbird extension adding a ton of tabs with context menus that contain parts of the folder tree) as I always was aware that extensions slow down my Mozilla platforms. I think if loading the XUL file itself could be deferred (as an opt-in choice for the developers, with a couple of checkpoints such as “loaded main window” “GLODA loaded” etc. ) then no code would be executed at all! It would require some extension of XUL attributes, but might be well worth while.

Did you consider that solution?

Also, I always found it annoying that same setTimers are flagged by the validation process!

I’ve seen a few extension authors building UI elements and styling them using JS. I suspect they simply have more experience with JS than XUL. It seems like XUL and CSS are pretty powerful and can do many things that people rely on JS to do. For instance, I’ve seen extensions using bizarre JS workarounds to do what type=”checkbox” does automatically. It seems like this would make the extension not only slower, but obviously means the button is not going to style properly as well. The same feels true for retrieving properties of other elements where people are using JS instead of observers. Are there speed benefits to doing as much as possible in XUL (using XUL commands, not inline scripts) vs. JS?

@pjdkrunkt: using XUL overlays is much more efficient because the chrome is cached after the add-on is installed, meaning that loading the browser with the add-on UI is very fast. If you build your entire UI using JS, then it will need to be processed every time the extension load, wasting more time and resources for it.
Using JS to generate XUL should be limited to the situations where you need to generate XUL dynamically, and not just because the author has a hard time understanding it.