Adds a test for using querySelectorAll instead of getElementById. Faster, but
still not as fast as a crawl.

Also "corrects" the DOCTYPE (thought I had done so already), which seems to slow
down web kit's dom api calls!!

Reviewed by jgw
http://gwt-code-reviews.appspot.com/128807

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7393 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.java b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.java
index 2f2cc81..6e7505d 100644
--- a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.java
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.java
@@ -51,7 +51,8 @@
   @UiField DeckPanel deck;
   @UiField Button button;
   @UiField Element running;
-  @UiField Element elapsed;
+  @UiField Element runs;
+  @UiField Element sum;
 
   @UiHandler("listBox")
   public void onChange(@SuppressWarnings("unused") ChangeEvent ignored) {
@@ -68,11 +69,13 @@
       public void execute() {
         double start = Duration.currentTimeMillis();
         benchmarks[index].run();
+        double end = Duration.currentTimeMillis();
         UIObject.setVisible(running, false);
         button.setEnabled(true);
-        double end = Duration.currentTimeMillis();
-        elapsedMs += end - start;
-        elapsed.setInnerText(Util.format(elapsedMs));
+        double run = end - start;
+        runs.setInnerText(runs.getInnerText() + Util.format(run) + " ");
+        elapsedMs += run;
+        sum.setInnerText("(" + Util.format(elapsedMs) + ")");
       }
     });
   }
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.ui.xml b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.ui.xml
index 30f5785..70c51e4 100644
--- a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.ui.xml
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Microbenchmarks.ui.xml
@@ -5,7 +5,7 @@
     <div style='margin-left:1em; margin-top:1em;'>
       Select Benchmark: <gwt:ListBox ui:field='listBox'/>
       <gwt:Button ui:field='button'>Run</gwt:Button>
-      <span ui:field='elapsed'></span>
+      <span ui:field='runs'/><span ui:field='sum'/>
       <span style="display:none; color:gray; font-style:oblique" 
         ui:field='running'>Running...</span>
     </div>
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDom.java b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlById.java
similarity index 90%
rename from reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDom.java
rename to reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlById.java
index 1ecadfe..14ad279 100644
--- a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDom.java
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlById.java
@@ -24,13 +24,13 @@
 /**
  * Run by {@link WidgetCreation}, see {@link Maker#name} for details.
  */
-public class TestDom extends Widget {
+public class TestDomInnerHtmlById extends Widget {
   public static class Maker extends WidgetCreation.Maker {
     Maker() {
-      super("Text heavy UI via innerHTML, no widgets, get children by id");
+      super("Text heavy UI via innerHTML, no widgets, getElementById");
     }
     public Widget make() {
-      return new TestDom();
+      return new TestDomInnerHtmlById();
     }
   }
 
@@ -44,7 +44,7 @@
   
   SpanElement span2;
 
-  private TestDom() {
+  private TestDomInnerHtmlById() {
     root = Util.fromHtml(Util.TEXTY_OUTER_HTML);
     
     Document.get().getBody().appendChild(root);
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlQuerySelectorAll.java b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlQuerySelectorAll.java
new file mode 100644
index 0000000..868fc50
--- /dev/null
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/TestDomInnerHtmlQuerySelectorAll.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.reference.microbenchmark.client;
+
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.SpanElement;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Run by {@link WidgetCreation}, see {@link Maker#name} for details.
+ */
+public class TestDomInnerHtmlQuerySelectorAll extends Widget {
+  public static class Maker extends WidgetCreation.Maker {
+    Maker() {
+      super("Text heavy UI via innerHTML, no widgets, querySelectorAll");
+    }
+    public Widget make() {
+      return new TestDomInnerHtmlQuerySelectorAll();
+    }
+  }
+
+  Element root;
+  DivElement div1;
+  DivElement div2;
+  DivElement div3;
+
+  DivElement div4;
+  SpanElement span1;
+  
+  SpanElement span2;
+
+  private TestDomInnerHtmlQuerySelectorAll() {
+    root = Util.fromHtml(Util.TEXTY_OUTER_HTML);
+    
+    String query = "#div1, #div2, #div3, #div4, #span1, #span2";
+    JsArray<Element> response = Util.querySelectorAll(root, query);
+    assert 6 == response.length() : "response length should be 6: " + response.length();
+    
+    div1 = response.get(0).cast();
+    div2 = response.get(1).cast();
+    span1 = response.get(2).cast();
+    div3 =  response.get(3).cast();
+    div4 =  response.get(4).cast();
+    span2 = response.get(5).cast();
+    
+    assert div1.getId().equals("div1");
+    assert div2.getId().equals("div2");
+    assert span1.getId().equals("span1");
+    assert div3.getId().equals("div3");
+    assert div4.getId().equals("div4");
+    assert span2.getId().equals("span2");
+
+    div1.removeAttribute("id");
+    div2.removeAttribute("id");
+    span1.removeAttribute("id");
+    div3.removeAttribute("id");
+    div4.removeAttribute("id");
+    span2.removeAttribute("id");
+
+    setElement(root);
+  }
+}
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Util.java b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Util.java
index 84fd4e0..87749d6 100644
--- a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Util.java
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/Util.java
@@ -1,13 +1,17 @@
 package com.google.gwt.reference.microbenchmark.client;
 
+import com.google.gwt.core.client.JsArray;
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Node;
 import com.google.gwt.i18n.client.NumberFormat;
 
 class Util {
   private static final DivElement detachedDiv = Document.get().createDivElement();
 
+  static final boolean hasQSA = hasQSA();
+  
   static final String EMPTY_OUTER_HTML = "<div>" + Util.EMPTY_INNER_HTML + "</div>";
   
   static final String EMPTY_INNER_HTML = "<div id='div1'>"
@@ -22,7 +26,7 @@
     +   "</div>";
   
   static final String TEXTY_OUTER_HTML = "<div>" + Util.TEXTY_INNER_HTML + "</div>";
-
+  
   static final String TEXTY_INNER_HTML = "Div root start" 
   +   "<div id='div1'>Div1 start"
   +     "<div id='div2'>Div2</div>" 
@@ -35,10 +39,14 @@
   +     "Div 3 end</div>" 
   +   "Div anon end</div>"
   + "Div root end";
-  
+
   static void addText(Element elm, String text) {
     elm.appendChild(Document.get().createTextNode(text));
   }
+  
+  static String format(double median) {
+    return NumberFormat.getFormat("0").format(median);
+  }
 
   static Element fromHtml(String html) {
     Util.detachedDiv.setInnerHTML(html);
@@ -47,18 +55,23 @@
     return e;
   }
 
-  static long roundToTens(double median) {
-    return Math.round(median/10)*10;
-  }
-
-  static String format(double median) {
-    return NumberFormat.getFormat("0").format(median);
-  }
-
   static String outerHtml(Element e) {
     String string = "<" + e.getNodeName() + ">" 
     + e.getInnerHTML()
     + "</" + e.getNodeName() + ">";
     return string;
   }
+
+  static native JsArray<Element> querySelectorAll(Node root, String selector) /*-{
+    return root.querySelectorAll(selector);
+  }-*/;
+
+  static long roundToTens(double median) {
+    return Math.round(median/10)*10;
+  }
+  
+  private static native boolean hasQSA() /*-{
+    var qsa = document.querySelectorAll;
+    return !(null == qsa);
+  }-*/;
 }
diff --git a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/WidgetCreation.java b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/WidgetCreation.java
index 12459ca..149acc5 100644
--- a/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/WidgetCreation.java
+++ b/reference/Microbenchmarks/src/com/google/gwt/reference/microbenchmark/client/WidgetCreation.java
@@ -32,7 +32,10 @@
 import com.google.gwt.user.client.ui.TextBox;
 import com.google.gwt.user.client.ui.Widget;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 
 /**
  * Compares various widget creation strategies.
@@ -62,27 +65,43 @@
   final Grid grid;
 
   final TextBox number;
-  final Maker[] makers = {
-      new Maker("SimplePanel") {
-        public Widget make() {
-          return new SimplePanel();
-        }
-      }, new Maker("FlowPanel") {
-        public Widget make() {
-          return new FlowPanel();
-        }
-      }, new Maker("HTMLPanel") {
-        public Widget make() {
-          return new HTMLPanel("");
-        }
-      }, new EmptyBinder.Maker(), new TestEmptyDomViaApi.Maker(),
-      new TestEmptyDom.Maker(), 
-      new TestEmptyCursorDomCrawl.Maker(),
-      new TestEmptyRealisticDomCrawl.Maker(),new TestDomViaApi.Maker(),
-      new TestDom.Maker(), new TestCursorDomCrawl.Maker(),
-      new TestRealisticDomCrawl.Maker(), new TestDomBinder.Maker(),
-      new TestFlows.Maker(), new TestManualHTMLPanel.Maker(),
-      new TestWidgetBinder.Maker()};
+  final List<Maker> makers;
+  {
+    List<Maker> makeMakers = new ArrayList<Maker>();
+    makeMakers.add(new Maker("SimplePanel") {
+          public Widget make() {
+            return new SimplePanel();
+          }
+        });
+    makeMakers.add(new Maker("FlowPanel") {
+      public Widget make() {
+        return new FlowPanel();
+      }
+    });
+    makeMakers.add(new Maker("HTMLPanel") {
+          public Widget make() {
+            return new HTMLPanel("");
+          }
+        });
+    makeMakers.add(new EmptyBinder.Maker());
+    makeMakers.add(new TestEmptyDomViaApi.Maker());
+    makeMakers.add(new TestEmptyDom.Maker());
+    makeMakers.add(new TestEmptyCursorDomCrawl.Maker());
+    makeMakers.add(new TestEmptyRealisticDomCrawl.Maker()); 
+    makeMakers.add(new TestDomViaApi.Maker());
+    makeMakers.add(new TestDomInnerHtmlById.Maker());
+    if (Util.hasQSA) {
+      makeMakers.add(new TestDomInnerHtmlQuerySelectorAll.Maker());
+    }
+    makeMakers.add(new TestCursorDomCrawl.Maker()); 
+    makeMakers.add(new TestRealisticDomCrawl.Maker());
+    makeMakers.add(new TestDomBinder.Maker()); 
+    makeMakers.add(new TestFlows.Maker());
+    makeMakers.add(new TestManualHTMLPanel.Maker()); 
+    makeMakers.add(new TestWidgetBinder.Maker());
+
+    makers = Collections.unmodifiableList(makeMakers);
+  }
 
   final private FlowPanel root;
 
@@ -108,7 +127,7 @@
       }
     });
 
-    grid = new Grid(makers.length + 1, 3);
+    grid = new Grid(makers.size() + 2, 3);
     grid.setText(0, 0, "50%");
     grid.setText(0, 1, "m");
 
@@ -141,20 +160,21 @@
   }
 
   public void run() {
-    RootPanel r = RootPanel.get();
+    RootPanel root = RootPanel.get();
 
     Widget[] widgets = new Widget[getInstances()];
 
     grid.resizeColumns(grid.getColumnCount() + 1);
 
     int row = 1;
+    double allTimes = 0;
     for (Maker maker : makers) {
       log(maker.name);
       double start = Duration.currentTimeMillis();
 
       for (int i = 0; i < getInstances(); ++i) {
         widgets[i] = maker.make();
-        r.add(widgets[i]);
+        root.add(widgets[i]);
       }
 
       /*
@@ -167,14 +187,16 @@
 
       double thisTime = Duration.currentTimeMillis() - start;
       record(row, thisTime);
+      allTimes += thisTime;
 
       // Clean up to keep the dom a reasonable size.
       
       for (int i = 0; i < getInstances(); ++i) {
-        r.remove(widgets[i]);
+        root.remove(widgets[i]);
       }
       row++;
     }
+    grid.setText(row, grid.getColumnCount() - 1, Util.format(allTimes));
   }
 
   private int getInstances() {
diff --git a/reference/Microbenchmarks/war/Microbenchmarks.html b/reference/Microbenchmarks/war/Microbenchmarks.html
index 07ccef6..dddd1e2 100644
--- a/reference/Microbenchmarks/war/Microbenchmarks.html
+++ b/reference/Microbenchmarks/war/Microbenchmarks.html
@@ -1,4 +1,4 @@
-<!DOCTYPE>
+<!DOCTYPE HTML>
 
 <html>
   <head>