Mozilla

Firefox 4: Better performance with Lazy Frame Construction

This is a re-post from Timothy Nikkel’s blog.

Lazy Frame Construction is new to Gecko and allows many DOM operations (appendChild, insertBefore, etc) to not trigger immediate reflows. This can vastly improve the interactive performance of very complex web pages. If you want to test this out, you should get a Firefox Nightly.

Lazy frame construction recently landed on mozilla-central. To explain what this means and how this improves things we need some background. Each node in the DOM tree of a webpage has a frame created for it that is used to determine where on the page the node is drawn and its size. A frame corresponds closely to the concept of a box from the CSS spec. We used to create frames for DOM nodes eagerly; that is as soon as a node was inserted into the document we would create a frame for it. But this can create wasted effort in many situations. For example if a script inserts a large number of nodes into the DOM we would create a frame for each node when it is inserted. But with lazy frame construction we can process all those nodes at once in a big batch, saving overhead. Furthermore the time it takes to create those frames no longer blocks that script, so the script can go and do what it needs to and the frames will get created when they are needed. There are other situations where a script would insert nodes into the document and remove them immediately, so there is no need to ever create a frame for these as they would never be painted on screen.

So now when a node is inserted into a document the node is flagged for needing a frame created for it, and then the next time the refresh driver notifies (currently at 20 ms intervals) the frame is created. The refresh driver is also what drives reflow of webpages and CSS & SVG animations.

Let’s look at two examples where lazy frame construction helps.

In this example we insert 80000 div elements and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user. The script can continue executing without flushing layout, but we do it here to measure how long the actual work takes.

var stime = new Date();
var container = document.getElementById("container");
var lastchild = document.getElementById("lastchild");
for (var i = 0; i < 80000; i++) {
  var div = document.createElement("div");
  container.insertBefore(div, lastchild);
}
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we are able to process the insertion of all 80000 div elements in one operation, saving the overhead of 80000 different inserts. In a build without lazy frame construction I get an average time of 1358 ms, with lazy frame construction I get 777 ms.

This example comes from a real webpage. We append a div and then set “div.style.position = ‘absolute’;”, and repeat that 2000 times, and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user.

var stime = new Date();
var container = document.getElementById("container2");
for (var i = 0; i < 2000; i++) {
  var div = document.createElement("div");
  container.appendChild(div);
  div.style.position = "absolute";
}
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we don't even bother creating the frame for the div until after the position has been set to absolute, so we don't waste any effort. In a build without lazy frame construction I get an average time of 4730 ms, with lazy frame construction I get 130 ms.

40 comments

Comments are now closed.

  1. myname wrote on May 26th, 2010 at 06:24:

    18327 (and frozen browser after test) vs 7437 (no problems with browser)

    GJ!

  2. Pino wrote on May 26th, 2010 at 06:32:

    The second test gives an impressive result indeed, but the first test scores 8000ms both on Firefox 3.6.4 (test build) and 8000 on Minefield as well. No idea if my situation is special or there is something wrong…

  3. Pavel Dudrenov wrote on May 26th, 2010 at 07:42:

    That’s pretty cool, it’s a step closer to something that I really wanted to see in dom for ages now. And that’s sort of atomic operations, as in: document.atomic(function(){/* tons of dom manipulations here */}) where atomic would not do any redraws, or something of that sort. Of caurse you can achieve some of that now with innerHTML, but not all. Anyway thats’s off topic.

    Lazy frame construction is a good idea and it’ll make a lot of pages faster. Good job guys.

    1. Boris wrote on May 26th, 2010 at 09:07:

      Pavel, all JS scripts are “atomic” in the sense you describe. The only question is what the UA manages to defer to the end of the script execution. Pretty much any modern UA defers layout, style computation, painting. Some defer rendering object construction (that’s what this article is about).

      1. Pavel wrote on May 26th, 2010 at 10:55:

        I guess “atomic” is the wrong name for it. I ment that no redraws will happen, as some redraws do happen in the middle of your script.

        1. Boris wrote on May 26th, 2010 at 12:36:

          Pavel, right now redraws don’t happen in the middle of scripts (setting aside sync XHR and modal dialogs) in any modern browser that I know of.

          1. pavel wrote on May 26th, 2010 at 15:31:

            what about el.offsetHeight for example

          2. Boris wrote on May 26th, 2010 at 19:03:

            If you do el.offsetHeight, then the browser has to do layout (but not drawing). This would be the case no matter what, even if the “atomic” API you suggest were added (since anything else would lead to weird races and scripts working or not depending on hardware, os, time of day, etc details).

  4. Richard Le Poidevin wrote on May 26th, 2010 at 09:04:

    Very impressive. I got:
    Test 1: 10489 -> 1333
    Test 2: 3288 -> 507

  5. LonerGoth wrote on May 26th, 2010 at 09:48:

    Test One Result – 25731
    Test Two Result -6851

    firefox 3.6.4.
    ms windows 7 home premium 32-bit

    Samsung R720 Laptop with:
    pentium dual-core cpu t4300 @ 2.10GHz
    4.0 Gb Ram
    ATI mobility Radeon HD 4300 series.

  6. LonerGoth wrote on May 26th, 2010 at 09:55:

    3.7a5pre updated 26/05/2010, 17:50
    test one: 1686ms
    test two: 665ms

    Dramatic improvement. Thanks!

  7. LonerGoth wrote on May 26th, 2010 at 09:56:

    Sorry, I’m in the UK, and I used my local GMT + 0 (UTC + 0) time…

  8. CaChi wrote on May 26th, 2010 at 10:32:

    Test 1 -> 3994
    Test 2 -> 5755

  9. homm wrote on May 26th, 2010 at 11:29:

    Firefox 3.6
    2500 ms
    5500 ms

    Firefox 4 This build
    1660 ms
    193 ms

    Chrome 5.0
    184173 ms !!!
    111 ms

    Opera 10.54
    1300 ms
    50 ms

    Firefox 4 have high CPU usage and freezes after tests when scrolling page and switch to another application. Opera steel work pretty fast.

  10. sawrub wrote on May 26th, 2010 at 19:59:

    Firefox 3.5.9 [Fedora] release.
    Test 1 took around 4k in first second and third attempt.
    Test 2 took around 9k in first attempt,60K in second and had to kill Firefox in third attempt as the CPU usage was 100% for more than 3 minutes i tested it for.

    Tested the same script with Chrome 5 [Fedora] and the biggest difference that i saw was the freezing irrespective of the time taken by each. Running the script in Firefox freezes the whole application,Switching to another tab in FF was not possible. Doing the same in Chrome just freezes that tab, while one can use other tabs independent of the one under test. Testing in Chrome seems like different browser, though it was tested on same lines as FF.
    Really sad to see the freeze on Firefox.

  11. Lumi wrote on May 27th, 2010 at 00:35:

    Seamonkey 2.1a1pre build: 20100509010325
    Test1 – 5433
    Test2 – 2108

  12. carol wrote on May 27th, 2010 at 08:26:

    first test 1056 ms
    second 466 ms

    i dont know its real world value say in regular test but anything that rise result this mutch should be good in my book all things being fairly equal!

  13. Wurdebalg Hurrst wrote on May 27th, 2010 at 12:00:

    I wonder if this is related to the IE Testcenter test with revealing the hexagon tiles, ie. if it makes Firefox better in this particular test.

  14. Benben wrote on May 28th, 2010 at 13:35:

    I can not find the element with id=”lastchild” in the page
    was that voluntary ?

  15. Tyler Durden wrote on May 29th, 2010 at 14:54:

    I don’t think these micro-benchmark are fair for cross-browser comparison.

    Anyway, it would be nice to have another more real-world benchmark using document.createDocumentFragment(). Indeed I thought that this method was created to tackle this issue in the first place.

    And I agree with Pavel Dudrenov : having a new document.atomic function that allow developper to control browser reflow could be interesting. Having “atomic” reflow could benefits to a lot of web app, but it could also lead to a lot of trouble if it is misused….

  16. Opperhert wrote on June 7th, 2010 at 05:43:

    first score appr 2508
    second 4609
    third (after defreezing) 67000

    http://i49.tinypic.com/293htnn.png

  17. carol wrote on June 11th, 2010 at 08:46:

    first test 981
    second test 407
    not sure if this is intented but if i try the test again without refreshing the page
    those number double (or so)each time so it can get humongous very quick!
    ty for the research love coder who try to simplify instead of complicating
    (a la html5 for exemple)instead of learning the full power of the tool they have at hand like ecmascript5.keep up the good work!

  18. Ali wrote on July 6th, 2010 at 14:49:

    “and then the next time the refresh driver notifies (currently at 20 ms intervals) the frame is created. The refresh driver is also what drives reflow of webpages and CSS & SVG animations”

    So it means a page can only render at max 50 FPS right?

    And Flash Player cannot render faster then that?

    Ali

  19. Gilfuin wrote on July 7th, 2010 at 06:15:

    72ms in Chrome ;)

  20. Boris wrote on July 7th, 2010 at 17:36:

    > So it means a page can only render at max 50 FPS right?

    Yes. The exact timing might be up to change; there’s a good argument that the right number is 60Hz, not 50Hz.

    Note that your typical modern LCD monitor only refreshes at 60Hz, so painting faster than that is completely pointless.

    > And Flash Player cannot render faster then that?

    It can’t update the on-screen display faster than 60Hz, no. It can, of course, push bits around at a higher rate than that, but no one will see some of those bits. There’s no problem pushing the bits around in Gecko either; it’s just not useful.

  21. Ali wrote on July 7th, 2010 at 23:09:

    Helpful explanation Boris. Thank you.

    Ali.

  22. Pingback from MozillaZine.jp » Blog Archive » Firefox 4 Beta 1 がリリースされた on July 28th, 2010 at 02:35:

    […] lazy frame construction の実装 […]

  23. Anonymous wrote on August 25th, 2010 at 17:33:

    Sorry for some off-topic. What about other browsers?
    Opera 10.54: first test: 1335ms, second test: 143ms
    Opera 10.10: first test: 1255ms, second test: 155ms
    Opera 9.64: first test: 2608ms, second test: 163ms
    Opera 8.54: first test: 3950ms, second test: 100ms

    Internet Explorer 7.0: first test: 3400ms, second test: 6775ms.

    Is it not fantastic?

  24. Marc Dix wrote on August 29th, 2010 at 23:19:

    Pretty much differing results…

    Firefox 4.0, Beta 4: 768 ms/330 ms
    Firefox 3.6.8: 1799ms/1293ms
    Chrome 5.0.375.127: 34719ms/68ms
    Safari 5.0.1: 33190ms[freeze]/64ms
    Internet Explorer 8.0.7600.16385: 2231ms/687ms
    Opera 10.61: 578ms/87ms

  25. Luis Alvarado wrote on September 20th, 2010 at 00:53:

    Tested in Ubuntu 10.04.1 with the following results:

    TEST 1 (Initial Test)
    Firefox 3.6.10 – Test 1 – 2840ms
    Firefox 3.6.10 – Test 2 – 3850ms
    Chrome 6.0.472.62 – Test 1 – 31143ms
    Chrome 6.0.472.62 – Test 2 – 71ms

    TEST 2 (Refreshed Page)
    Firefox 3.6.10 – Test 1 – 2830ms
    Firefox 3.6.10 – Test 2 – 4675ms
    Chrome 6.0.472.62 – Test 1 – 29153ms
    Chrome 6.0.472.62 – Test 2 – 64ms

    TEST 3 (Reopened Browsers)
    Firefox 3.6.10 – Test 1 – 2767ms
    Firefox 3.6.10 – Test 2 – 4652ms
    Chrome 6.0.472.62 – Test 1 – 31186ms
    Chrome 6.0.472.62 – Test 2 – 63ms

  26. edorivai wrote on September 23rd, 2010 at 14:54:

    Google Chrome just crashed, while Minefield scored an impressive 1400!

    Working on linux btw,

    GJ Guys!

  27. Michel wrote on November 14th, 2010 at 07:36:

    Windows 7 :
    Firefox 4 beta 7 : first test 1360ms – second test 550ms
    Internet Explorer 9 beta : first test 3749ms – second test 319ms
    Google Chrome Beta 8 : first test FREEZE – second test 211ms

  28. Shane Bundy wrote on March 13th, 2011 at 09:51:

    On Windows 7 ;
    Opera 11.10 (b2039) – 678ms
    Minefield (2011/03/11) – 1473ms
    Chromium (r77944) – 152688ms

    I don’t know whether to be surprised about Opera’s time but I am really surprised on Chromium’s time. I’m sure WebKit uses LFC as well or is it Google’s WebKit mods in Chromium that caused this?

  29. Shane Bundy wrote on March 14th, 2011 at 16:48:

    After I loaded this page I reloaded it and redid the test and got 160ms for Minefield this time (on an old Celeron M 530!)

    1. Shane Bundy wrote on March 14th, 2011 at 16:50:

      Didn’t realise there were 2 tests. My bad.

      On Minefield ;
      Test 1 – 1683ms
      Test 2 – 162ms

      :-)

  30. Pingback from Mozilla Firefox 4.0 RC2 — Hiphopboy's Blog on March 18th, 2011 at 22:59:

    […] More responsive page rendering using lazy frame construction […]

  31. psxlover wrote on March 22nd, 2011 at 14:05:

    For me everytime I run one of the tests in Firefox 4 I get a bigger number than before…

  32. Pingback from Download Firefox 4 final version | Mozilla| Browser| Open Source on April 10th, 2011 at 22:44:

    […] URL field without reloading the page using HTML History APIsMore responsive page rendering using lazy frame constructionLink history lookup is done asynchronously to provide better responsiveness during pageloadCSS […]

  33. Pingback from Firefox 4 Released – Made to make the Web a better place. | Dan Agnew on July 6th, 2011 at 15:38:

    […] More responsive page rendering using lazy frame construction […]

  34. dang ky ten mien wrote on January 15th, 2012 at 10:48:

    thanks for shares

Comments are closed for this article.