001 package hirondelle.web4j.util;
002
003 /**
004 Allows timing of the execution of any block of code.
005
006 Example use case:
007 <PRE>
008 Stopwatch stopwatch = new Stopwatch();
009 stopwatch.start();
010 //..perform operations
011 stopwatch.stop();
012
013 System.out.println("The reading on the stopwatch is: " + stopwatch);
014
015 //reuse the same stopwatch again
016 //Note that there is no need to call a reset method.
017 stopwatch.start();
018 //..perform operations
019 stopwatch.stop();
020
021 //perform a numeric comparison
022 if ( stopwatch.toValue() > 5 ) {
023 System.out.println("The reading is high: " + stopwatch);
024 }
025 </PRE>
026
027 <P>The value on the stopwatch may be inspected at any time using the
028 {@link #toString} and {@link #toValue} methods.
029
030 <P><b>Example 2</b>
031 <br>To time the various steps in a long startup or initialization task, your code may take the form:
032 <PRE>
033 Stopwatch stopwatch = new Stopwatch();
034 stopwatch.start();
035 //..perform operation 1
036 log("Step 1 completed " + stopwatch + " after start.");
037
038 //perform operation 2
039 log("Step 2 completed " + stopwatch + " after start.");
040
041 //perform the last operation, operation 3
042 stopwatch.stop();
043 log("Final Step 3 completed " + stopwatch + " after start") ;
044 </PRE>
045
046 <P><i>Implementation Note:</i></br>
047 This class uses {@link System#nanoTime()}, not {@link System#currentTimeMillis()}.
048 */
049 public final class Stopwatch {
050
051 /**
052 Start the stopwatch.
053
054 <P>You cannot call this method if the stopwatch is already started.
055 */
056 public void start(){
057 if ( fIsRunning ) {
058 throw new IllegalStateException("Must stop before calling start again.");
059 }
060 //reset both start and stop
061 fStart = getCurrentTime();
062 fStop = 0;
063 fIsRunning = true;
064 }
065
066 /**
067 Stop the stopwatch.
068
069 <P>You can only call this method if the stopwatch has been started.
070 */
071 public void stop() {
072 if ( !fIsRunning ) {
073 throw new IllegalStateException("Cannot stop if not currently running.");
074 }
075 fStop = getCurrentTime();
076 fIsRunning = false;
077 }
078
079 /**
080 Return the current "reading" on the stopwatch, in milliseconds, in a format suitable for logging.
081
082 <P>Example return value : '<tt>1089 ms</tt>', which indicates just over a second.
083 */
084 public String toString() {
085 StringBuilder result = new StringBuilder();
086 result.append( toValue() );
087 result.append(" ms");
088 return result.toString();
089 }
090
091 /**
092 Return the current "reading" on the stopwatch in milliseconds, as a numeric type.
093 */
094 public long toValue() {
095 long result = fStop == 0 ? getCurrentTime() - fStart : fStop -fStart;
096 return result;
097 }
098
099 // PRIVATE //
100 private long fStart;
101 private long fStop;
102 private boolean fIsRunning;
103
104 /** Converts from nanoseconds to milliseconds. */
105 private static final int DIVISOR = 1000*1000;
106
107 private long getCurrentTime(){
108 return System.nanoTime()/DIVISOR;
109 }
110 }