Changeset 77050 in webkit


Ignore:
Timestamp:
Jan 28, 2011 11:37:58 PM (13 years ago)
Author:
eric@webkit.org
Message:

2011-01-28 Eric Seidel <eric@webkit.org>

Reviewed by Darin Adler.

HTML5 TreeBuilder regressed a Peacekeeper DOM test by 40%
https://bugs.webkit.org/show_bug.cgi?id=48719

It's unclear exactly what the Peacekeeper benchmark is testing,
because I haven't found a way to run it myself.

However, I constructed a benchmark which shows at least one possible slow point.
The HTML5 spec talks about creating a new document for every time we use
the fragment parsing algorithm. Document() it turns out, it a huge bloated
mess, and the constructor and destructor do a huge amount of work.
To avoid constructing (or destructing) documents for each innerHTML call,
this patch adds a shared dummy document used by all innerHTML calls.

  • benchmarks/parser/tiny-innerHTML.html: Added.

2011-01-28 Eric Seidel <eric@webkit.org>

Reviewed by Darin Adler.

HTML5 TreeBuilder regressed a Peacekeeper DOM test by 40%
https://bugs.webkit.org/show_bug.cgi?id=48719

It's unclear exactly what the Peacekeeper benchmark is testing,
because I haven't found a way to run it myself.

However, I constructed a benchmark which shows at least one possible slow point.
The HTML5 spec talks about creating a new document for every time we use
the fragment parsing algorithm. Document() it turns out, it a huge bloated
mess, and the constructor and destructor do a huge amount of work.
To avoid constructing (or destructing) documents for each innerHTML call,
this patch adds a shared dummy document used by all innerHTML calls.

This patch brings us from 7x slower than Safari 5 on tiny-innerHTML
to only 1.5x slower than Safari 5. I'm sure there is more work to do here.

Saving a shared Document like this is error prone. Currently
DummyDocumentFactory::releaseDocument() calls removeAllChildren()
in an attempt to clear the Document's state. However it's possible
that that call is not sufficient and we'll have future bugs here.

  • html/parser/HTMLTreeBuilder.cpp: (WebCore::DummyDocumentFactory::createDummyDocument): (WebCore::DummyDocumentFactory::releaseDocument): (WebCore::HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext): (WebCore::HTMLTreeBuilder::FragmentParsingContext::document): (WebCore::HTMLTreeBuilder::FragmentParsingContext::finished):
  • html/parser/HTMLTreeBuilder.h:
Location:
trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/PerformanceTests/Parser/ChangeLog

    r74825 r77050  
     12011-01-28  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        HTML5 TreeBuilder regressed a Peacekeeper DOM test by 40%
     6        https://bugs.webkit.org/show_bug.cgi?id=48719
     7
     8        It's unclear exactly what the Peacekeeper benchmark is testing,
     9        because I haven't found a way to run it myself.
     10
     11        However, I constructed a benchmark which shows at least one possible slow point.
     12        The HTML5 spec talks about creating a new document for every time we use
     13        the fragment parsing algorithm.  Document() it turns out, it a huge bloated
     14        mess, and the constructor and destructor do a huge amount of work.
     15        To avoid constructing (or destructing) documents for each innerHTML call,
     16        this patch adds a shared dummy document used by all innerHTML calls.
     17
     18        * benchmarks/parser/tiny-innerHTML.html: Added.
     19
    1202010-12-31  Adam Barth  <abarth@webkit.org>
    221
  • trunk/Source/WebCore/ChangeLog

    r77049 r77050  
     12011-01-28  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        HTML5 TreeBuilder regressed a Peacekeeper DOM test by 40%
     6        https://bugs.webkit.org/show_bug.cgi?id=48719
     7
     8        It's unclear exactly what the Peacekeeper benchmark is testing,
     9        because I haven't found a way to run it myself.
     10
     11        However, I constructed a benchmark which shows at least one possible slow point.
     12        The HTML5 spec talks about creating a new document for every time we use
     13        the fragment parsing algorithm.  Document() it turns out, it a huge bloated
     14        mess, and the constructor and destructor do a huge amount of work.
     15        To avoid constructing (or destructing) documents for each innerHTML call,
     16        this patch adds a shared dummy document used by all innerHTML calls.
     17
     18        This patch brings us from 7x slower than Safari 5 on tiny-innerHTML
     19        to only 1.5x slower than Safari 5.  I'm sure there is more work to do here.
     20
     21        Saving a shared Document like this is error prone.  Currently
     22        DummyDocumentFactory::releaseDocument() calls removeAllChildren()
     23        in an attempt to clear the Document's state. However it's possible
     24        that that call is not sufficient and we'll have future bugs here.
     25
     26        * html/parser/HTMLTreeBuilder.cpp:
     27        (WebCore::DummyDocumentFactory::createDummyDocument):
     28        (WebCore::DummyDocumentFactory::releaseDocument):
     29        (WebCore::HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext):
     30        (WebCore::HTMLTreeBuilder::FragmentParsingContext::document):
     31        (WebCore::HTMLTreeBuilder::FragmentParsingContext::finished):
     32        * html/parser/HTMLTreeBuilder.h:
     33
    1342011-01-28  Johnny Ding  <jnd@chromium.org>
    235
  • trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp

    r76248 r77050  
    396396}
    397397
     398// NOTE: HTML5 requires that we use a dummy document when parsing
     399// document fragments.  However, creating a new Document element
     400// for each fragment is very slow (Document() does too much work, and
     401// innerHTML is a common call).  So we use a shared dummy document.
     402// This sharing works because there can only ever be one fragment
     403// parser at any time.  Fragment parsing is synchronous and done
     404// only from the main thread.  It should be impossible for javascript
     405// (or anything else) to ever hold a reference to the dummy document.
     406// See https://bugs.webkit.org/show_bug.cgi?id=48719
     407class DummyDocumentFactory {
     408    WTF_MAKE_NONCOPYABLE(DummyDocumentFactory); WTF_MAKE_FAST_ALLOCATED;
     409public:
     410    // Use an explicit create/release here to ASSERT this sharing is safe.
     411    static HTMLDocument* createDummyDocument();
     412    static void releaseDocument(HTMLDocument*);
     413
     414private:
     415    static HTMLDocument* s_sharedDummyDocument;
     416    static int s_sharedDummyDocumentMutex;
     417};
     418
     419HTMLDocument* DummyDocumentFactory::createDummyDocument()
     420{
     421    if (!s_sharedDummyDocument) {
     422        s_sharedDummyDocument = HTMLDocument::create(0, KURL()).releaseRef();
     423        s_sharedDummyDocumentMutex = 0;
     424    }
     425    ASSERT(!s_sharedDummyDocumentMutex);
     426    ASSERT(!s_sharedDummyDocument->hasChildNodes());
     427    s_sharedDummyDocumentMutex++;
     428    return s_sharedDummyDocument;
     429}
     430
     431void DummyDocumentFactory::releaseDocument(HTMLDocument* dummyDocument)
     432{
     433    ASSERT(s_sharedDummyDocument == dummyDocument);
     434    s_sharedDummyDocumentMutex--;
     435    ASSERT(!s_sharedDummyDocumentMutex);
     436    dummyDocument->removeAllChildren();
     437}
     438
     439HTMLDocument* DummyDocumentFactory::s_sharedDummyDocument = 0;
     440int DummyDocumentFactory::s_sharedDummyDocumentMutex = 0;
     441
    398442HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
    399443    : m_fragment(0)
     
    404448
    405449HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
    406     : m_dummyDocumentForFragmentParsing(HTMLDocument::create(0, KURL(), fragment->document()->baseURI()))
     450    : m_dummyDocumentForFragmentParsing(DummyDocumentFactory::createDummyDocument())
    407451    , m_fragment(fragment)
    408452    , m_contextElement(contextElement)
     
    410454{
    411455    m_dummyDocumentForFragmentParsing->setCompatibilityMode(fragment->document()->compatibilityMode());
     456    // Setting the baseURL should work the same as it would have had we passed
     457    // it during HTMLDocument() construction, since the new document is empty.
     458    m_dummyDocumentForFragmentParsing->setURL(fragment->document()->baseURI());
    412459}
    413460
     
    415462{
    416463    ASSERT(m_fragment);
    417     return m_dummyDocumentForFragmentParsing.get();
     464    return m_dummyDocumentForFragmentParsing;
    418465}
    419466
     
    421468{
    422469    // Populate the DocumentFragment with the parsed content now that we're done.
    423     ContainerNode* root = m_dummyDocumentForFragmentParsing.get();
     470    ContainerNode* root = m_dummyDocumentForFragmentParsing;
    424471    if (m_contextElement)
    425472        root = m_dummyDocumentForFragmentParsing->documentElement();
    426473    m_fragment->takeAllChildrenFrom(root);
     474    ASSERT(!m_dummyDocumentForFragmentParsing->hasChildNodes());
     475    DummyDocumentFactory::releaseDocument(m_dummyDocumentForFragmentParsing);
     476    m_dummyDocumentForFragmentParsing = 0;
    427477}
    428478
  • trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h

    r76248 r77050  
    221221
    222222    private:
    223         RefPtr<Document> m_dummyDocumentForFragmentParsing;
     223        // Use a shared dummy document to avoid expensive Document creation.
     224        // Hold a raw pointer to the document since there is no need to ref it.
     225        HTMLDocument* m_dummyDocumentForFragmentParsing;
    224226        DocumentFragment* m_fragment;
    225227        Element* m_contextElement;
Note: See TracChangeset for help on using the changeset viewer.