How to do Benchmark
/*
* 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("
Related examples in the same category