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    
006    package fc.util;
007    
008    /**
009    Allows measuring the start and stop time and (hence the elapsed time) of
010    some event. ("event" meaning something of interest, for example, a method
011    call). Can be started/stopped repeatedly. (cumulative time across all such
012    start/stops are available via the {@link #cumulativeTime} method).
013    <p>
014    All times are in <i>nano-seconds</i>. 
015    <p>
016    Thread Safety: This class is <b>not</b> threadsafe and it's method
017    do <b>not</b> acquire any locks to reduce any time skew due to
018    lock acquisition. Multiple threads should use separate NanoWatch
019    objects or alternatively, higher level synchronization.
020    
021    @author   hursh jain
022    @see    Watch A lower precision (milliseconds) watch.
023    */
024    public class NanoWatch extends Watch
025    {
026    public NanoWatch(String name) {
027      super(name);
028      }
029    
030    public NanoWatch() {
031      super("DefaultNanoWatch/" + Thread.currentThread().getName());
032      }
033    
034    /** 
035    Start measuring time. Call this method just before calling the
036    method/code to be instrumented. This method does <b>not</b> reset the
037    Watch, so the reset method should be called before calling this method
038    <b>again</b>.
039    */
040    public NanoWatch start() {
041      startTime = System.nanoTime();  
042      running = true;
043      return this;
044      }
045      
046    /** Stop measuring the time */
047    public void stop() {
048      stopTime = System.nanoTime();
049      cumulativeTime += (stopTime - startTime);
050      running = false;
051      }
052    
053    
054    /** 
055    Returns the time elapsed since the Watch was started. If the watch was
056    started 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    */
061    public 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    /** 
073    Returns the time elapsed since the Watch was started. (this method is
074    an alias for {@link #time} method).
075    */
076    public long getTime() 
077      {
078      return time();
079      }
080    
081    private static final double ms_factor = 1.0 / 1000000.00D;
082    
083    /** 
084    Returns the elapsed time in milliseconds. Useful when nanosecond values are
085    too hard to read.
086    */
087    public double getTimeInMillis() 
088      {
089      long t = time();  
090      return t * ms_factor;
091      }
092    
093    
094    /** 
095    Returns the total time recorded by this Watch (across several starts/stops)
096    */
097    public long cumulativeTime() 
098      {
099      if (! running) 
100        return cumulativeTime;
101      
102      return cumulativeTime + (System.nanoTime() - startTime);
103      }
104    
105    /** 
106    Reset all values to zero. This method should be called
107    before this object is used <b>again</b>.
108    */
109    public void reset() 
110      {
111      startTime = stopTime =  0;
112      }
113    
114    /** Is the Watch currently running ? */
115    public boolean isRunning() {
116      return running;
117      }
118    
119    /** 
120    Get the start time (in nanoseconds), the start time is arbitrary (see 
121    {@link System#nanoTime}).
122    */
123    protected long getStart() {
124      return startTime;
125      }
126    
127    /** 
128    Get the stop time (in nanoseconds). Useful only as a difference from
129    the start time
130    */
131    protected long getStop() {
132      return stopTime;
133      }
134    
135    public 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    
150    public 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