001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002// The Molly framework is freely distributable under the terms of an
003// MIT-style license. For details, see the molly pages web site at:
004// http://www.mollypages.org/. Use, modify, have fun !
005
006package fc.util;
007
008/**
009Allows measuring the start and stop time and (hence the elapsed time) of
010some event. ("event" meaning something of interest, for example, a method
011call). Can be started/stopped repeatedly. (cumulative time across all such
012start/stops are available via the {@link #cumulativeTime} method).
013<p>
014All times are in <i>nano-seconds</i>. 
015<p>
016Thread Safety: This class is <b>not</b> threadsafe and it's method
017do <b>not</b> acquire any locks to reduce any time skew due to
018lock acquisition. Multiple threads should use separate NanoWatch
019objects or alternatively, higher level synchronization.
020
021@author   hursh jain
022@see    Watch A lower precision (milliseconds) watch.
023*/
024public final class NanoWatch extends Watch
025{
026public NanoWatch(String name) {
027  super(name);
028  }
029
030public NanoWatch() {
031  super("DefaultNanoWatch/" + Thread.currentThread().getName());
032  }
033
034/** 
035Start measuring time. Call this method just before calling the
036method/code to be instrumented. This method does <b>not</b> reset the
037Watch, so the reset method should be called before calling this method
038<b>again</b>.
039*/
040public NanoWatch start() {
041  startTime = System.nanoTime();  
042  running = true;
043  return this;
044  }
045  
046/** Stop measuring the time */
047public void stop() {
048  stopTime = System.nanoTime();
049  cumulativeTime += (stopTime - startTime);
050  running = false;
051  }
052
053
054/** 
055Returns the time elapsed since the Watch was started. If the watch was
056started and stopped, returns the time between the start/stop interval.
057
058@throws RuntimeException  if the watch was never started before calling
059              this method.
060*/
061public long time() 
062  {
063  if (startTime == -1)
064    throw new RuntimeException("You need to start the watch at least once before calling this method");
065
066  if (running)
067    return System.nanoTime() - startTime;
068  
069  return  stopTime - startTime;
070  }
071
072/** 
073Returns the time elapsed since the Watch was started. (this method is
074an alias for {@link #time} method).
075*/
076public long getTime() 
077  {
078  return time();
079  }
080
081private static final double ms_factor = 1.0 / 1000000.00D;
082
083/** 
084Returns the elapsed time in milliseconds. Useful when nanosecond values are
085too hard to read.
086*/
087public double getTimeInMillis() 
088  {
089  long t = time();  
090  return t * ms_factor;
091  }
092
093
094/** 
095Returns the total time recorded by this Watch (across several starts/stops)
096*/
097public long cumulativeTime() 
098  {
099  if (! running) 
100    return cumulativeTime;
101  
102  return cumulativeTime + (System.nanoTime() - startTime);
103  }
104
105/** 
106Reset all values to zero. This method should be called
107before this object is used <b>again</b>.
108*/
109public void reset() 
110  {
111  startTime = stopTime =  0;
112  }
113
114/** Is the Watch currently running ? */
115public boolean isRunning() {
116  return running;
117  }
118
119/** 
120Get the start time (in nanoseconds), the start time is arbitrary (see 
121{@link System#nanoTime}).
122*/
123protected long getStart() {
124  return startTime;
125  }
126
127/** 
128Get the stop time (in nanoseconds). Useful only as a difference from
129the start time
130*/
131protected long getStop() {
132  return stopTime;
133  }
134
135public String toString() 
136  {
137  java.text.NumberFormat nf = java.text.NumberFormat.getNumberInstance();
138  nf.setGroupingUsed(true);
139  
140  String str = myname;
141
142  str += ": Cum.Time=[" + nf.format(cumulativeTime()) + " nanoseconds]";
143  
144  if (running) 
145    str += "; Elapsed=[" + nf.format(time()) + " nanoseconds]";
146    
147  return str;
148  }
149
150public static void main(String[] args)
151  {
152  fc.util.Watch t1 = new fc.util.NanoWatch("NanoWatch 1");
153  t1.start();
154  
155  new Thread(new Runnable() { 
156    public void run() {
157      try { 
158        Watch t2 = new NanoWatch();
159        t2.start(); Thread.currentThread().sleep(20); t2.stop(); 
160        System.out.println("t2.toString():" + t2);
161        } 
162      catch (Exception e) { e.printStackTrace(); }
163      } 
164    }).start();
165  
166  //following should return -1
167  System.out.println("NanoWatch 1, total time taken:" + t1.time());
168
169  System.out.println("NanoWatch 1, time=" + t1.time());
170  System.out.println("NanoWatch 1, before-being-stopped, toString():" + t1);
171  t1.stop();
172  System.out.println("NanoWatch 1, is running ? " + t1.isRunning() );
173  System.out.println("NanoWatch 1, after-being-stopped, toString():" + t1);
174  System.out.println("NanoWatch 1, elapsed time:" + t1.time());
175  System.out.println("NanoWatch 1, cumulative time taken:" + t1.cumulativeTime());
176  System.out.println("NanoWatch 1, elapsed time:" + t1.time());
177  }
178
179} //~class NanoWatch