Changeset 133372 in webkit


Ignore:
Timestamp:
Nov 2, 2012 4:39:42 PM (11 years ago)
Author:
commit-queue@webkit.org
Message:

Replace NodeRareData hash map with a union on m_renderer
https://bugs.webkit.org/show_bug.cgi?id=100057

Patch by Elliott Sprehn <esprehn@chromium.org> on 2012-11-02
Reviewed by Eric Seidel.

Use a union on Node::m_renderer between NodeRareData* and RenderObject*. This removes
the overhead of accessing rare data and the memory from the map.

This is an 8% improvement on Bindings/get-elements-by-tag-name.html which tested
document.getElementsByTagName and was previously optimized in Bug 90059 for a 5%
improvement. As this is better than even the special casing for document that was
done in that bug, general node list access should see an even greater win.

This reduces the memory usage on nytimes.com by 250k per Bug 101052 by
removing the rare data map overhead.

This is also a 15% improvement on Parser/textarea-parsing.html

By removing the performance overhead of rareData() this patch addresses the performance
issues raised in Bugs 73853, 87034 and 89635.

I ran Parser/html5-full-render.html and there was no performance regression after
tuning Text::recalcTextStyle and the refactor that was done in r132684.

No new tests, this is just a refactor.

  • dom/Document.cpp:

(WebCore::Document::Document):

  • dom/Document.h:

(WebCore::Node::Node):

  • dom/Element.cpp:

(WebCore::Element::elementRareData):

  • dom/Node.cpp:

(WebCore::Node::rareData):
(WebCore::Node::ensureRareData):
(WebCore::Node::clearRareData):
(WebCore::Node::renderBox):
(WebCore::Node::renderBoxModelObject):
(WebCore::Node::reportMemoryUsage):

  • dom/Node.h:

(NodeRareDataBase):

Base class for NodeRareData that knows about the renderer so we can
inline the accesses in Node.h

(WebCore::NodeRareDataBase::renderer):
(WebCore::NodeRareDataBase::setRenderer):
(WebCore::NodeRareDataBase::~NodeRareDataBase):
(WebCore::NodeRareDataBase::NodeRareDataBase):
(WebCore):
(WebCore::Node::renderer):
(WebCore::Node::setRenderer):
(Node):

  • dom/NodeRareData.h:
  • dom/NodeRenderStyle.h:

(WebCore::Node::renderStyle):

  • dom/Text.cpp:

(WebCore::Text::recalcTextStyle):

This method appears very hot in html5-full-render.html and accessing the
renderer 4 times caused a 2% performance regression with this patch. I
reduced it to 1 access and there's no longer any performance regression.

  • dom/WebCoreMemoryInstrumentation.cpp: Removed tracking of the rare data map memory usage as there is no longer a map to track.
  • dom/WebCoreMemoryInstrumentation.h:
  • inspector/InspectorMemoryAgent.cpp:

(WebCore::InspectorMemoryAgent::getProcessMemoryDistribution):

Location:
trunk/Source/WebCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r133366 r133372  
     12012-11-02  Elliott Sprehn  <esprehn@chromium.org>
     2
     3        Replace NodeRareData hash map with a union on m_renderer
     4        https://bugs.webkit.org/show_bug.cgi?id=100057
     5
     6        Reviewed by Eric Seidel.
     7
     8        Use a union on Node::m_renderer between NodeRareData* and RenderObject*. This removes
     9        the overhead of accessing rare data and the memory from the map.
     10
     11        This is an 8% improvement on Bindings/get-elements-by-tag-name.html which tested
     12        document.getElementsByTagName and was previously optimized in Bug 90059 for a 5%
     13        improvement. As this is better than even the special casing for document that was
     14        done in that bug, general node list access should see an even greater win.
     15
     16        This reduces the memory usage on nytimes.com by 250k per Bug 101052 by
     17        removing the rare data map overhead.
     18
     19        This is also a 15% improvement on Parser/textarea-parsing.html
     20
     21        By removing the performance overhead of rareData() this patch addresses the performance
     22        issues raised in Bugs 73853, 87034 and 89635.
     23
     24        I ran Parser/html5-full-render.html and there was no performance regression after
     25        tuning Text::recalcTextStyle and the refactor that was done in r132684.
     26
     27        No new tests, this is just a refactor.
     28
     29        * dom/Document.cpp:
     30        (WebCore::Document::Document):
     31        * dom/Document.h:
     32        (WebCore::Node::Node):
     33        * dom/Element.cpp:
     34        (WebCore::Element::elementRareData):
     35        * dom/Node.cpp:
     36        (WebCore::Node::rareData):
     37        (WebCore::Node::ensureRareData):
     38        (WebCore::Node::clearRareData):
     39        (WebCore::Node::renderBox):
     40        (WebCore::Node::renderBoxModelObject):
     41        (WebCore::Node::reportMemoryUsage):
     42        * dom/Node.h:
     43        (NodeRareDataBase):
     44          Base class for NodeRareData that knows about the renderer so we can
     45          inline the accesses in Node.h
     46        (WebCore::NodeRareDataBase::renderer):
     47        (WebCore::NodeRareDataBase::setRenderer):
     48        (WebCore::NodeRareDataBase::~NodeRareDataBase):
     49        (WebCore::NodeRareDataBase::NodeRareDataBase):
     50        (WebCore):
     51        (WebCore::Node::renderer):
     52        (WebCore::Node::setRenderer):
     53        (Node):
     54        * dom/NodeRareData.h:
     55        * dom/NodeRenderStyle.h:
     56        (WebCore::Node::renderStyle):
     57        * dom/Text.cpp:
     58        (WebCore::Text::recalcTextStyle):
     59          This method appears very hot in html5-full-render.html and accessing the
     60          renderer 4 times caused a 2% performance regression with this patch. I
     61          reduced it to 1 access and there's no longer any performance regression.
     62        * dom/WebCoreMemoryInstrumentation.cpp:
     63          Removed tracking of the rare data map memory usage as there is no longer
     64          a map to track.
     65        * dom/WebCoreMemoryInstrumentation.h:
     66        * inspector/InspectorMemoryAgent.cpp:
     67        (WebCore::InspectorMemoryAgent::getProcessMemoryDistribution):
     68
    1692012-11-02  Alexey Proskuryakov  <ap@apple.com>
    270
  • trunk/Source/WebCore/dom/Document.cpp

    r133326 r133372  
    479479    , m_sawElementsInKnownNamespaces(false)
    480480    , m_isSrcdocDocument(false)
    481     , m_documentRareData(0)
    482481    , m_eventQueue(DocumentEventQueue::create(this))
    483482    , m_weakReference(DocumentWeakReference::create(this))
     
    20252024    marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view);
    20262025    marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view);
    2027 }
    2028 
    2029 void Document::setDocumentRareData(NodeRareData* rareData)
    2030 {
    2031     m_documentRareData = rareData;
    20322026}
    20332027
  • trunk/Source/WebCore/dom/Document.h

    r133326 r133372  
    117117class NodeFilter;
    118118class NodeIterator;
    119 class NodeRareData;
    120119class Page;
    121120class PlatformMouseEvent;
     
    467466    bool isSrcdocDocument() const { return m_isSrcdocDocument; }
    468467
    469     NodeRareData* documentRareData() const { return m_documentRareData; };
    470     void setDocumentRareData(NodeRareData*);
    471 
    472468    StyleResolver* styleResolverIfExists() const { return m_styleResolver.get(); }
    473469
     
    14301426    bool m_isSrcdocDocument;
    14311427
    1432     NodeRareData* m_documentRareData;
    1433 
    14341428    RefPtr<DocumentEventQueue> m_eventQueue;
    14351429
     
    15271521    , m_previous(0)
    15281522    , m_next(0)
    1529     , m_renderer(0)
    15301523{
    15311524    if (document)
  • trunk/Source/WebCore/dom/Element.cpp

    r133326 r133372  
    155155{
    156156    ASSERT(hasRareData());
    157     return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this));
    158 }
    159    
     157    return static_cast<ElementRareData*>(rareData());
     158}
     159
    160160inline ElementRareData* Element::ensureElementRareData()
    161161{
  • trunk/Source/WebCore/dom/Node.cpp

    r133279 r133372  
    471471{
    472472    ASSERT(hasRareData());
    473     NodeRareData* data = isDocumentNode() ? static_cast<const Document*>(this)->documentRareData() : NodeRareData::rareDataFromMap(this);
    474     ASSERT(data);
    475     return data;
     473    return static_cast<NodeRareData*>(m_data.m_rareData);
    476474}
    477475
     
    482480
    483481    NodeRareData* data = createRareData().leakPtr();
    484     if (isDocumentNode()) {
    485         // Fast path for a Document. A Document knows a pointer to NodeRareData.
    486         ASSERT(!static_cast<Document*>(this)->documentRareData());
    487         static_cast<Document*>(this)->setDocumentRareData(data);
    488     } else {
    489         ASSERT(!NodeRareData::rareDataMap().contains(this));
    490         NodeRareData::rareDataMap().set(this, data);
    491     }
     482    ASSERT(data);
     483    data->setRenderer(m_data.m_renderer);
     484    m_data.m_rareData = data;
    492485    setFlag(HasRareDataFlag);
    493486    return data;
    494487}
    495    
     488
    496489OwnPtr<NodeRareData> Node::createRareData()
    497490{
     
    507500#endif
    508501
    509     if (isDocumentNode()) {
    510         Document* document = static_cast<Document*>(this);
    511         NodeRareData* data = document->documentRareData();
    512         ASSERT(data);
    513         delete data;
    514         document->setDocumentRareData(0);
    515     } else {
    516         NodeRareData::NodeRareDataMap& dataMap = NodeRareData::rareDataMap();
    517         NodeRareData::NodeRareDataMap::iterator it = dataMap.find(this);
    518         ASSERT(it != dataMap.end());
    519         delete it->value;
    520         dataMap.remove(it);
    521     }
     502    RenderObject* renderer = m_data.m_rareData->renderer();
     503    delete m_data.m_rareData;
     504    m_data.m_renderer = renderer;
    522505    clearFlag(HasRareDataFlag);
    523506}
     
    799782RenderBox* Node::renderBox() const
    800783{
    801     return m_renderer && m_renderer->isBox() ? toRenderBox(m_renderer) : 0;
     784    RenderObject* renderer = this->renderer();
     785    return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
    802786}
    803787
    804788RenderBoxModelObject* Node::renderBoxModelObject() const
    805789{
    806     return m_renderer && m_renderer->isBoxModelObject() ? toRenderBoxModelObject(m_renderer) : 0;
     790    RenderObject* renderer = this->renderer();
     791    return renderer && renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
    807792}
    808793
     
    28312816    info.addMember(m_next);
    28322817    info.addMember(m_previous);
    2833     if (m_renderer)
    2834         info.addMember(m_renderer->style());
     2818    if (RenderObject* renderer = this->renderer())
     2819        info.addMember(renderer->style());
    28352820    if (hasRareData())
    28362821        info.addMember(rareData());
  • trunk/Source/WebCore/dom/Node.h

    r133286 r133372  
    112112};
    113113
     114class NodeRareDataBase {
     115public:
     116    RenderObject* renderer() const { return m_renderer; }
     117    void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
     118    virtual ~NodeRareDataBase() { }
     119protected:
     120    NodeRareDataBase() { }
     121private:
     122    RenderObject* m_renderer;
     123};
     124
    114125class Node : public EventTarget, public ScriptWrappable, public TreeShared<Node, ContainerNode> {
    115126    friend class Document;
     
    500511    // Integration with rendering tree
    501512
    502     RenderObject* renderer() const { return m_renderer; }
    503     void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
    504    
     513    // As renderer() includes a branch you should avoid calling it repeatedly in hot code paths.
     514    RenderObject* renderer() const { return hasRareData() ? m_data.m_rareData->renderer() : m_data.m_renderer; };
     515    void setRenderer(RenderObject* renderer)
     516    {
     517        if (hasRareData())
     518            m_data.m_rareData->setRenderer(renderer);
     519        else
     520            m_data.m_renderer = renderer;
     521    }
     522
    505523    // Use these two methods with caution.
    506524    RenderBox* renderBox() const;
     
    810828    Node* m_previous;
    811829    Node* m_next;
    812     RenderObject* m_renderer;
     830    // When a node has rare data we move the renderer into the rare data.
     831    union DataUnion {
     832        DataUnion() : m_renderer(0) { }
     833        RenderObject* m_renderer;
     834        NodeRareDataBase* m_rareData;
     835    } m_data;
    813836
    814837protected:
  • trunk/Source/WebCore/dom/NodeRareData.h

    r133275 r133372  
    179179};
    180180
    181 class NodeRareData {
     181class NodeRareData : public NodeRareDataBase {
    182182    WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED;
    183183public:   
     
    201201    }
    202202
    203     typedef HashMap<const Node*, NodeRareData*> NodeRareDataMap;
    204    
    205     static NodeRareDataMap& rareDataMap()
    206     {
    207         static NodeRareDataMap* dataMap = new NodeRareDataMap;
    208         return *dataMap;
    209     }
    210    
    211     static NodeRareData* rareDataFromMap(const Node* node)
    212     {
    213         return rareDataMap().get(node);
    214     }
    215 
    216203    TreeScope* treeScope() const { return m_treeScope; }
    217204    void setTreeScope(TreeScope* treeScope) { m_treeScope = treeScope; }
  • trunk/Source/WebCore/dom/NodeRenderStyle.h

    r132684 r133372  
    3636    // Using a ternary here confuses the Solaris Studio 12/12.1/12.2 compilers:
    3737    // Bug is CR 6569194, "Problem with question operator binding in inline function"
    38     if (m_renderer)
    39         return m_renderer->style();
     38    if (RenderObject* renderer = this->renderer())
     39        return renderer->style();
    4040    return nonRendererStyle();
    4141}
  • trunk/Source/WebCore/dom/Text.cpp

    r130190 r133372  
    257257        willRecalcTextStyle(change);
    258258
    259     if (change != NoChange && parentNode() && parentNode()->renderer()) {
    260         if (renderer())
    261             renderer()->setStyle(parentNode()->renderer()->style());
    262     }
     259    RenderObject* renderer = this->renderer();
     260
     261    // The only time we have a renderer and our parent doesn't is if our parent
     262    // is a shadow root.
     263    if (change != NoChange && renderer && !parentNode()->isShadowRoot())
     264        renderer->setStyle(parentNode()->renderer()->style());
     265
    263266    if (needsStyleRecalc()) {
    264         if (renderer()) {
    265             if (renderer()->isText())
    266                 toRenderText(renderer())->setText(dataImpl());
     267        if (renderer) {
     268            if (renderer->isText())
     269                toRenderText(renderer)->setText(dataImpl());
    267270        } else
    268271            reattach();
  • trunk/Source/WebCore/dom/WebCoreMemoryInstrumentation.cpp

    r133298 r133372  
    3131#include "config.h"
    3232#include "WebCoreMemoryInstrumentation.h"
    33 
    34 #include "Node.h"
    35 #include "NodeRareData.h"
    36 #include <wtf/MemoryInstrumentationHashMap.h>
    3733
    3834namespace WebCore {
     
    7773MemoryObjectType WebCoreMemoryTypes::ProcessPrivateMemory = "ProcessPrivateMemory";
    7874
    79 void WebCoreMemoryInstrumentation::reportMemoryUsage(MemoryInstrumentation* memoryInstrumentation)
    80 {
    81     memoryInstrumentation->addRootObject(NodeRareData::rareDataMap(), WebCoreMemoryTypes::DOM);
    82 }
    83 
    8475} // namespace WebCore
  • trunk/Source/WebCore/dom/WebCoreMemoryInstrumentation.h

    r133298 r133372  
    8282};
    8383
    84 class WebCoreMemoryInstrumentation {
    85 public:
    86     static void reportMemoryUsage(MemoryInstrumentation*);
    87 };
    88 
    8984} // namespace WebCore
    9085
  • trunk/Source/WebCore/inspector/InspectorMemoryAgent.cpp

    r133298 r133372  
    537537    RefPtr<InspectorMemoryBlocks> children = InspectorMemoryBlocks::create();
    538538    addPlatformComponentsInfo(children);
    539     WebCoreMemoryInstrumentation::reportMemoryUsage(&memoryInstrumentation);
    540539
    541540    memoryInstrumentation.addRootObject(this);
Note: See TracChangeset for help on using the changeset viewer.