Java tutorial
/* * Copyright (c) 1996, 1997 by Doug Bell <dbell@shvn.com>. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ import java.awt.Button; import java.awt.Checkbox; import java.awt.Event; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Label; import java.awt.List; import java.awt.TextArea; public class BenchmarkApplet extends java.applet.Applet implements BenchmarkRunner, Runnable { static final String spaces = " "; static final String newline = System.getProperty("line.separator"); private volatile boolean running; private int estimatatedSeconds; private ThreadGroup tgroup; private Thread testTask; private List testList; private TextArea out; private Label timeEstimate; private Button doit, abort, clear; private Checkbox console; private Benchmark[] tests = { new Benchmark(this), new MixedBenchmark(this), new LoopBenchmark(this), new VariableBenchmark(this), new MethodBenchmark(this), new OperatorBenchmark(this), new CastingBenchmark(this), new InstantiationBenchmark(this), new ExceptionBenchmark(this) }; public void init() { tgroup = Thread.currentThread().getThreadGroup(); Font font = new Font("Courier", Font.PLAIN, 10); FontMetrics fm = getFontMetrics(font); int lines = Math.max(10, size().height / fm.getHeight() - 4); out = new TextArea(lines, spaces.length() + Benchmark.resolutionName.length()); out.setFont(font); out.setEditable(false); add(out); boolean toobig; do { testList = new List(--lines, true); add(testList, 0); validate(); if (toobig = testList.size().height - out.size().height > 2) remove(testList); } while (toobig); for (int ii = 0; ii < tests.length; ii++) testList.addItem(tests[ii].getName()); testList.select(0); // Calibration benchmark testList.select(1); // Mixed benchmark timeEstimate = new Label(getTimeEstimate()); add(timeEstimate); add(doit = new Button("Run Benchmark")); add(abort = new Button("Stop")); add(clear = new Button("Clear")); abort.disable(); clear.disable(); add(console = new Checkbox("Console")); validate(); } public void start() { Benchmark.recalibrate(); } public synchronized void run() { try { running = true; timingTests(); } finally { running = false; doit.enable(); abort.disable(); } } public boolean action(Event evt, Object arg) { if (evt.target == doit) { if (!running) { testTask = new Thread(tgroup, this); testTask.start(); } return true; } else if (evt.target == abort) { if (running) { testTask.stop(); println("*** aborted by user ***"); } return true; } else if (evt.target == clear) { out.setText(""); clear.disable(); return true; } return false; } public boolean handleEvent(Event evt) { if (evt.target == testList) { if (evt.id == Event.LIST_SELECT || evt.id == Event.LIST_DESELECT) if (timeEstimate != null) timeEstimate.setText(getTimeEstimate()); } return super.handleEvent(evt); } private void timingTests() { int cnt, testSeconds = 0; long begin = System.currentTimeMillis(); doit.disable(); abort.enable(); Benchmark.gc(); println(newline + "Benchmark tests: [mem=" + Runtime.getRuntime().freeMemory() + "/" + Runtime.getRuntime().totalMemory() + "]"); for (cnt = 0; cnt < testList.countItems(); cnt++) if (testList.isSelected(cnt)) testSeconds += tests[cnt].getTestTime(); println("Estimated time: " + timeString(estimatatedSeconds) + " (tests " + timeString(testSeconds) + ")"); long total = 0; for (cnt = 0; cnt < testList.countItems(); cnt++) if (testList.isSelected(cnt)) total += tests[cnt].runTest(); println("*** done: " + timeString((int) (System.currentTimeMillis() + 500 - begin) / 1000) + " (tests " + timeString((int) ((total + 500) / 1000)) + ") ***"); } static String timeString(int seconds) { int sec = seconds % 60; return (seconds / 60) + ((sec < 10) ? ":0" : ":") + sec; } private String getTimeEstimate() { estimatatedSeconds = 0; for (int cnt = 0; cnt < testList.countItems(); cnt++) if (testList.isSelected(cnt)) estimatatedSeconds += tests[cnt].getRunningTime(); return "Estimated running time: " + timeString(estimatatedSeconds); } public void report(String msg, long nanos) { if (msg != null) { String time = Long.toString(nanos); int index = msg.length() + time.length(); String space = (index >= spaces.length()) ? " " : spaces.substring(index); println(msg + space + time + Benchmark.resolutionName); } } public synchronized void println(String s) { if (console.getState()) System.out.println(s); out.appendText(s + newline); clear.enable(); Thread.yield(); // give interface a chance to process events } } // class BenchmarkApplet // EOF /* * Copyright (c) 1996, 1997 by Doug Bell <dbell@shvn.com>. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ class DerivedObject { } class DerivedObject2 extends DerivedObject { } class DerivedObject3 extends DerivedObject2 { } class DerivedObject4 extends DerivedObject3 { } class DerivedObject5 extends DerivedObject4 { } interface Inter1 { } interface Inter2 extends Inter1 { } interface Inter3 extends Inter2 { } interface Inter4 extends Inter3 { } interface Inter5 extends Inter4 { } interface Inter6 extends Inter5 { } /* * This is the base benchmark class. To create a new benchmark, extend this class and * implement getTestTime(), getRunningTime() and runTest() in the extended class. */ class Benchmark implements Runnable { private static boolean calibrated; private static long gcMemTarget; private static String[] resNames = { " ms", " s", " ns", " ps" }; private static long[] resValues = { 1000L, 1000000L, 1000000000L, 1000000000000L }; protected static int resIndex = 2; // ns = nanosecond protected static String resolutionName = resNames[resIndex]; protected static long resolution = resValues[resIndex]; protected static long timerLoopNanos; protected static int[] useint = new int[3]; // used to prevent dead variable elimination private BenchmarkRunner runner; private Thread timer; private long sampleMillis = 1000L; // 1 second for each test private int sampleCount = 3; private int timerIterations; private boolean timerPaused; private long timerStart, reportMillis; private int[] iterations = new int[sampleCount]; private long[] milliseconds = new long[sampleCount]; protected long timerMillis, totalMillis; protected volatile boolean go; public static void gc() { System.runFinalization(); System.gc(); if (Runtime.getRuntime().freeMemory() < gcMemTarget) { try { int[] mem = new int[(int) gcMemTarget / 4]; mem = null; } catch (OutOfMemoryError e) { gcMemTarget -= 10000; recalibrate(); } System.gc(); } try { Thread.sleep(100); } catch (InterruptedException e) { } } public static void recalibrate() { calibrated = false; } public static void calibrate() { calibrated = false; new Benchmark().runTest(); if (timerLoopNanos < 98) { if (resIndex < resValues.length - 1) { resIndex++; resolutionName = resNames[resIndex]; resolution = resValues[resIndex]; calibrate(); } } else if (timerLoopNanos > 102000) { if (resIndex > 0) { resIndex--; resolutionName = resNames[resIndex]; resolution = resValues[resIndex]; calibrate(); } } if (!calibrated) { gcMemTarget = 0; gc(); long sysmem = Math.min(1000000, Runtime.getRuntime().totalMemory() - 10000); gcMemTarget = Math.min(1000000, Runtime.getRuntime().freeMemory() - 5000); if (true || gcMemTarget < 200000 && sysmem > gcMemTarget) { boolean ok; gcMemTarget = sysmem; do { ok = true; try { int[] mem = new int[(int) gcMemTarget / 4]; mem = null; } catch (OutOfMemoryError e) { gcMemTarget -= 10000; ok = false; } } while (!ok); } gcMemTarget = Math.min(sysmem, gcMemTarget); calibrated = true; } } static long getNanos(long[] millis, int[] iterations, long overheadNanos) { long nanos = resolution * 100; for (int ii = Math.min(millis.length, iterations.length); --ii >= 0;) { if (iterations[ii] > 0) nanos = Math.min(nanos, (((resolution / 1000) * millis[ii]) / iterations[ii]) - overheadNanos); iterations[ii] = 0; millis[ii] = 0; } return nanos; } Benchmark() { this(null); } Benchmark(BenchmarkRunner runner) { this.runner = runner; } /** Returns the name of the test. * Default implementation uses the unqualified class name, stripping 'Benchmark' * from the name if it exists. */ public String getName() { String name = getClass().getName(); int index = name.lastIndexOf('.'); name = name.substring(index < 0 ? 0 : index); if (name.equals("Benchmark")) name = "Calibrate"; else if (name.endsWith("Benchmark")) name = name.substring(0, name.length() - "Benchmark".length()); return name; } /** Returns approximate running time of justs the timing tests, in seconds. * Subclass should override this method. */ public int getTestTime() { return (int) (getSampleCount() * getSampleMillis()) / 1000; } /** Returns approximate total running time of the benchmark, in seconds. * Subclass should override this method. */ public int getRunningTime() { return getTestTime(); } /** Set the number of samples to measure for a test. */ final void setSampleCount(int samples) { if (samples != sampleCount && samples > 0) { sampleCount = samples; iterations = new int[samples]; milliseconds = new long[samples]; } } /** Get the number of samples to measure for a test. */ final int getSampleCount() { return sampleCount; } /** Set the number of milliseconds to run the timer. */ final void setSampleMillis(long millis) { if (millis > 0) sampleMillis = millis; } /** Get the number of milliseconds to run the timer. */ final long getSampleMillis () { return sampleMillis; } /** Should be called at the beginning of runTest(). */ protected void startTest () { println(""); println("