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>milliseconds</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 Watch
019 objects or alternatively, higher level synchronization.
020 <p>
021 Note: This class <i>used</i> to be called "Timer" but changed to Watch to
022 avoid an annoying name conflict with <code>java.util.Timer</code>
023
024 @author hursh jain
025 @version 1.0, 10/19/2001
026 @see NanoWatch A higher nano-second precision watch.
027 */
028 public class Watch
029 {
030 String myname;
031 volatile boolean running = false;
032 long startTime = -1;
033 long stopTime;
034 long cumulativeTime;
035
036 public Watch(String name) {
037 this.myname = name;
038 }
039
040 public Watch() {
041 this("DefaultWatch/" + Thread.currentThread().getName());
042 }
043
044 /**
045 Start measuring time. Call this method just before calling the
046 method/code to be instrumented. This method does <b>not</b> reset the
047 Watch, so the reset method should be called before calling this method
048 <b>again</b>. Returns <tt>this</tt> so we can say:
049 <blockquote>
050 <tt>Watch w = new Watch().start()</tt>
051 </blockquote>
052 */
053 public Watch start() {
054 startTime = System.currentTimeMillis();
055 running = true;
056 return this;
057 }
058
059 /** Stop measuring the time */
060 public void stop() {
061 stopTime = System.currentTimeMillis();
062 cumulativeTime += (stopTime - startTime);
063 running = false;
064 }
065
066 /**
067 Returns the time elapsed since the Watch was started. If the watch was
068 started and stopped, returns the time (in milliseconds) between the
069 start/stop interval.
070
071 @throws RuntimeException if the watch was never started before calling
072 this method.
073 */
074 public long time()
075 {
076 if (startTime == -1)
077 throw new RuntimeException("You need to start the watch at least once before calling this method");
078
079 if (running)
080 return System.currentTimeMillis() - startTime;
081
082 return stopTime - startTime;
083 }
084
085 /**
086 This method is an alias for {@link #time} method.
087 */
088 public long getTime()
089 {
090 return time();
091 }
092
093 /**
094 Useful for showing the elapsed time in seconds. Intervals between,
095 (<code>0 - 499</code> milliseconds are rounded down and
096 <code>500 - 999</code> milliseconds are rounded up).
097 */
098 public long timeInSeconds()
099 {
100 final long time = getTime();
101
102 if (time < 500) return 0;
103 if (time <= 1000) return 1;
104
105 long quotient = time / 1000;
106 long remainder = time % 1000;
107 return quotient + ((remainder < 500) ? 0 : 1);
108 }
109
110 /**
111 This method is an alias for {@link #timeInSeconds} method.
112 */
113 public long getTimeInSeconds()
114 {
115 return timeInSeconds();
116 }
117
118 /**
119 Useful in NanoWatch and other subclasses. Not really useful here, returns
120 the same value as {@link #getTime}/{@link #time} functions instead.
121 <p>
122 This method is defined here so all watches have a common interface and
123 any instance can be bound to a variable of type <code>Watch</code>.
124 */
125 public double getTimeInMillis()
126 {
127 return getTime() * 1.0D;
128 }
129
130 /**
131 Returns the total time recorded by this Watch (across several starts/stops)
132 */
133 public long cumulativeTime()
134 {
135 if (! running)
136 return cumulativeTime;
137
138 return cumulativeTime + (System.currentTimeMillis() - startTime);
139 }
140
141 /**
142 Reset all values to zero. This method should be called
143 before this object is used <b>again</b>.
144 */
145 public void reset()
146 {
147 startTime = stopTime = 0;
148 }
149
150 /** Is the Watch currently running ? */
151 public boolean isRunning() {
152 return running;
153 }
154
155 /** Get the start time (in milliseconds since Jan 1, 1970)*/
156 protected long getStart() {
157 return startTime;
158 }
159
160 /** Get the stop time, (in milliseconds since Jan 1, 1970) */
161 protected long getStop() {
162 return stopTime;
163 }
164
165 /**
166 Describes the current state of this watch. The exact details of said
167 description are unspecified and subject to change.
168 */
169 public String toString()
170 {
171 String str = myname;
172
173 str += ": Cum.Time=[" + cumulativeTime() + " ms]" +
174 "; Start=[" + startTime + "]";
175
176 if (! running)
177 str += "; Stop=[" + stopTime + "]";
178 else
179 str += "; Elapsed=[" + time() + " ms]";
180
181 return str;
182 }
183
184 public static void main(String[] args)
185 {
186 fc.util.Watch t1 = new fc.util.Watch("Watch 1");
187 t1.start();
188
189 new Thread(new Runnable() {
190 public void run() {
191 try {
192 Watch t2 = new Watch();
193 t2.start(); Thread.currentThread().sleep(20); t2.stop();
194 System.out.println("t2.toString():" + t2);
195 }
196 catch (Exception e) { e.printStackTrace(); }
197 }
198 }).start();
199
200 //following should return -1
201 System.out.println("Watch 1, total time taken:" + t1.time());
202
203 System.out.println("Watch 1, time=" + t1.time());
204 System.out.println("Watch 1, before-being-stopped, toString():" + t1);
205 t1.stop();
206 System.out.println("Watch 1, is running ? " + t1.isRunning() );
207 System.out.println("Watch 1, after-being-stopped, toString():" + t1);
208 System.out.println("Watch 1, elapsed time:" + t1.time());
209 System.out.println("Watch 1, cumulative time taken:" + t1.cumulativeTime());
210 System.out.println("Watch 1, elapsed time:" + t1.time());
211
212 new Thread(new Runnable() {
213 public void run() {
214 try {
215 Watch t2 = new Watch();
216 t2.start();
217 Thread.currentThread().sleep(250);
218 t2.stop();
219 System.out.println("After sleeping 250ms: time in seconds: " + t2.getTimeInSeconds());
220 t2.start();
221 Thread.currentThread().sleep(500);
222 System.out.println("After sleeping 750ms: time in seconds: " + t2.getTimeInSeconds());
223 Thread.currentThread().sleep(500);
224 System.out.println("After sleeping 1250ms: time in seconds: " + t2.getTimeInSeconds());
225 Thread.currentThread().sleep(500);
226 System.out.println("After sleeping 1750ms: time in seconds: " + t2.getTimeInSeconds());
227 Thread.currentThread().sleep(1000);
228 System.out.println("After sleeping 2750ms: time in seconds: " + t2.getTimeInSeconds());
229 }
230 catch (Exception e) { e.printStackTrace(); }
231 }
232 }).start();
233 }
234
235 } //~class Watch