A convenience class to do code profiling. : StopWatch « Development Class « Java






A convenience class to do code profiling.

        
//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 <code>true</code>
   */
  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
   *            <code>true</code> to print results, <code>false</code> 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<Long> selfTimeObservations = new ArrayList<Long>(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;
  }
}

   
    
    
    
    
    
    
    
  








Related examples in the same category

1.StopWatch provides a convenient API for timings.
2.Simulates a stop watch with a lap counter.
3.Provides the programatic analog of a physical stop watch
4.Basic Timer
5.Provides various features related to the current date and timeProvides various features related to the current date and time
6.Simple stop watch
7.Some simple stop watch.
8.Stop Watch with PrintWriter
9.Stop Watch from JGraphT
10.Stop watch with nano second
11.StopWatch reports elapsed time between start and stop
12.Stopwatch is a debugging tool for manually profiling code execution
13.Your own timer
14.A class for timing things.