Time execution speed

Here's an example of a utility Stopwatch class which can provide timings for any section of code.

It's important to note that System.currentTimeMillis has low resolution, on the order of 10ms for most systems. For timing the execution speed of code, it's usually best to use System.nanoTime instead. According to this excellent article by David Holmes, the typical resolution of nanoTime is on the order of microseconds.

Since variations will naturally occur between invocations, you should take the median value of a number of different measurements.

Profiling tools like Visual VM are another option as well. Profilers are often included in IDEs.

Note that precise micro-benchmarking in Java is a tricky business, mostly because of just-in-time compilation (the HotSpot compiler):

Here's an example run of the Stopwatch class appearing below:

The reading for StringBuilder is: 3.611 ms
The reading is high: 193.484 ms


import java.math.BigDecimal;

/** 
 Time the execution of any block of code.
 
 <P>This implementation times the duration using <tt>System.nanoTime</tt>.
 
 <P>On most systems <tt>System.currentTimeMillis</tt> has a time 
 resolution of about 10ms, which is quite poor for timing code, so it is
 avoided here.
*/
public final class Stopwatch {

  /**
   An example of the use of this class to
   time the execution of simple String manipulation code.
  */
  public static void main(String... arguments) {
    Stopwatch stopwatch = new Stopwatch();

    stopwatch.start();

    //do stuff
    StringBuilder messageOne = new StringBuilder();
    int numIterations = 5000;
    for(int idx=0; idx < numIterations; ++idx){
      messageOne.append("blah");
    }

    stopwatch.stop();
    //Note that there is no need to call a method to get the duration,
    //since toString is automatic here
    System.out.println("The reading for StringBuilder is: " + stopwatch);

    //reuse the same stopwatch to measure an alternative implementation
    //Note that there is no need to call a reset method.
    stopwatch.start();

    //do stuff again
    String messageTwo = null;
    for(int idx=0; idx < numIterations; ++idx){
      messageTwo = messageTwo + "blah";
    }

    stopwatch.stop();
    //perform a numeric comparsion
    if ( stopwatch.toValue() > 5 ) {
      System.out.println("The reading is high: " + stopwatch);
    }
    else {
      System.out.println("The reading is low: " + stopwatch);
    }
  }

  /**
   Start the stopwatch.
   @throws IllegalStateException if the stopwatch is already running.
  */
  public void start(){
    if (fIsRunning) {
      throw new IllegalStateException("Must stop before calling start again.");
    }
    //reset both start and stop
    fStart = System.nanoTime();
    fStop = 0;
    fIsRunning = true;
    fHasBeenUsedOnce = true;
  }

  /**
   Stop the stopwatch.
   @throws IllegalStateException if the stopwatch is not already running.
  */
  public void stop() {
    if (!fIsRunning) {
      throw new IllegalStateException("Cannot stop if not currently running.");
    }
    fStop = System.nanoTime();
    fIsRunning = false;
  }

  /**
   Express the "reading" on the stopwatch.
    
   <P>Example: <tt>123.456 ms</tt>. The resolution of timings on most systems 
   is on the order of a few microseconds, so this style of presentation is usually 
   appropriate for reflecting the real precision of most timers. 
  
   <P>Ref: https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks
     
   @throws IllegalStateException if the Stopwatch has never been used,
   or if the stopwatch is still running.
  */
  @Override public String toString() {
    validateIsReadable();
    StringBuilder result = new StringBuilder();
    BigDecimal value = new BigDecimal(toValue());//scale is zero
    //millis, with 3 decimals:
    value = value.divide(MILLION, 3, BigDecimal.ROUND_HALF_EVEN);
    result.append(value);
    result.append(" ms");
    return result.toString();
  }

  /**
   Express the "reading" on the stopwatch as a numeric type, in nanoseconds.
  
   @throws IllegalStateException if the Stopwatch has never been used,
   or if the stopwatch is still running.
  */
  public long toValue() {
    validateIsReadable();
    return  fStop - fStart;
  }
  
  // PRIVATE
  private long fStart;
  private long fStop;

  private boolean fIsRunning;
  private boolean fHasBeenUsedOnce;
  
  /** Converts from nanos to millis. */
  private static final BigDecimal MILLION = new BigDecimal("1000000");
  
  /**
   Throws IllegalStateException if the watch has never been started,
   or if the watch is still running.
  */
  private void validateIsReadable() {
    if (fIsRunning) {
      String message = "Cannot read a stopwatch which is still running.";
      throw new IllegalStateException(message);
    }
    if (!fHasBeenUsedOnce) {
      String message = "Cannot read a stopwatch which has never been started.";
      throw new IllegalStateException(message);
    }
  }
} 



See Also :
Copy an array
String concatenation does not scale
Measure application performance
Would you use this technique?
Yes   No   Undecided   
© 2014 Hirondelle Systems | Source Code | Contact | License | RSS
Individual code snippets can be used under this BSD license - Last updated on September 21, 2013.
Over 2,000,000 unique IPs last year - Built with WEB4J.
- In Memoriam : Bill Dirani -