Add performance tests for DOM attribute getters and setters
authorharaken@chromium.org <haraken@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 08:55:59 +0000 (08:55 +0000)
committerharaken@chromium.org <haraken@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 08:55:59 +0000 (08:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=79208

Reviewed by Ryosuke Niwa.

PerformanceTests:

This patch adds performance micro-benchmarks for DOM attribute
getters and setters. We selected DOM attributes from HTMLElement,
Element and Node which will most impact on the DOM performance
in the real Web and which have different call-paths from another
DOM attribute.

The perf test result in my local Chromium/Linux environment is as follows:
median= 14967.0 ms, stdev= 85.2385476178 ms, min= 14861.0 ms, max= 15155.0 ms

If we run the test with DumpRenderTree, we can get the following test results:
Info: [HTMLElement.id] avg=65.76ms, median=65.00ms, stdev=2.14ms, min=63, max=70
Info: [HTMLElement.title] avg=64.05ms, median=63.00ms, stdev=1.50ms, min=63, max=67
Info: [HTMLElement.lang] avg=64.19ms, median=63.00ms, stdev=1.82ms, min=62, max=67
Info: [HTMLElement.dir] avg=64.10ms, median=63.00ms, stdev=1.72ms, min=62, max=68
Info: [HTMLElement.className] avg=63.33ms, median=63.00ms, stdev=0.89ms, min=63, max=67
Info: [HTMLElement.classList] avg=1946.00ms, median=1945.00ms, stdev=38.22ms, min=1921, max=2110
Info: [HTMLElement.tabIndex] avg=83.52ms, median=80.00ms, stdev=6.00ms, min=79, max=94
Info: [HTMLElement.draggable] avg=78.14ms, median=81.00ms, stdev=3.51ms, min=74, max=82
Info: [HTMLElement.webkitdropzone] avg=64.33ms, median=63.00ms, stdev=1.98ms, min=63, max=68
Info: [HTMLElement.hidden] avg=65.57ms, median=64.00ms, stdev=3.27ms, min=63, max=71
Info: [HTMLElement.accessKey] avg=64.43ms, median=63.00ms, stdev=2.11ms, min=62, max=68
Info: [HTMLElement.children] avg=130.76ms, median=128.00ms, stdev=9.75ms, min=109, max=143
Info: [HTMLElement.isContentEditable] avg=74.29ms, median=75.00ms, stdev=2.00ms, min=71, max=77
Info: [HTMLElement.spellcheck] avg=79.52ms, median=80.00ms, stdev=2.52ms, min=76, max=82
Info: [HTMLElement.innerHTML] avg=279.05ms, median=279.00ms, stdev=1.96ms, min=276, max=283
Info: [HTMLElement.innerText] avg=204.14ms, median=203.00ms, stdev=2.95ms, min=200, max=210
Info: [HTMLElement.outerHTML] avg=1544.10ms, median=1546.00ms, stdev=15.56ms, min=1514, max=1568
Info: [HTMLElement.outerText] avg=216.05ms, median=207.00ms, stdev=18.19ms, min=201, max=247
Info: [HTMLElement.contentEditable] avg=334.24ms, median=323.00ms, stdev=36.06ms, min=318, max=446
Info: [HTMLElement.id="foo"] avg=53.19ms, median=53.00ms, stdev=1.76ms, min=52, max=58
Info: [HTMLElement.title="foo"] avg=63.14ms, median=63.00ms, stdev=0.35ms, min=63, max=64
Info: [HTMLElement.lang="foo"] avg=60.86ms, median=61.00ms, stdev=0.56ms, min=60, max=62
Info: [HTMLElement.dir="foo"] avg=53.57ms, median=54.00ms, stdev=0.58ms, min=53, max=55
Info: [HTMLElement.className="foo"] avg=64.52ms, median=64.00ms, stdev=0.91ms, min=63, max=66
Info: [HTMLElement.tabIndex="foo"] avg=367.86ms, median=369.00ms, stdev=8.06ms, min=352, max=380
Info: [HTMLElement.draggable="foo"] avg=79.43ms, median=79.00ms, stdev=0.58ms, min=79, max=81
Info: [HTMLElement.webkitdropzone="foo"] avg=62.14ms, median=62.00ms, stdev=0.35ms, min=62, max=63
Info: [HTMLElement.hidden="foo"] avg=61.67ms, median=62.00ms, stdev=0.71ms, min=61, max=64
Info: [HTMLElement.accessKey="foo"] avg=61.86ms, median=62.00ms, stdev=0.56ms, min=61, max=63
Info: [HTMLElement.spellcheck="foo"] avg=79.57ms, median=80.00ms, stdev=0.58ms, min=78, max=80
Info: [HTMLElement.innerHTML="foo"] avg=1176.67ms, median=1169.00ms, stdev=26.60ms, min=1146, max=1246
Info: [HTMLElement.innerText="foo"] avg=51.62ms, median=52.00ms, stdev=0.72ms, min=50, max=53
Info: [Element.tagName] avg=79.52ms, median=80.00ms, stdev=1.05ms, min=78, max=81
Info: [Element.style] avg=126.19ms, median=126.00ms, stdev=10.40ms, min=104, max=161
Info: [Element.offsetLeft] avg=98.95ms, median=104.00ms, stdev=4.01ms, min=100, max=99
Info: [Element.clientLeft] avg=98.33ms, median=102.00ms, stdev=2.59ms, min=100, max=99
Info: [Element.scrollLeft] avg=103.29ms, median=96.00ms, stdev=15.63ms, min=100, max=97
Info: [Element.dataset] avg=2448.62ms, median=2441.00ms, stdev=20.43ms, min=2426, max=2503
Info: [Element.firstElementChild] avg=58.71ms, median=58.00ms, stdev=2.37ms, min=57, max=65
Info: [Element.lastElementChild] avg=56.33ms, median=55.00ms, stdev=1.83ms, min=54, max=59
Info: [Element.previousElementSibling] avg=52.95ms, median=52.00ms, stdev=1.70ms, min=52, max=57
Info: [Element.nextElementSibling] avg=58.48ms, median=58.00ms, stdev=1.79ms, min=57, max=63
Info: [Element.childElementCount] avg=64.57ms, median=64.00ms, stdev=1.81ms, min=63, max=71
Info: [Element.onload] avg=98.38ms, median=98.00ms, stdev=0.49ms, min=98, max=99
Info: [Element.scrollLeft="foo"] avg=95.24ms, median=95.00ms, stdev=0.92ms, min=94, max=98
Info: [Element.onload="foo"] avg=67.14ms, median=67.00ms, stdev=0.56ms, min=66, max=68
Info: [Node.nodeName] avg=76.29ms, median=76.00ms, stdev=0.63ms, min=75, max=77
Info: [Node.nodeType] avg=53.05ms, median=52.00ms, stdev=2.61ms, min=52, max=61
Info: [Node.parentNode] avg=53.52ms, median=53.00ms, stdev=1.22ms, min=52, max=56
Info: [Node.childNodes] avg=118.33ms, median=123.00ms, stdev=8.85ms, min=107, max=129
Info: [Node.firstChild] avg=53.62ms, median=53.00ms, stdev=1.13ms, min=51, max=55
Info: [Node.lastChild] avg=53.14ms, median=53.00ms, stdev=1.21ms, min=52, max=55
Info: [Node.previousSibling] avg=51.86ms, median=51.00ms, stdev=1.55ms, min=50, max=54
Info: [Node.nextSibling] avg=52.86ms, median=54.00ms, stdev=1.81ms, min=50, max=55
Info: [Node.attributes] avg=2027.71ms, median=2026.00ms, stdev=10.48ms, min=2010, max=2051
Info: [Node.ownerDocument] avg=152.14ms, median=152.00ms, stdev=1.73ms, min=149, max=155
Info: [Node.namespaceURI] avg=60.86ms, median=59.00ms, stdev=3.85ms, min=56, max=66
Info: [Node.localName] avg=60.00ms, median=59.00ms, stdev=2.71ms, min=57, max=66
Info: [Node.baseURI] avg=671.10ms, median=668.00ms, stdev=10.66ms, min=659, max=706
Info: [Node.parentElement] avg=55.05ms, median=56.00ms, stdev=2.15ms, min=52, max=58
Info: [Node.nodeValue] avg=61.24ms, median=60.00ms, stdev=2.56ms, min=59, max=68
Info: [Node.prefix] avg=60.90ms, median=58.00ms, stdev=4.26ms, min=57, max=68
Info: [Node.textContent] avg=149.71ms, median=149.00ms, stdev=1.12ms, min=148, max=152
Info: [Node.nodeValue="foo"] avg=23.62ms, median=23.00ms, stdev=0.72ms, min=23, max=25
Info: [Node.prefix="foo"] avg=49.57ms, median=49.00ms, stdev=0.73ms, min=49, max=51
Info: [Node.textContent="foo"] avg=145.81ms, median=140.00ms, stdev=17.43ms, min=138, max=199

* Bindings/dom_attributes.html: Added.
* resources/runner.js:
(PerfTestRunner.info):

Tools:

We want to allow perf tests to output info messages
that do not affect the test results. To accomplish this,
this patch modifies perftestsrunner.py so that it ignores
a line that starts from "Info:".

* Scripts/webkitpy/performance_tests/perftestsrunner.py:
(PerfTestsRunner):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108748 268f45cc-cd09-0410-ab3c-d52691b4dbfc

PerformanceTests/Bindings/dom_attributes.html [new file with mode: 0644]
PerformanceTests/ChangeLog
PerformanceTests/resources/runner.js
Tools/ChangeLog
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py

diff --git a/PerformanceTests/Bindings/dom_attributes.html b/PerformanceTests/Bindings/dom_attributes.html
new file mode 100644 (file)
index 0000000..c4e6c3b
--- /dev/null
@@ -0,0 +1,496 @@
+<!DOCTYPE html>
+<body>
+<script src="../resources/runner.js"></script>
+<script>
+
+var getterRepeat = 3000000;
+var setterRepeat = 500000;
+
+var times = {};
+
+PerfTestRunner.run(function() {
+    var tests = [{name: 'HTMLElement.id',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.id;
+                        }
+                 },
+                 {name: 'HTMLElement.title',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.title;
+                        }
+                 },
+                 {name: 'HTMLElement.lang',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.lang;
+                        }
+                 },
+                 {name: 'HTMLElement.dir',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.dir;
+                        }
+                 },
+                 {name: 'HTMLElement.className',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.className;
+                        }
+                 },
+                 {name: 'HTMLElement.classList',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.classList;
+                        }
+                 },
+                 {name: 'HTMLElement.tabIndex',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.tabIndex;
+                        }
+                 },
+                 {name: 'HTMLElement.draggable',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.draggable;
+                        }
+                 },
+                 {name: 'HTMLElement.webkitdropzone',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.webkitdropzone;
+                        }
+                 },
+                 {name: 'HTMLElement.hidden',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.hidden;
+                        }
+                 },
+                 {name: 'HTMLElement.accessKey',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.accessKey;
+                        }
+                 },
+                 {name: 'HTMLElement.children',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.children;
+                        }
+                 },
+                 {name: 'HTMLElement.isContentEditable',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.isContentEditable;
+                        }
+                 },
+                 {name: 'HTMLElement.spellcheck',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.spellcheck;
+                        }
+                 },
+                 {name: 'HTMLElement.innerHTML',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.innerHTML;
+                        }
+                 },
+                 {name: 'HTMLElement.innerText',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.innerText;
+                        }
+                 },
+                 {name: 'HTMLElement.outerHTML',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.outerHTML;
+                        }
+                 },
+                 {name: 'HTMLElement.outerText',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.outerText;
+                        }
+                 },
+                 {name: 'HTMLElement.contentEditable',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.contentEditable;
+                        }
+                 },
+                 {name: 'HTMLElement.id="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.id = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.title="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.title = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.lang="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.lang = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.dir="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.dir = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.className="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.className = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.tabIndex="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.tabIndex = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.draggable="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.draggable = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.webkitdropzone="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.webkitdropzone = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.hidden="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.hidden = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.accessKey="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.accessKey = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.spellcheck="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.spellcheck = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.innerHTML="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.innerHTML = "foo";
+                        }
+                 },
+                 {name: 'HTMLElement.innerText="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.innerText = "foo";
+                        }
+                 },
+                 {name: 'Element.tagName',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.tagName;
+                        }
+                 },
+                 {name: 'Element.style',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.style;
+                        }
+                 },
+                 {name: 'Element.offsetLeft',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.offsetLeft;
+                        }
+                 },
+                 {name: 'Element.clientLeft',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.clientLeft;
+                        }
+                 },
+                 {name: 'Element.scrollLeft',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.scrollLeft;
+                        }
+                 },
+                 {name: 'Element.dataset',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.dataset;
+                        }
+                 },
+                 {name: 'Element.firstElementChild',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.firstElementChild;
+                        }
+                 },
+                 {name: 'Element.lastElementChild',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.lastElementChild;
+                        }
+                 },
+                 {name: 'Element.previousElementSibling',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.previousElementSibling;
+                        }
+                 },
+                 {name: 'Element.nextElementSibling',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.nextElementSibling;
+                        }
+                 },
+                 {name: 'Element.childElementCount',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.childElementCount;
+                        }
+                 },
+                 {name: 'Element.onload',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.onload;
+                        }
+                 },
+                 {name: 'Element.scrollLeft="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.scrollLeft = "foo";
+                        }
+                 },
+                 {name: 'Element.onload="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.onload = "foo";
+                        }
+                 },
+                 {name: 'Node.nodeName',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.nodeName;
+                        }
+                 },
+                 {name: 'Node.nodeType',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.nodeType;
+                        }
+                 },
+                 {name: 'Node.parentNode',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.parentNode;
+                        }
+                 },
+                 {name: 'Node.childNodes',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.childNodes;
+                        }
+                 },
+                 {name: 'Node.firstChild',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.firstChild;
+                        }
+                 },
+                 {name: 'Node.lastChild',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.lastChild;
+                        }
+                 },
+                 {name: 'Node.previousSibling',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.previousSibling;
+                        }
+                 },
+                 {name: 'Node.nextSibling',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.nextSibling;
+                        }
+                 },
+                 {name: 'Node.attributes',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.attributes;
+                        }
+                 },
+                 {name: 'Node.ownerDocument',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.ownerDocument;
+                        }
+                 },
+                 {name: 'Node.namespaceURI',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.namespaceURI;
+                        }
+                 },
+                 {name: 'Node.localName',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.localName;
+                        }
+                 },
+                 {name: 'Node.baseURI',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.baseURI;
+                        }
+                 },
+                 {name: 'Node.parentElement',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.parentElement;
+                        }
+                 },
+                 {name: 'Node.nodeValue',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.nodeValue;
+                        }
+                 },
+                 {name: 'Node.prefix',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.prefix;
+                        }
+                 },
+                 {name: 'Node.textContent',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < getterRepeat; i++)
+                                div.textContent;
+                        }
+                 },
+                 {name: 'Node.nodeValue="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.nodeValue = "foo";
+                        }
+                 },
+                 {name: 'Node.prefix="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.prefix = "foo";
+                        }
+                 },
+                 {name: 'Node.textContent="foo"',
+                  func: function() {
+                            var div = document.createElement("div");
+                            for (var i = 0; i < setterRepeat; i++)
+                                div.textContent = "foo";
+                        }
+                 },
+                ];
+    runTests(tests);
+}, 1, undefined, onCompleted);
+
+function runTests(tests) {
+    for (var i = 0; i < tests.length; i++) {
+        var start = Date.now();
+        (tests[i].func)();
+        if (times[tests[i].name] === undefined)
+            times[tests[i].name] = [];
+        times[tests[i].name].push(Date.now() - start);
+    }
+}
+
+function onCompleted() {
+    for (var name in times) {
+        var statistics = PerfTestRunner.computeStatistics(times[name]);
+        PerfTestRunner.info("[" + name + "] avg=" + statistics.mean.toFixed(2) + "ms, median=" + statistics.median.toFixed(2) + "ms, stdev=" + statistics.stdev.toFixed(2) + "ms, min=" + statistics.min + ", max=" + statistics.max);
+    }
+}
+</script>
+</body>
+</html>
index 027d7ca..c2038b0 100644 (file)
@@ -1,3 +1,91 @@
+2012-02-24  Kentaro Hara  <haraken@chromium.org>
+
+        Add performance tests for DOM attribute getters and setters
+        https://bugs.webkit.org/show_bug.cgi?id=79208
+
+        Reviewed by Ryosuke Niwa.
+
+        This patch adds performance micro-benchmarks for DOM attribute
+        getters and setters. We selected DOM attributes from HTMLElement,
+        Element and Node which will most impact on the DOM performance
+        in the real Web and which have different call-paths from another
+        DOM attribute.
+
+        The perf test result in my local Chromium/Linux environment is as follows:
+        median= 14967.0 ms, stdev= 85.2385476178 ms, min= 14861.0 ms, max= 15155.0 ms
+
+        If we run the test with DumpRenderTree, we can get the following test results:
+        Info: [HTMLElement.id] avg=65.76ms, median=65.00ms, stdev=2.14ms, min=63, max=70
+        Info: [HTMLElement.title] avg=64.05ms, median=63.00ms, stdev=1.50ms, min=63, max=67
+        Info: [HTMLElement.lang] avg=64.19ms, median=63.00ms, stdev=1.82ms, min=62, max=67
+        Info: [HTMLElement.dir] avg=64.10ms, median=63.00ms, stdev=1.72ms, min=62, max=68
+        Info: [HTMLElement.className] avg=63.33ms, median=63.00ms, stdev=0.89ms, min=63, max=67
+        Info: [HTMLElement.classList] avg=1946.00ms, median=1945.00ms, stdev=38.22ms, min=1921, max=2110
+        Info: [HTMLElement.tabIndex] avg=83.52ms, median=80.00ms, stdev=6.00ms, min=79, max=94
+        Info: [HTMLElement.draggable] avg=78.14ms, median=81.00ms, stdev=3.51ms, min=74, max=82
+        Info: [HTMLElement.webkitdropzone] avg=64.33ms, median=63.00ms, stdev=1.98ms, min=63, max=68
+        Info: [HTMLElement.hidden] avg=65.57ms, median=64.00ms, stdev=3.27ms, min=63, max=71
+        Info: [HTMLElement.accessKey] avg=64.43ms, median=63.00ms, stdev=2.11ms, min=62, max=68
+        Info: [HTMLElement.children] avg=130.76ms, median=128.00ms, stdev=9.75ms, min=109, max=143
+        Info: [HTMLElement.isContentEditable] avg=74.29ms, median=75.00ms, stdev=2.00ms, min=71, max=77
+        Info: [HTMLElement.spellcheck] avg=79.52ms, median=80.00ms, stdev=2.52ms, min=76, max=82
+        Info: [HTMLElement.innerHTML] avg=279.05ms, median=279.00ms, stdev=1.96ms, min=276, max=283
+        Info: [HTMLElement.innerText] avg=204.14ms, median=203.00ms, stdev=2.95ms, min=200, max=210
+        Info: [HTMLElement.outerHTML] avg=1544.10ms, median=1546.00ms, stdev=15.56ms, min=1514, max=1568
+        Info: [HTMLElement.outerText] avg=216.05ms, median=207.00ms, stdev=18.19ms, min=201, max=247
+        Info: [HTMLElement.contentEditable] avg=334.24ms, median=323.00ms, stdev=36.06ms, min=318, max=446
+        Info: [HTMLElement.id="foo"] avg=53.19ms, median=53.00ms, stdev=1.76ms, min=52, max=58
+        Info: [HTMLElement.title="foo"] avg=63.14ms, median=63.00ms, stdev=0.35ms, min=63, max=64
+        Info: [HTMLElement.lang="foo"] avg=60.86ms, median=61.00ms, stdev=0.56ms, min=60, max=62
+        Info: [HTMLElement.dir="foo"] avg=53.57ms, median=54.00ms, stdev=0.58ms, min=53, max=55
+        Info: [HTMLElement.className="foo"] avg=64.52ms, median=64.00ms, stdev=0.91ms, min=63, max=66
+        Info: [HTMLElement.tabIndex="foo"] avg=367.86ms, median=369.00ms, stdev=8.06ms, min=352, max=380
+        Info: [HTMLElement.draggable="foo"] avg=79.43ms, median=79.00ms, stdev=0.58ms, min=79, max=81
+        Info: [HTMLElement.webkitdropzone="foo"] avg=62.14ms, median=62.00ms, stdev=0.35ms, min=62, max=63
+        Info: [HTMLElement.hidden="foo"] avg=61.67ms, median=62.00ms, stdev=0.71ms, min=61, max=64
+        Info: [HTMLElement.accessKey="foo"] avg=61.86ms, median=62.00ms, stdev=0.56ms, min=61, max=63
+        Info: [HTMLElement.spellcheck="foo"] avg=79.57ms, median=80.00ms, stdev=0.58ms, min=78, max=80
+        Info: [HTMLElement.innerHTML="foo"] avg=1176.67ms, median=1169.00ms, stdev=26.60ms, min=1146, max=1246
+        Info: [HTMLElement.innerText="foo"] avg=51.62ms, median=52.00ms, stdev=0.72ms, min=50, max=53
+        Info: [Element.tagName] avg=79.52ms, median=80.00ms, stdev=1.05ms, min=78, max=81
+        Info: [Element.style] avg=126.19ms, median=126.00ms, stdev=10.40ms, min=104, max=161
+        Info: [Element.offsetLeft] avg=98.95ms, median=104.00ms, stdev=4.01ms, min=100, max=99
+        Info: [Element.clientLeft] avg=98.33ms, median=102.00ms, stdev=2.59ms, min=100, max=99
+        Info: [Element.scrollLeft] avg=103.29ms, median=96.00ms, stdev=15.63ms, min=100, max=97
+        Info: [Element.dataset] avg=2448.62ms, median=2441.00ms, stdev=20.43ms, min=2426, max=2503
+        Info: [Element.firstElementChild] avg=58.71ms, median=58.00ms, stdev=2.37ms, min=57, max=65
+        Info: [Element.lastElementChild] avg=56.33ms, median=55.00ms, stdev=1.83ms, min=54, max=59
+        Info: [Element.previousElementSibling] avg=52.95ms, median=52.00ms, stdev=1.70ms, min=52, max=57
+        Info: [Element.nextElementSibling] avg=58.48ms, median=58.00ms, stdev=1.79ms, min=57, max=63
+        Info: [Element.childElementCount] avg=64.57ms, median=64.00ms, stdev=1.81ms, min=63, max=71
+        Info: [Element.onload] avg=98.38ms, median=98.00ms, stdev=0.49ms, min=98, max=99
+        Info: [Element.scrollLeft="foo"] avg=95.24ms, median=95.00ms, stdev=0.92ms, min=94, max=98
+        Info: [Element.onload="foo"] avg=67.14ms, median=67.00ms, stdev=0.56ms, min=66, max=68
+        Info: [Node.nodeName] avg=76.29ms, median=76.00ms, stdev=0.63ms, min=75, max=77
+        Info: [Node.nodeType] avg=53.05ms, median=52.00ms, stdev=2.61ms, min=52, max=61
+        Info: [Node.parentNode] avg=53.52ms, median=53.00ms, stdev=1.22ms, min=52, max=56
+        Info: [Node.childNodes] avg=118.33ms, median=123.00ms, stdev=8.85ms, min=107, max=129
+        Info: [Node.firstChild] avg=53.62ms, median=53.00ms, stdev=1.13ms, min=51, max=55
+        Info: [Node.lastChild] avg=53.14ms, median=53.00ms, stdev=1.21ms, min=52, max=55
+        Info: [Node.previousSibling] avg=51.86ms, median=51.00ms, stdev=1.55ms, min=50, max=54
+        Info: [Node.nextSibling] avg=52.86ms, median=54.00ms, stdev=1.81ms, min=50, max=55
+        Info: [Node.attributes] avg=2027.71ms, median=2026.00ms, stdev=10.48ms, min=2010, max=2051
+        Info: [Node.ownerDocument] avg=152.14ms, median=152.00ms, stdev=1.73ms, min=149, max=155
+        Info: [Node.namespaceURI] avg=60.86ms, median=59.00ms, stdev=3.85ms, min=56, max=66
+        Info: [Node.localName] avg=60.00ms, median=59.00ms, stdev=2.71ms, min=57, max=66
+        Info: [Node.baseURI] avg=671.10ms, median=668.00ms, stdev=10.66ms, min=659, max=706
+        Info: [Node.parentElement] avg=55.05ms, median=56.00ms, stdev=2.15ms, min=52, max=58
+        Info: [Node.nodeValue] avg=61.24ms, median=60.00ms, stdev=2.56ms, min=59, max=68
+        Info: [Node.prefix] avg=60.90ms, median=58.00ms, stdev=4.26ms, min=57, max=68
+        Info: [Node.textContent] avg=149.71ms, median=149.00ms, stdev=1.12ms, min=148, max=152
+        Info: [Node.nodeValue="foo"] avg=23.62ms, median=23.00ms, stdev=0.72ms, min=23, max=25
+        Info: [Node.prefix="foo"] avg=49.57ms, median=49.00ms, stdev=0.73ms, min=49, max=51
+        Info: [Node.textContent="foo"] avg=145.81ms, median=140.00ms, stdev=17.43ms, min=138, max=199
+
+        * Bindings/dom_attributes.html: Added.
+        * resources/runner.js:
+        (PerfTestRunner.info):
+
 2012-02-22  Kentaro Hara  <haraken@chromium.org>
 
         Add performance tests for the Element.id getter and setter
index dd8a004..f7b1473 100644 (file)
@@ -11,6 +11,10 @@ PerfTestRunner.log = function (text) {
     window.scrollTo(0, document.body.height);
 }
 
+PerfTestRunner.info = function (text) {
+    this.log("Info: " + text);
+}
+
 PerfTestRunner.logInfo = function (text) {
     if (!window.layoutTestController)
         this.log(text);
index a4e51b2..3038e2e 100644 (file)
@@ -1,3 +1,18 @@
+2012-02-24  Kentaro Hara  <haraken@chromium.org>
+
+        Add performance tests for DOM attribute getters and setters
+        https://bugs.webkit.org/show_bug.cgi?id=79208
+
+        Reviewed by Ryosuke Niwa.
+
+        We want to allow perf tests to output info messages
+        that do not affect the test results. To accomplish this,
+        this patch modifies perftestsrunner.py so that it ignores
+        a line that starts from "Info:".
+
+        * Scripts/webkitpy/performance_tests/perftestsrunner.py:
+        (PerfTestsRunner):
+
 2012-02-24  Andrew Lo  <anlo@rim.com>
 
         [BlackBerry] Enable requestAnimationFrame
index e35dacd..189500f 100644 (file)
@@ -259,6 +259,7 @@ class PerfTestsRunner(object):
     _lines_to_ignore_in_parser_result = [
         re.compile(r'^Running \d+ times$'),
         re.compile(r'^Ignoring warm-up '),
+        re.compile(r'^Info:'),
         re.compile(r'^\d+(.\d+)?$'),
         # Following are for handle existing test like Dromaeo
         re.compile(re.escape("""main frame - has 1 onunload handler(s)""")),