Add a balanced benchmark for QuerySelector
authorbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 May 2013 22:31:02 +0000 (22:31 +0000)
committerbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 May 2013 22:31:02 +0000 (22:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=116811

Reviewed by Sam Weinig.

The goal of this benchmark is to have an overview of querySelector as typically used
by webpages.

It uses queries similar to what is used by popular websites and applies somewhat
similar weighting for each type of query.

The tree used for the queries is intentionally kept simple to ensure we measure QuerySelector
a not purely the overhead of traversal.

* CSS/QuerySelector.html: Added.
* CSS/resources/query-selector.html: Added.

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

PerformanceTests/CSS/QuerySelector.html [new file with mode: 0644]
PerformanceTests/CSS/resources/query-selector.html [new file with mode: 0644]
PerformanceTests/ChangeLog

diff --git a/PerformanceTests/CSS/QuerySelector.html b/PerformanceTests/CSS/QuerySelector.html
new file mode 100644 (file)
index 0000000..0b20c7d
--- /dev/null
@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Query selector benchmark.</title>
+    <script src="../resources/runner.js"></script>
+</head>
+<body>
+    
+</body>
+<script>
+
+var iframe = document.createElement("iframe");
+iframe.style.display = "none";
+document.body.appendChild(iframe);
+
+function verifySizeExpectation(result, expectedSize)
+{
+    if (result.length != expectedSize)
+        throw "The query did not return the expected results."
+}
+
+var test = {
+    description: "This tests the performance of querySelector for a variety of common use cases.",
+    setup: function() {
+        // In order to restrict caching between operations, the tree is rebuilt from scratch.
+        var spec = PerfTestRunner.loadFile("resources/query-selector.html");
+        iframe.contentDocument.firstChild.innerHTML = spec;
+    },
+    run: function() {
+        var iFrameDocument = iframe.contentDocument;
+
+        for (var repeat = 0; repeat < 5; ++repeat) {
+            /// Various multiselector. About 15% of the queries.
+            for (var i = 0; i < 150; ++i) {
+                // Complex descent.
+                var result = iFrameDocument.querySelectorAll("html body div>#complex-multi-rules1 .some-class li[data-bar].some-class");
+                verifySizeExpectation(result, 1);
+
+                // id tag.
+                verifySizeExpectation(iFrameDocument.querySelectorAll("#complex-multi-rules2 acronym"), 1);
+                verifySizeExpectation(iFrameDocument.querySelectorAll("[id='complex-multi-rules2'] a"), 1);
+
+                // Multiple id + selector, sharing the same id.
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules3 source, #complex-multi-rules3 li, #complex-multi-rules3 td");
+                verifySizeExpectation(result, 11);
+                result = iFrameDocument.querySelectorAll("[id='complex-multi-rules3'] source, [id='complex-multi-rules3'] li, [id='complex-multi-rules3'] td");
+                verifySizeExpectation(result, 11);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules3 .some-class, #complex-multi-rules3 .other-class");
+                verifySizeExpectation(result, 7);
+                result = iFrameDocument.querySelectorAll("[id='complex-multi-rules3'] .some-class, [id='complex-multi-rules3'] li, [id='complex-multi-rules3'] .other-class");
+                verifySizeExpectation(result, 7);
+
+                // Several Ids.
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules4 #complex-multi-rules4-sub1 #complex-multi-rules4-sub2 #complex-multi-rules4-sub3");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules4 [id='complex-multi-rules4-sub1'] #complex-multi-rules4-sub2 [id='complex-multi-rules4-sub3']");
+                result = iFrameDocument.querySelectorAll("[id='complex-multi-rules4'] [id='complex-multi-rules4-sub1'] [id='complex-multi-rules4-sub2'] [id='complex-multi-rules4-sub3']");
+                verifySizeExpectation(result, 1);
+
+                // Id sandwich: Multiple ids with selectors in between.
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules5 div #complex-multi-rules5-left ul li.other-class #complex-multi-rules5-right table tr>td");
+                verifySizeExpectation(result, 2);
+                result = iFrameDocument.querySelectorAll("div#complex-multi-rules5>div div#complex-multi-rules5-left ul .other-class p img#complex-multi-rules5-image");
+                verifySizeExpectation(result, 1);
+
+                // Named form attribute under hierarchy.
+                result = iFrameDocument.querySelectorAll("input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form[name='complex-multi-rules6-form'] input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form[name='complex-multi-rules6-form'] div input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form[name='complex-multi-rules6-form'] div div input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form[name='complex-multi-rules6-form']>div>div>input[name='complex-multi-rules6-file-input']");
+                verifySizeExpectation(result, 1);
+
+                // Hierarchy of tag and class.
+                result = iFrameDocument.querySelectorAll("div div a div div p.result-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("div div.some-class a.other-class div.another-class div p.result-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("div>div>a div div p.result-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("div>div.some-class>a.other-class>div.another-class>div>p.result-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("div div a div div p.result-class, div div.some-class a div div p.result-class, div div.some-class a.other-class div div p.result-class, div div.some-class a.other-class div.another-class div p.result-class");
+                verifySizeExpectation(result, 1);
+            }
+
+            // tag.class. About 10% of the queries
+            for (var i = 0; i < 100; ++i) {
+                result = iFrameDocument.querySelectorAll("details.details-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("summary.summary-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("article.article-class");
+                verifySizeExpectation(result, 1);
+            }
+
+            // Single selector query, 75% of the queries. Split between:
+            //    -tag
+            //    -[attribute]
+            //         -exist
+            //         -value=something
+            //    -#id
+            //    -.class
+            for (var i = 0; i < 750; ++i) {
+                // Tags.
+                result = iFrameDocument.querySelectorAll("details");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("summary");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("article");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("head");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("body");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("form");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("input");
+                verifySizeExpectation(result, 1);
+
+                // Attributes exists.
+                result = iFrameDocument.querySelectorAll("[data-foo]");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[data-bar]");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[title]");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[href]");
+                verifySizeExpectation(result, 2);
+
+                // Attribute = value.
+                result = iFrameDocument.querySelectorAll("[data-foo=bar]");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[data-bar=baz]");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[title='WebKit Tempalte Framework']");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("[href='http://www.webkit.org/']");
+                verifySizeExpectation(result, 1);
+
+                // Id.
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules1");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules2");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules3");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules4");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules5");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules6");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules7");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll("#complex-multi-rules8");
+                verifySizeExpectation(result, 1);
+
+                // Id with duplicate.
+                result = iFrameDocument.querySelectorAll("#duplicate-id");
+                verifySizeExpectation(result, 3);
+
+                // .class.
+                result = iFrameDocument.querySelectorAll(".details-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll(".summary-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll(".article-class");
+                verifySizeExpectation(result, 1);
+                result = iFrameDocument.querySelectorAll(".result-class");
+                verifySizeExpectation(result, 1);
+            }
+        }
+    }
+}
+PerfTestRunner.measureTime(test);
+</script>
+</html>
\ No newline at end of file
diff --git a/PerformanceTests/CSS/resources/query-selector.html b/PerformanceTests/CSS/resources/query-selector.html
new file mode 100644 (file)
index 0000000..bfbd822
--- /dev/null
@@ -0,0 +1,146 @@
+<html>
+<body>
+    <div>
+        <div id=complex-multi-rules1>
+            <p>Complex descent.</p>
+            <div class=some-class>
+                <ul>
+                    <li data-foo="bar">one</li>
+                    <li>two</li>
+                    <li data-bar="baz" class=some-class>three</li>
+                </ul>
+            </div>
+        </div>
+
+        <div id=complex-multi-rules2>
+            <p>id + tag.</p>
+            <acronym title="WebKit Tempalte Framework">WTF</acronym>
+            <a href="http://www.apple.com">Link</a>
+        </div>
+
+        <div id=complex-multi-rules3>
+            <p>Multiple id + tag, sharing the same id.</p>
+            <audio>
+                <source class=some-class>
+                <source class=some-class>
+                <source class=some-class>
+            </audio>
+            <ol>
+                <li class=other-class>one</li>
+                <li class=other-class>two</li>
+                <li class=other-class>three</li>
+                <li class=other-class>four</li>
+            </ol>
+            <table>
+                <tr><td>cell</td><td>cell</td></tr>
+                <tr><td>cell</td><td>cell</td></tr>
+            </table>
+        </div>
+
+        <div id=complex-multi-rules4>
+            <p>Several Ids.</p>
+            Foo?
+            <div>
+                Bar?
+                <div id=complex-multi-rules4-sub1>
+                    Foo?
+                    <div>
+                        Bar?
+                        <div id=complex-multi-rules4-sub2>
+                            Foo?
+                            <div>
+                                <div id=complex-multi-rules4-sub3>
+                                    Foo Bar!
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div id=complex-multi-rules5>
+            <p>Id sandwich: Multiple ids with selectors in between.</p>
+            <div>
+                Padding.
+            </div>
+            <div>
+                <div id=complex-multi-rules5-left>
+                    <ul>
+                        <li class=other-class>one</li>
+                        <li class=other-class>two</li>
+                        <li class=other-class>
+                            three
+                            <div id=complex-multi-rules5-right>
+                                <p>complex-multi-rules5-right</p>
+                                <table>
+                                    <tr><td>cell</td><td>cell</td></tr>
+                                </table>
+                            </div>
+                        </li>
+                        <li class=other-class>
+                            four
+                            <p>Some text. <img id=complex-multi-rules5-image></p>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+        </div>
+
+        <div id=complex-multi-rules6>
+            <p>Named form attribute under hierarchy.</p>
+            <form name='complex-multi-rules6-form'>
+                <div>
+                    <div>
+                        <input type=file name=complex-multi-rules6-file-input>
+                    </div>
+                </div>
+            </form>
+        </div>
+
+        <div id=complex-multi-rules7>
+            <p>Hierarchy of tag and class.</p>
+            <div class=some-class>
+                <a href="http://www.webkit.org/" class=other-class>
+                    <div class=another-class>
+                        <div>
+                            <p class=result-class>FooBar!!!</p>
+                        </div>
+                    </div>
+                </a>
+            </div>
+        </div>
+
+        <div id=complex-multi-rules8>
+            <p>Commonly used restrictionselector.</p>
+            <div class=some-class>
+                <div class=some-class>
+                    <ul>
+                        <li>one</li>
+                        <li>two</li>
+                        <li>three</li>
+                    </ul>
+                </div>
+            </div>
+        </div>
+
+        <div id=tag-and-class>
+            <p>tag.class</p>
+            <details open class=details-class>
+                <summary class=summary-class>Summary</summary>
+                <p>Foo Bar!</p>
+            </details>
+            <article class=article-class>
+                <p>Lorem Ipsum</p>
+            </article>
+        </div>
+
+        <div id=duplicate-id>
+        </div>
+        <div id=duplicate-id>
+        </div>
+        <div id=duplicate-id>
+        </div>
+    </div>
+</body>
+</html>
\ No newline at end of file
index af4c69b..d24af56 100644 (file)
@@ -1,3 +1,22 @@
+2013-05-27  Benjamin Poulain  <benjamin@webkit.org>
+
+        Add a balanced benchmark for QuerySelector
+        https://bugs.webkit.org/show_bug.cgi?id=116811
+
+        Reviewed by Sam Weinig.
+
+        The goal of this benchmark is to have an overview of querySelector as typically used
+        by webpages.
+
+        It uses queries similar to what is used by popular websites and applies somewhat
+        similar weighting for each type of query.
+
+        The tree used for the queries is intentionally kept simple to ensure we measure QuerySelector
+        a not purely the overhead of traversal.
+
+        * CSS/QuerySelector.html: Added.
+        * CSS/resources/query-selector.html: Added.
+
 2013-05-18  Ryosuke Niwa  <rniwa@webkit.org>
 
         Add a performance test for copying