Development Class Java

//package com.ryanm.util;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
/**
 * A convenience class to do code profiling.
 * 
 * @author Keith Woodward
 */
public class CodeTimer {
  private static DecimalFormat fourDP = new DecimalFormat("0.####");
  private static DecimalFormat percent = new DecimalFormat("0.#%");
  /**
   * How long a call to {@link #tick(String)} takes
   */
  private static long SELF_TIME;
  private static final long NANOS_IN_A_SECOND = 1000000000;
  private static final long NANOS_IN_A_MILLISECOND = 1000000;
  static {
    recalibrate(10000);
  }
  /**
   * The name of this {@link CodeTimer}, to identify the output
   */
  public final String name;
  /**
   * Names of intervals
   */
  private String[] intervalNames = new String[5];
  /**
   * Sum of interval durations
   */
  private long[] intervalDurationSums = new long[intervalNames.length];
  /**
   * The index of the current interval
   */
  private int intervalIndex;
  /**
   * The time of the last call to {@link #tick(String)}
   */
  private long lastClickTime;
  /**
   * Count of timing periods
   */
  private int periodCount = 0;
  private boolean periodStarted = false;
  private long periodStartTime;
  /**
   * Sum of period durations
   */
  private long periodDurationSum = 0;
  /**
   * Defaults to true
   */
  public boolean enabled = true;
  private long lastPrintOutNanos = System.nanoTime();
  /**
   * The number of seconds between prints, defaults to 5
   */
  public int printFrequencySeconds = 5;
  /**
   * The level of information printed for the total time spent in a profiling
   * period
   */
  public Output period;
  /**
   * The level of information printed for time taken in intervals
   */
  public Output interval;
  /**
   * @param name
   *            A name for this {@link CodeTimer}, so as to identify the
   *            output
   * @param period
   *            output for profiling period duration. May not be null
   * @param interval
   *            output for interval durations, May not be null
   */
  public CodeTimer(String name, Output period, Output interval) {
    this.name = name;
    this.period = period;
    this.interval = interval;
  }
  /**
   * Call to start a profiling period, or to start an interval in an open
   * period
   * 
   * @param name
   *            A helpful name for this interval. Makes it easy to find what
   *            bit of code you're measuring
   */
  public void tick(String name) {
    if (enabled) {
      long clickTime = System.nanoTime();
      if (!periodStarted) {
        periodStarted = true;
        periodStartTime = clickTime;
        intervalNames[0] = name;
      } else {
        long duration = clickTime - lastClickTime;
        intervalDurationSums[intervalIndex] += duration;
        intervalIndex++;
        if (intervalIndex >= intervalNames.length) {
          intervalNames = ArrayUtil.grow(intervalNames);
          intervalDurationSums = ArrayUtil.grow(intervalDurationSums);
        }
        intervalNames[intervalIndex] = name;
      }
      lastClickTime = clickTime;
    }
  }
  /**
   * Call to end a profiling period, and print the results if
   * {@link #printFrequencySeconds} have passed since we last printed
   */
  public void lastTick() {
    lastTick(System.nanoTime() - lastPrintOutNanos > printFrequencySeconds
        * NANOS_IN_A_SECOND);
  }
  /**
   * Call to end a profiling period
   * 
   * @param print
   *            true to print results, false no to
   */
  public void lastTick(boolean print) {
    if (enabled) {
      long clickTime = System.nanoTime();
      long intervalDuration = clickTime - lastClickTime;
      intervalDurationSums[intervalIndex] += intervalDuration;
      intervalIndex = 0;
      long periodDuration = clickTime - periodStartTime;
      periodDurationSum += periodDuration;
      periodCount++;
      periodStarted = false;
      if (print) {
        System.out.println(name + " period "
            + period.format(periodDurationSum, periodCount));
        long perDur = periodDurationSum / periodCount;
        for (int i = 0; i < intervalNames.length
            && intervalNames[i] != null; i++) {
          float intDur = intervalDurationSums[i] / periodCount;
          float p = intDur / perDur;
          System.out.println("\t"
              + intervalNames[i]
              + "\t"
              + percent.format(p)
              + "\t"
              + interval.format(intervalDurationSums[i],
                  periodCount));
        }
        for (int i = 0; i < intervalDurationSums.length; i++) {
          intervalDurationSums[i] = 0;
          intervalNames[i] = null;
        }
        periodDurationSum = 0;
        periodCount = 0;
        lastPrintOutNanos = clickTime;
      }
    }
  }
  /**
   * Calibrates the timer for the machine
   * 
   * @param numTests
   *            10000 might be about right
   */
  public static void recalibrate(int numTests) {
    boolean print = false;
    CodeTimer codeTimer = new CodeTimer("calibrate", null, null);
    // warm the JIT
    for (int i = 0; i < 1024; i++) {
      codeTimer.tick("foo");
      codeTimer.lastTick(false);
    }
    // find how out long it takes to call click(), so that time can
    // be accounted for
    ArrayList selfTimeObservations = new ArrayList(numTests);
    for (int i = 0; i < numTests; i++) {
      long nanoSelfTime = -(System.nanoTime() - System.nanoTime());
      codeTimer.tick("foo");
      long t0 = System.nanoTime();
      codeTimer.tick("bar");
      long t1 = System.nanoTime();
      codeTimer.tick("baz");
      codeTimer.lastTick(false);
      long currentSelfTime = t1 - t0 - nanoSelfTime;
      if (print) {
        System.out
            .println("calibrating : currentSelfTime == "
                + currentSelfTime + ", nanoSelfTime == "
                + nanoSelfTime);
      }
      selfTimeObservations.add(new Long(currentSelfTime));
    }
    // sort the times
    Collections.sort(selfTimeObservations);
    if (print) {
      for (int i = 0; i < selfTimeObservations.size(); i++) {
        System.out
            .println("calibrating : selfTimeObservations.get(i) == "
                + selfTimeObservations.get(i));
      }
    }
    // cut out the slowest 5% which are assumed to be outliers
    for (int i = 0; i < (int) (numTests * 0.05); i++) {
      selfTimeObservations.remove(0);
    }
    // cut out the fastest 5% which are assumed to be outliers
    for (int i = 0; i < (int) (numTests * 0.05); i++) {
      selfTimeObservations.remove(selfTimeObservations.size() - 1);
    }
    if (print) {
      System.out
          .println("calibrating : Slimmed list: selfTimeObservations.size() == "
              + selfTimeObservations.size());
      for (int i = 0; i < selfTimeObservations.size(); i++) {
        System.out
            .println("calibrating : selfTimeObservations.get(i) == "
                + selfTimeObservations.get(i));
      }
    }
    // find the average
    long sumOfSelfTimes = 0;
    for (int i = 0; i < selfTimeObservations.size(); i++) {
      sumOfSelfTimes += selfTimeObservations.get(i).longValue();
    }
    SELF_TIME = sumOfSelfTimes / selfTimeObservations.size();
    if (print) {
      System.out.println("calibrating : SELF_TIME == " + SELF_TIME);
    }
  }
  /**
   * Time unit that is printed
   * 
   * @author ryanm
   */
  public enum Output {
    /**
     * Second-level granularity
     */
    Seconds {
      @Override
      public String format(long totalNanos, long count) {
        double avTotalSeconds = (double) totalNanos
            / (count * NANOS_IN_A_SECOND);
        return fourDP.format(avTotalSeconds) + "s";
      }
    },
    /**
     * Millisecond-level granularity
     */
    Millis {
      @Override
      public String format(long totalNanos, long count) {
        double avTotalMillis = (double) totalNanos
            / (count * NANOS_IN_A_MILLISECOND);
        return fourDP.format(avTotalMillis) + "ms";
      }
    },
    /**
     * Nanosecond-level granularity
     */
    Nanos {
      @Override
      public String format(long totalNanos, long count) {
        double avTotalNanos = (double) totalNanos / count;
        return fourDP.format(avTotalNanos) + "ns";
      }
    };
    /**
     * @param totalNanos
     *            The sum of some number of measurements
     * @param count
     *            The number of measurements
     * @return A string describing the average time
     */
    public abstract String format(long totalNanos, long count);
  };
}
class ArrayUtil {
  /**
   * Doubles the size of an array
   * 
   * @param in
   * @return The new array
   */
  public static String[] grow(String[] in) {
    String[] na = new String[in.length * 2];
    System.arraycopy(in, 0, na, 0, in.length);
    return na;
  }
  /**
   * Doubles the size of an array
   * 
   * @param in
   * @return The new array
   */
  public static long[] grow(long[] in) {
    long[] na = new long[in.length * 2];
    System.arraycopy(in, 0, na, 0, in.length);
    return na;
  }
  /**
   * Doubles the size of an array
   * 
   * @param in
   * @return The new array
   */
  public static int[] grow(int[] in) {
    int[] na = new int[in.length * 2];
    System.arraycopy(in, 0, na, 0, in.length);
    return na;
  }
}