Changeset 80861 in webkit


Ignore:
Timestamp:
Mar 11, 2011 10:29:31 AM (13 years ago)
Author:
tonyg@chromium.org
Message:

2011-03-11 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::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

    r80859 r80861  
     12011-03-11  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::HTMLParserScheduler::checkForYieldBeforeScript): Added.
     39        * page/FrameView.h:
     40        (WebCore::FrameView::hasEverPainted): Added.
     41
    1422011-03-11  Dimitri Glazkov  <dglazkov@chromium.org>
    243
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r80759 r80861  
    213213    // The parser will pause itself when waiting on a script to load or run.
    214214    if (m_treeBuilder->isPaused()) {
     215        if (mode == AllowYield)
     216            m_parserScheduler->checkForYieldBeforeScript(session);
     217
     218        // If we don't run the script, we cannot allow the next token to be taken.
     219        if (session.needsYield)
     220            return false;
     221
    215222        // If we're paused waiting for a script, we try to execute scripts before continuing.
    216223        bool shouldContinueParsing = runScriptsForPausedTreeBuilder();
     
    239246{
    240247    ASSERT(!isStopped());
    241     ASSERT(!m_treeBuilder->isPaused());
    242248    ASSERT(!isScheduledForResume());
    243249    // ASSERT that this object is both attached to the Document and protected.
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.cpp

    r80759 r80861  
    8787}
    8888
     89void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
     90{
     91    // If we've never painted before and a layout is pending, yield prior to running
     92    // scripts to give the page a chance to paint earlier.
     93    Document* document = m_parser->document();
     94    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
     95    if (needsFirstPaint && document->isLayoutTimerActive())
     96        session.needsYield = true;
     97}
     98
    8999void HTMLParserScheduler::scheduleForResume()
    90100{
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.h

    r80759 r80861  
    7171        ++session.processedTokens;
    7272    }
     73    void checkForYieldBeforeScript(PumpSession&);
    7374
    7475    void scheduleForResume();
  • trunk/Source/WebCore/page/FrameView.h

    r80804 r80861  
    207207    PaintBehavior paintBehavior() const;
    208208    bool isPainting() const;
     209    bool hasEverPainted() const { return m_lastPaintTime; }
    209210    void setNodeToDraw(Node*);
    210211
Note: See TracChangeset for help on using the changeset viewer.