BenchmarkApplet.java Source code

Java tutorial

Introduction

Here is the source code for BenchmarkApplet.java

Source

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