Changeset 79104 in webkit


Ignore:
Timestamp:
Feb 18, 2011 11:57:08 PM (13 years ago)
Author:
tonyg@chromium.org
Message:

2011-02-18 Tony Gentilcore <tonyg@chromium.org>

Reviewed by Eric Seidel.

Let the parser yield for layout before running scripts
https://bugs.webkit.org/show_bug.cgi?id=54355

Prior to this patch, the parser would yield to perform a layout/paint before running a
script only if the script or a stylesheet blocking the script is not loaded yet. Since we
don't preload scan into the body while parsing the head, typically we'll block on a script
early in the body that causes us to yield to do the first paint within a reasonable time.

However, I'm planning to change the PreloadScanner to scan into the body from the head.
That significantly improves overall load time, but would hurt first paint time because
fewer scripts would be blocked during parsing and thus wouldn't yield.

This change causes us to yield before running scripts if we haven't painted yet (regardless
of whether or not the script is loaded). In addition to allowing the above mentioned
PreloadScanner change to be implemented without regressing first paint time, this also
improves first paint time by itself.

I tested Alexa's top 45 websites using Web Page Replay to control the content and simulate
bandwidth. This patch improved average first paint time by 1% over an unlimited connection,
6% over a 1Mbps connection and 11% over a 5Mbps connection. There was no statistically
signifcant change in page load time.

Within the pages tested, 33 had no statistically significant change in time to first paint,
12 improved, and none regressed. Of the improved, some of the standouts from the 1Mbps set
are: 20% on youtube, 37% on wiki, 27% on ebay, 13% on cnn, 16% on espn, 74% on sohu.

  • html/parser/HTMLDocumentParser.cpp: (WebCore::HTMLDocumentParser::canTakeNextToken): This is the new yield point. (WebCore::HTMLDocumentParser::pumpTokenizer): Remove ASSERT that we are not paused. isPaused means that we are waiting for a script. Bug 54574 changed pumpTokenizer() so that it does the right thing whether we are just before a token or waiting for a script. Now that we may yield before a token or before a script, this may be called while paused.
  • html/parser/HTMLParserScheduler.cpp: (WebCore::isLayoutTimerActive): Added a FIXME because r52919 changed minimumLayoutDelay() to return m_extraLayoutDelay instead of 0 as a minimum. So checking !minimumLayoutDelay() no longer works. The fix is to change it to check minimumLayoutDelay() == m_extraLayoutDelay. But this is all the more reason to move this method onto Document. I'll do this in a follow up. (WebCore::HTMLParserScheduler::checkForYieldBeforeScript): Added.
  • page/FrameView.h: (WebCore::FrameView::hasEverPainted): Added.
Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r79103 r79104  
     12011-02-18  Tony Gentilcore  <tonyg@chromium.org>
     2
     3        Reviewed by Eric Seidel.
     4
     5        Let the parser yield for layout before running scripts
     6        https://bugs.webkit.org/show_bug.cgi?id=54355
     7
     8        Prior to this patch, the parser would yield to perform a layout/paint before running a
     9        script only if the script or a stylesheet blocking the script is not loaded yet. Since we
     10        don't preload scan into the body while parsing the head, typically we'll block on a script
     11        early in the body that causes us to yield to do the first paint within a reasonable time.
     12
     13        However, I'm planning to change the PreloadScanner to scan into the body from the head.
     14        That significantly improves overall load time, but would hurt first paint time because
     15        fewer scripts would be blocked during parsing and thus wouldn't yield.
     16
     17        This change causes us to yield before running scripts if we haven't painted yet (regardless
     18        of whether or not the script is loaded). In addition to allowing the above mentioned
     19        PreloadScanner change to be implemented without regressing first paint time, this also
     20        improves first paint time by itself.
     21
     22        I tested Alexa's top 45 websites using Web Page Replay to control the content and simulate
     23        bandwidth. This patch improved average first paint time by 1% over an unlimited connection,
     24        6% over a 1Mbps connection and 11% over a 5Mbps connection. There was no statistically
     25        signifcant change in page load time.
     26
     27        Within the pages tested, 33 had no statistically significant change in time to first paint,
     28        12 improved, and none regressed. Of the improved, some of the standouts from the 1Mbps set
     29        are: 20% on youtube, 37% on wiki, 27% on ebay, 13% on cnn, 16% on espn, 74% on sohu.
     30
     31        * html/parser/HTMLDocumentParser.cpp:
     32        (WebCore::HTMLDocumentParser::canTakeNextToken): This is the new yield point.
     33        (WebCore::HTMLDocumentParser::pumpTokenizer): Remove ASSERT that we are not paused. isPaused
     34        means that we are waiting for a script. Bug 54574 changed pumpTokenizer() so that it does
     35        the right thing whether we are just before a token or waiting for a script. Now that we may
     36        yield before a token or before a script, this may be called while paused.
     37        * html/parser/HTMLParserScheduler.cpp:
     38        (WebCore::isLayoutTimerActive): Added a FIXME because r52919 changed minimumLayoutDelay()
     39        to return m_extraLayoutDelay instead of 0 as a minimum. So checking !minimumLayoutDelay()
     40        no longer works. The fix is to change it to check minimumLayoutDelay() ==
     41        m_extraLayoutDelay. But this is all the more reason to move this method onto Document. I'll
     42        do this in a follow up.
     43        (WebCore::HTMLParserScheduler::checkForYieldBeforeScript): Added.
     44        * page/FrameView.h:
     45        (WebCore::FrameView::hasEverPainted): Added.
     46
    1472011-02-18  Dawit Alemayehu  <adawit@kde.org>
    248
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r79006 r79104  
    208208    // The parser will pause itself when waiting on a script to load or run.
    209209    if (m_treeBuilder->isPaused()) {
     210        if (mode == AllowYield)
     211            m_parserScheduler->checkForYieldBeforeScript(session);
     212
     213        // If we don't run the script, we cannot allow the next token to be taken.
     214        if (session.needsYield)
     215            return false;
     216
    210217        // If we're paused waiting for a script, we try to execute scripts before continuing.
    211218        bool shouldContinueParsing = runScriptsForPausedTreeBuilder();
     
    234241{
    235242    ASSERT(!isStopped());
    236     ASSERT(!m_treeBuilder->isPaused());
    237243    ASSERT(!isScheduledForResume());
    238244    // ASSERT that this object is both attached to the Document and protected.
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.cpp

    r79006 r79104  
    7979{
    8080    ASSERT(doc);
     81    // FIXME: This is broken on Android because minimumLayoutDelay is never 0.
    8182    return doc->view() && doc->view()->layoutPending() && !doc->minimumLayoutDelay();
    8283}
     
    9293    }
    9394    m_parser->resumeParsingAfterYield();
     95}
     96
     97void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
     98{
     99    // If we've never painted before and a layout is pending, yield prior to running
     100    // scripts to give the page a chance to paint earlier.
     101    Document* document = m_parser->document();
     102    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
     103    if (needsFirstPaint && isLayoutTimerActive(document))
     104        session.needsYield = true;
    94105}
    95106
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.h

    r79006 r79104  
    6868        ++session.processedTokens;
    6969    }
     70    void checkForYieldBeforeScript(PumpSession&);
    7071
    7172    void scheduleForResume();
  • trunk/Source/WebCore/page/FrameView.h

    r79053 r79104  
    208208    PaintBehavior paintBehavior() const;
    209209    bool isPainting() const;
     210    bool hasEverPainted() const { return m_lastPaintTime; }
    210211    void setNodeToDraw(Node*);
    211212
Note: See TracChangeset for help on using the changeset viewer.