Changeset 110992 in webkit
- Timestamp:
- Mar 16, 2012 5:31:57 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r110991 r110992 1 2012-03-16 Kentaro Hara <haraken@chromium.org> 2 3 [Performance] Optimize innerHTML and outerHTML 4 https://bugs.webkit.org/show_bug.cgi?id=81214 5 6 Reviewed by Adam Barth. 7 8 This patch makes innerHTML and outerHTML 2.4 times faster. 9 10 Performance test: https://bugs.webkit.org/attachment.cgi?id=132034 11 The performance test measures body.innerHTML for 3000 lines of HTML, 12 which is copied from the HTML spec. 13 14 - Chromium/Mac without the patch 15 div.innerHTML: 1658.6 ms 16 div.outerHTML: 4859.6 ms 17 body.innerHTML: 640.2 ms 18 body.outerHTML: 641.8 ms 19 20 - Chromium/Mac with the patch 21 div.innerHTML: 751.0 ms 22 div.outerHTML: 2096.0 ms 23 body.innerHTML: 271.2 ms 24 body.outerHTML: 271.2 ms 25 26 - Chromium/Linux without the patch 27 div.innerHTML: 950.4 ms 28 div.outerHTML: 2257.8 ms 29 body.innerHTML: 452.8 ms 30 body.outerHTML: 457.6 ms 31 32 - Chromium/Linux with the patch 33 div.innerHTML: 582.4 ms 34 div.outerHTML: 1283.0 ms 35 body.innerHTML: 233.0 ms 36 body.outerHTML: 233.4 ms 37 38 - AppleWebKit/Mac without the patch 39 div.innerHTML: 900.6 ms 40 div.outerHTML: 2245.2 ms 41 body.innerHTML: 462.6 ms 42 body.outerHTML: 468.0 ms 43 44 - AppleWebKit/Mac with the patch 45 div.innerHTML: 529.8 ms 46 div.outerHTML: 1090.2 ms 47 body.innerHTML: 239.2 ms 48 body.outerHTML: 239.2 ms 49 50 This patch applies the following two optimizations: 51 52 (a) Remove redundant copies between Vector<String> and StringBuilders 53 in MarkupAccumulator::serializeNodes(), MarkupAccumulator::appendStartTag(), 54 and MarkupAccumulator::appendEndTag(). 55 56 (Previous behavior) 57 - Create a StringBuilder for each tag. 58 - Append a created string in each StringBuilder to Vector<String>, 59 parsing the DOM tree. 60 - After the parsing, allocate a StringBuilder whose size is the sum 61 of all Strings in Vector<String>. 62 - Append all Strings in Vector<String> to the StringBuilder. 63 (New behavior) 64 - Allocate a StringBuilder with a default buffer size. 65 - Append created strings to the StringBuilder, incrementally parsing 66 the DOM tree. 67 68 (b) Optimize stringBuilder.append(). 69 (b-1) Replace stringBuilder.append("A") with stringBuilder.append('A'). 70 stringBuilder.append("A") requires to cast the characters to LChar*, 71 and then call strlen("A"). stringBuilder.append('A') is faster. 72 (b-2) Replace stringBuilder.append("AB") with stringBuilder.append('A') 73 and stringBuilder.append('B'). In my experiment, appending characters 74 one by one is faster than appending the characters at a breath if the 75 number of characters is less than 3. 76 (b-3) Hard-code a string length; i.e. replace stringBuilder.append("ABCDE") 77 with stringBuilder.append("ABCDE", 5). While the former requires to call 78 strlen("ABCDE"), the latter does not. 79 80 (a) improves performance by 170% ~ 200%. (b) improves performance by 30 ~ 40%. 81 82 Tests: fast/dom/Range/range-extract-contents.html 83 fast/dom/serialize-nodes.xhtml 84 fast/dom/XMLSerializer.html 85 and all other tests that use innerHTML or outerHTML. 86 No change in the test results. 87 88 * editing/MarkupAccumulator.cpp: 89 (WebCore::MarkupAccumulator::serializeNodes): 90 (WebCore::MarkupAccumulator::appendString): 91 (WebCore::MarkupAccumulator::appendStartTag): 92 (WebCore::MarkupAccumulator::appendEndTag): 93 (WebCore::MarkupAccumulator::concatenateMarkup): 94 (WebCore::MarkupAccumulator::appendQuotedURLAttributeValue): 95 (WebCore::MarkupAccumulator::appendComment): 96 (WebCore::MarkupAccumulator::appendDocumentType): 97 (WebCore::MarkupAccumulator::appendProcessingInstruction): 98 (WebCore::MarkupAccumulator::appendOpenTag): 99 (WebCore::MarkupAccumulator::appendAttribute): 100 (WebCore::MarkupAccumulator::appendCDATASection): 101 * editing/MarkupAccumulator.h: 102 (MarkupAccumulator): 103 1 104 2012-03-16 Kihong Kwon <kihong.kwon@samsung.com> 2 105 -
trunk/Source/WebCore/editing/MarkupAccumulator.cpp
r110915 r110992 38 38 #include "ProcessingInstruction.h" 39 39 #include "XMLNSNames.h" 40 #include <wtf/text/StringBuilder.h>41 40 #include <wtf/unicode/CharacterNames.h> 42 41 … … 88 87 String MarkupAccumulator::serializeNodes(Node* targetNode, Node* nodeToSkip, EChildrenOnly childrenOnly) 89 88 { 90 StringBuilder result;91 89 serializeNodesWithNamespaces(targetNode, nodeToSkip, childrenOnly, 0); 92 result.reserveCapacity(length()); 93 concatenateMarkup(result); 94 return result.toString(); 90 return m_markup.toString(); 95 91 } 96 92 … … 135 131 void MarkupAccumulator::appendString(const String& string) 136 132 { 137 m_ succeedingMarkup.append(string);133 m_markup.append(string); 138 134 } 139 135 140 136 void MarkupAccumulator::appendStartTag(Node* node, Namespaces* namespaces) 141 137 { 142 StringBuilder markup; 143 appendStartMarkup(markup, node, namespaces); 144 appendString(markup.toString()); 138 appendStartMarkup(m_markup, node, namespaces); 145 139 if (m_nodes) 146 140 m_nodes->append(node); … … 149 143 void MarkupAccumulator::appendEndTag(Node* node) 150 144 { 151 StringBuilder markup; 152 appendEndMarkup(markup, node); 153 appendString(markup.toString()); 145 appendEndMarkup(m_markup, node); 154 146 } 155 147 … … 162 154 } 163 155 164 // FIXME: This is a very inefficient way of accumulating the markup.165 // We're converting results of appendStartMarkup and appendEndMarkup from StringBuilder to String166 // and then back to StringBuilder and again to String here.167 156 void MarkupAccumulator::concatenateMarkup(StringBuilder& result) 168 157 { 169 for (size_t i = 0; i < m_succeedingMarkup.size(); ++i) 170 result.append(m_succeedingMarkup[i]); 158 result.append(m_markup); 171 159 } 172 160 … … 185 173 ASSERT(element->isURLAttribute(const_cast<Attribute*>(&attribute))); 186 174 const String resolvedURLString = resolveURLIfNeeded(element, attribute.value()); 187 UChar quoteChar = ' \"';175 UChar quoteChar = '"'; 188 176 String strippedURLString = resolvedURLString.stripWhiteSpace(); 189 177 if (protocolIsJavaScript(strippedURLString)) { … … 191 179 if (strippedURLString.contains('"')) { 192 180 if (strippedURLString.contains('\'')) 193 strippedURLString.replace(' \"', """);181 strippedURLString.replace('"', """); 194 182 else 195 183 quoteChar = '\''; … … 302 290 { 303 291 // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->". 304 result.append("<!--"); 292 static const char commentBegin[] = "<!--"; 293 result.append(commentBegin, sizeof(commentBegin) - 1); 305 294 result.append(comment); 306 result.append("-->"); 295 static const char commentEnd[] = "-->"; 296 result.append(commentEnd, sizeof(commentEnd) - 1); 307 297 } 308 298 … … 312 302 return; 313 303 314 result.append("<!DOCTYPE "); 304 static const char doctypeString[] = "<!DOCTYPE "; 305 result.append(doctypeString, sizeof(doctypeString) - 1); 315 306 result.append(n->name()); 316 307 if (!n->publicId().isEmpty()) { 317 result.append(" PUBLIC \""); 308 static const char publicString[] = " PUBLIC \""; 309 result.append(publicString, sizeof(publicString) - 1); 318 310 result.append(n->publicId()); 319 result.append( "\"");311 result.append('"'); 320 312 if (!n->systemId().isEmpty()) { 321 result.append(" \""); 313 result.append(' '); 314 result.append('"'); 322 315 result.append(n->systemId()); 323 result.append( "\"");316 result.append('"'); 324 317 } 325 318 } else if (!n->systemId().isEmpty()) { 326 result.append(" SYSTEM \""); 319 static const char systemString[] = " SYSTEM \""; 320 result.append(systemString, sizeof(systemString) - 1); 327 321 result.append(n->systemId()); 328 result.append( "\"");322 result.append('"'); 329 323 } 330 324 if (!n->internalSubset().isEmpty()) { 331 result.append(" ["); 325 result.append(' '); 326 result.append('['); 332 327 result.append(n->internalSubset()); 333 result.append( "]");334 } 335 result.append( ">");328 result.append(']'); 329 } 330 result.append('>'); 336 331 } 337 332 … … 339 334 { 340 335 // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>". 341 result.append("<?"); 336 result.append('<'); 337 result.append('?'); 342 338 result.append(target); 343 result.append( " ");339 result.append(' '); 344 340 result.append(data); 345 result.append("?>"); 341 result.append('?'); 342 result.append('>'); 346 343 } 347 344 … … 367 364 result.append(element->nodeNamePreservingCase()); 368 365 if (!element->document()->isHTMLDocument() && namespaces && shouldAddNamespaceElement(element)) 369 appendNamespace(result, element->prefix(), element->namespaceURI(), *namespaces); 366 appendNamespace(result, element->prefix(), element->namespaceURI(), *namespaces); 370 367 } 371 368 … … 396 393 appendQuotedURLAttributeValue(result, element, attribute); 397 394 else { 398 result.append(' \"');395 result.append('"'); 399 396 appendAttributeValue(result, attribute.value(), documentIsHTML); 400 result.append(' \"');397 result.append('"'); 401 398 } 402 399 … … 408 405 { 409 406 // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>". 410 result.append("<![CDATA["); 407 static const char cdataBegin[] = "<![CDATA["; 408 result.append(cdataBegin, sizeof(cdataBegin) - 1); 411 409 result.append(section); 412 result.append("]]>"); 410 static const char cdataEnd[] = "]]>"; 411 result.append(cdataEnd, sizeof(cdataEnd) - 1); 413 412 } 414 413 -
trunk/Source/WebCore/editing/MarkupAccumulator.h
r110915 r110992 31 31 #include <wtf/HashMap.h> 32 32 #include <wtf/Vector.h> 33 #include <wtf/text/StringBuilder.h> 33 34 34 35 namespace WebCore { … … 79 80 virtual void appendEndTag(Node*); 80 81 static size_t totalLength(const Vector<String>&); 81 size_t length() const { return totalLength(m_succeedingMarkup); }82 size_t length() const { return m_markup.length(); } 82 83 void concatenateMarkup(StringBuilder&); 83 84 void appendAttributeValue(StringBuilder&, const String&, bool); … … 109 110 void serializeNodesWithNamespaces(Node* targetNode, Node* nodeToSkip, EChildrenOnly, const Namespaces*); 110 111 111 Vector<String> m_succeedingMarkup;112 StringBuilder m_markup; 112 113 const EAbsoluteURLs m_resolveURLsMethod; 113 114 };
Note: See TracChangeset
for help on using the changeset viewer.