Mega Code Archive

 
Categories / Java / Development Class
 

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("