/* * Copyright 2008 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.emultest.benchmarks.java.lang; import com.google.gwt.benchmarks.client.Benchmark; import com.google.gwt.benchmarks.client.IntRange; import com.google.gwt.benchmarks.client.Operator; import com.google.gwt.benchmarks.client.RangeField; import com.google.gwt.core.client.JavaScriptObject; /** * A {@link Benchmark} for {@link StringBuilder StringBuilders}. This includes * a benchmark from Ray Cromwell that builds display commands in one of two * ways. One version uses a StringBuilder, and the other uses raw pushes with * JavaScript. Note that there is no actual DisplayList interface, because * otherwise the benchmark might have some dynamic dispatch involved. By default * this benchmarks only the standard <code>StringBuilder</code> and * <code>StringBuffer</code>. To run the full suite, comment in the alternate * version of {@link #appendKindsRange}. */ public class StringBufferBenchmark extends Benchmark { /** * The type of StringBuilder to use for a test. */ protected enum SBType { JS("raw JavaScrpt"), STRBLD("StringBuilder"), STRBUF("StringBuffer"); public String description; private SBType(String description) { this.description = description; } } /** * A DisplayList represented using a native JavaScript array, and updated via * the JavaScript push() method. */ @SuppressWarnings("unused") private static class JSArrayDisplayList { private JavaScriptObject jso = JavaScriptObject.createArray(); public void begin() { jso = JavaScriptObject.createArray(); } public native void cmd(String cmd) /*-{ this.@com.google.gwt.emultest.benchmarks.java.lang.StringBufferBenchmark$JSArrayDisplayList::jso.push(cmd, 0); }-*/; public native void cmd(String cmd, int a) /*-{ this.@com.google.gwt.emultest.benchmarks.java.lang.StringBufferBenchmark$JSArrayDisplayList::jso.push(cmd, 1, a); }-*/; public native void cmd(String cmd, int a, int b) /*-{ this.@com.google.gwt.emultest.benchmarks.java.lang.StringBufferBenchmark$JSArrayDisplayList::jso.push(cmd, 2, a, b); }-*/; public native void cmd(String cmd, int a, int b, int c) /*-{ this.@com.google.gwt.emultest.benchmarks.java.lang.StringBufferBenchmark$JSArrayDisplayList::jso.push(cmd, 3, a, b, c); }-*/; public native String end() /*-{ return this.@com.google.gwt.emultest.benchmarks.java.lang.StringBufferBenchmark$JSArrayDisplayList::jso.join(''); }-*/; public void fill() { cmd("F"); } public void lineTo(int x, int y) { cmd("L", 0, 0); } public void moveTo(int x, int y) { cmd("M", 0, 0); } public void rotate(int angle) { cmd("R", angle); } public void stroke() { cmd("S"); } public void translate(int x, int y) { cmd("T", x, y); } } /** * A DisplayList represented as a {@link StringBuffer} of commands and * arguments. To contrast, see {@link JSArrayDisplayList}. */ @SuppressWarnings("unused") private static class StringBufferDisplayList { private StringBuffer strbld = new StringBuffer(); public void begin() { strbld = new StringBuffer(); } public void cmd(String cmd) { strbld.append(cmd); strbld.append(0); } public void cmd(String cmd, int a) { strbld.append(cmd); strbld.append(1); strbld.append(a); } public void cmd(String cmd, int a, int b) { strbld.append(cmd); strbld.append(2); strbld.append(a); strbld.append(b); } public void cmd(String cmd, int a, int b, int c) { strbld.append(cmd); strbld.append(3); strbld.append(a); strbld.append(b); strbld.append(c); } public String end() { return strbld.toString(); } public void fill() { cmd("F"); } public void lineTo(int x, int y) { cmd("L", 0, 0); } public void moveTo(int x, int y) { cmd("M", 0, 0); } public void rotate(int angle) { cmd("R", angle); } public void stroke() { cmd("S"); } public void translate(int x, int y) { cmd("T", x, y); } } /** * A DisplayList represented as a {@link StringBuilder} of commands and * arguments. To contrast, see {@link JSArrayDisplayList}. */ @SuppressWarnings("unused") private static class StringBuilderDisplayList { private StringBuilder strbld = new StringBuilder(); public void begin() { strbld = new StringBuilder(); } public void cmd(String cmd) { strbld.append(cmd); strbld.append(0); } public void cmd(String cmd, int a) { strbld.append(cmd); strbld.append(1); strbld.append(a); } public void cmd(String cmd, int a, int b) { strbld.append(cmd); strbld.append(2); strbld.append(a); strbld.append(b); } public void cmd(String cmd, int a, int b, int c) { strbld.append(cmd); strbld.append(3); strbld.append(a); strbld.append(b); strbld.append(c); } public String end() { return strbld.toString(); } public void fill() { cmd("F"); } public void lineTo(int x, int y) { cmd("L", 0, 0); } public void moveTo(int x, int y) { cmd("M", 0, 0); } public void rotate(int angle) { cmd("R", angle); } public void stroke() { cmd("S"); } public void translate(int x, int y) { cmd("T", x, y); } } private static final String P_CLOSE = "</p>"; private static final String P_OPEN = "<p>"; public final SBType[] appendKindsRange = new SBType[] { SBType.STRBUF, SBType.STRBLD}; public final IntRange appendTimesRange = new IntRange(32, 4096, Operator.MULTIPLY, 2); public final SBType[] displayListKindsRange = new SBType[] { SBType.STRBUF, SBType.STRBLD, SBType.JS}; public final IntRange displayListTimesRange = new IntRange(32, 4096, Operator.MULTIPLY, 2); private volatile String abcde = "abcde"; @Override public String getModuleName() { return "com.google.gwt.emultest.EmulSuiteBenchmarks"; } /** * Needed for JUnit. */ public void testAppend() { } public void testAppend(@RangeField("appendTimesRange") Integer times, @RangeField("appendKindsRange") SBType sbtype) { int outerTimes = 1; switch (sbtype) { case STRBLD: for (int i = 0; i < outerTimes; i++) { appendWithStringBuilder(times); } break; case STRBUF: for (int i = 0; i < outerTimes; i++) { appendWithStringBuffer(times); } break; } } /** * Needed for JUnit. */ public void testDisplayList() { } /** * Test creating a display list command sequence. */ public void testDisplayList(@RangeField("displayListTimesRange") Integer times, @RangeField("displayListKindsRange") SBType sbtype) { switch (sbtype) { case JS: drawWithJSArrayDisplayList(times); break; case STRBUF: drawWithStringBufferDisplayList(times); break; case STRBLD: drawWithStringBuilderDisplayList(times); break; } } private void appendWithStringBuffer(int times) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < times; i++) { sb.append(P_OPEN); sb.append(abcde); sb.append(P_CLOSE); } pretendToUse(sb.toString().length()); } private void appendWithStringBuilder(int times) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < times; i++) { sb.append(P_OPEN); sb.append(abcde); sb.append(P_CLOSE); } pretendToUse(sb.toString().length()); } /** * Test drawing commands using JSArrayDisplayList. */ private void drawWithJSArrayDisplayList(int times) { JSArrayDisplayList dl = new JSArrayDisplayList(); dl.begin(); for (int i = 0; i < times; i++) { // draw a box dl.translate(50, 50); dl.rotate(45); dl.moveTo(0, 0); dl.lineTo(100, 0); dl.lineTo(100, 100); dl.lineTo(0, 100); dl.lineTo(0, 0); dl.stroke(); dl.fill(); } pretendToUse(dl.end().length()); } /** * Test drawing commands using {@link StringBufferDisplayList}. */ private void drawWithStringBufferDisplayList(int times) { final StringBufferDisplayList dl = new StringBufferDisplayList(); dl.begin(); for (int i = 0; i < times; i++) { // draw a box dl.translate(50, 50); dl.rotate(45); dl.moveTo(0, 0); dl.lineTo(100, 0); dl.lineTo(100, 100); dl.lineTo(0, 100); dl.lineTo(0, 0); dl.stroke(); dl.fill(); } pretendToUse(dl.end().length()); } /** * Test drawing commands using {@link StringBufferDisplayList}. */ private void drawWithStringBuilderDisplayList(int times) { final StringBuilderDisplayList dl = new StringBuilderDisplayList(); dl.begin(); for (int i = 0; i < times; i++) { // draw a box dl.translate(50, 50); dl.rotate(45); dl.moveTo(0, 0); dl.lineTo(100, 0); dl.lineTo(100, 100); dl.lineTo(0, 100); dl.lineTo(0, 0); dl.stroke(); dl.fill(); } pretendToUse(dl.end().length()); } /** * Make a value appear to be live, so that dead code elimination will not * strip it out. */ private native void pretendToUse(int x) /*-{ $wnd.completelyUselessField = x }-*/; }