I took a look at what happens on Firefox startup on Mac with a profile I’ve used for testing for a while. Specifically, how often and why the root element (<window>) in the browser window is asked to be laid out. Each line below is an attempt to lay out (reflow) the root element. A reflow can happen as a result of a number of different things such as new elements being inserted, images being loaded and so forth. What happens is that the document layout objects are marked as dirty as necessary, then at a future point, a reflow occurs. This allows a script to make a number of changes without having each change cause a full refresh. I’ve broken down each attempt to mark the root element (or some other reflow root) as dirty, separated by commas in each line. In the table below, a reflow occurs 15 times.
Action | Time to finish |
---|---|
Hidden Window | 0.55ms |
Main Window is parsed and laid out | 14.95ms |
Attribute changed, and loaded page (about:blank) is laid out | 0.78ms |
Search icon is set | 0.35ms |
Scrollbar attributes changed, toolbarspring is inserted, window’s load event fires and listeners called and finished | 2.21.ms |
Scrollbar attributes changed, tabview.png is set | 0.34ms |
folderDropArrow.png is set | 0.27ms |
browser.js delayedStartup() is called, splitter is inserted into urlbar | 0.24ms |
menupopup is appended to back button, delayedStartup() finishes, bookmarks toolbar handling begins | 5.77ms |
chrome://browser/skin/places/query.png is set | 0.56ms |
chrome://browser/skin/page-livemarks.png is set | 0.39ms |
chrome://global/skin/tree/folder.png is set | 0.46ms |
Call to flush frames | 0.33ms |
Bookmark icon is set | 0.48ms |
Bookmark icon is set | 0.37ms |
The last few images are all the assignment of the icons on the bookmarks toolbar. These don’t occur if the toolbar is hidden. In total, approximately 400 changes to an element’s attribute are made and 41 nodes are appended to the document after it is parsed.
Now let’s take a look at the mobile version, running on an Android tablet. Here, 24 reflows occur over the 2200ms startup time.
Action | Time to finish |
---|---|
Insert html element into main window?, insert html element into hidden window?, parse and lay out main window | 7.43ms (also 183.7ms reading xbl) |
Four dirty marks caused by scrollbar attribute changes | 1.07ms |
Remove text node (a <br> is appended to a <div> immediately following), append <documenttab> | 2.55ms |
Append <notificationbox> | 0.78ms |
Some attributes on <label> and <image> elements are changed, some <label> elements are removed | 1.20ms |
scrollbar.pageincrement is changed | 0.28ms |
SizeToContent is called | 0.22ms |
Unknown reason, but probably caused by bug 230959 | 0.94ms |
slider.pageincrement is changed, attributes on <tablet> are changed | 5.329ms |
Three dirty marks caused by scrollbar attribute changes | 1.65ms |
Attribute changed on a <scrollbox> | 1.19ms |
Attribute changed on a <scrollbox> | 0.57ms |
Attributes left, width and height changed on a <vbox> | 1.40ms |
Two scrollbar related dirty marks, mode attribute changed on various things (no dirty mark), loading attribute on an <image> | 1.88ms |
mode attribute changed on various things (no dirty mark), loading attribute on an <image> | 0.76ms |
Some <image> elements are inserted and removed | 0.72ms |
Unknown reason, probably a flush caused by retrieving some layout information | 0.53ms |
Unknown reason, probably a flush caused by retrieving some layout information | 0.68ms |
Loaded page starts appearing, <toolbarbutton> label changed | 2.27ms |
Text node appended to page | 0.51ms |
Text node removed from page, height changed on an <hbox> related to a nearby <canvas>. | 1.54ms |
mode attribute changed on various things (no dirty mark), loading attribute on an <image> | 0.74ms |
<box> is marked not hidden (think this is the autocomplete widget), insert frames into box, some attributes on <richlistitem> and <menuitem> are changed | 33.78ms (also 265.18ms reading xbl) |
Eight dirty marks caused by scrollbar attribute changes | 2.70ms |
Observations:
- There are lots of changes to scrollbars here, despite no scrollbars on mobile Firefox being visible. The set listed in the last row is likely caused by the resize caused by the on-screen keyboard appearing. 120ms of time occurs from when this begins to when this ends, although it is likely that only a small amount of this is directly scrollbar related.
- I didn’t measure XBL parsing time on desktop Firefox in this test, but it typically takes about 10% of the startup time. Of course, XBL caching should reduce the time to load XBL here. It should be noted though that parsing and creating the main document takes 25% of the rest of the time.
- The time between reflow 2 and reflow 18 is 550ms. I’m not familiar enough with the mobile code, but this appears to be the time to process and manipulate things after the main document is parsed, equivalent to desktop Firefox’s handling in browser.js.
- The last two rows are for the autocomplete and on-screen keyboard appearing. It takes up 675ms of time, but the main window has already appeared, so the user’s perception of the time to start up may not need to include this time.
Some of the mobile reflows might be due to our triple-resize event. There are 2 bogus ones and then it finally gets set to what the OS tells it to be.
Comment by Taras Glek — November 3, 2011 @ 7:25 pm
Why are multiple reflows done in the first place? Wouldn’t it be better to hold them off until the whole UI has been loaded?
Comment by CAFxX — November 4, 2011 @ 10:09 am
This is fascinating work, well done! It reflects the experience I’ve always had when restarting Firefox and that is one of a lot of activity.
The simple question has to be asked: why isn’t most of this reflow made redundant by saving the window’s layout information before closing? I imagine a certain amount of re-checking would be necessary to make sure the window is not larger than a monitor that might have had it’s resolution changed in between Firefox restarts, for example. But other than it seems Firefox does a lot of work that slows down for no particular reason?
The way XUL or the underlying Firefox codebase ‘draws’ windows has always been an oddity compared to most other Windows-based applications running on other toolkits – even GTK+ for Windows doesn’t seem to do so much work just to present the basic initial window. It seems that not only is this a waste of start up time but in some cases I still see the awful user experience of Firefox starting up with the window sized to a puny 200 x 200 pixels – on a desktop! I’ve never been able to figure out why that happens. I’ve always assumed that Firefox allowance for resized popup windows in JS has had something to do with it but maybe it’s just an inherant XUL weakness?
Comment by pd — November 5, 2011 @ 6:34 am