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 This method is an alias for {@link #timeInSeconds} method.
120 */
121 public long seconds()
122 {
123 return timeInSeconds();
124 }
125
126 /**
127 This method is an alias for {@link #timeInSeconds} method.
128 */
129 public long elapsed()
130 {
131 return timeInSeconds();
132 }
133
134
135 /**
136 This method is an alias for {@link #timeInSeconds} method.
137 */
138 public long timeSeconds()
139 {
140 return timeInSeconds();
141 }
142
143
144 /**
145 This method is an alias for {@link #getTimeInMillis} method.
146 */
147 public double timeMillis()
148 {
149 return getTimeInMillis();
150 }
151
152
153 /**
154 Useful in NanoWatch and other subclasses. Not really useful here, returns
155 the same value as {@link #getTime}/{@link #time} functions instead.
156 <p>
157 This method is defined here so all watches have a common interface and
158 any instance can be bound to a variable of type <code>Watch</code>.
159 */
160 public double getTimeInMillis()
161 {
162 return getTime() * 1.0D;
163 }
164
165 /**
166 Returns the total time recorded by this Watch (across several starts/stops)
167 */
168 public long cumulativeTime()
169 {
170 if (! running)
171 return cumulativeTime;
172
173 return cumulativeTime + (System.currentTimeMillis() - startTime);
174 }
175
176 /**
177 Reset all values to zero. This method should be called before this object is
178 used <b>again</b>. Does not restart the timer, call start again when start the
179 timer.
180 */
181 public void reset()
182 {
183 startTime = stopTime = 0;
184 }
185
186
187 /**
188 Reset all values to zero and restarts the timer.
189 */
190 public void restart()
191 {
192 reset();
193 start();
194 }
195
196 /** Is the Watch currently running ? */
197 public boolean isRunning() {
198 return running;
199 }
200
201 /** Get the start time (in milliseconds since Jan 1, 1970)*/
202 protected long getStart() {
203 return startTime;
204 }
205
206 /** Get the stop time, (in milliseconds since Jan 1, 1970) */
207 protected long getStop() {
208 return stopTime;
209 }
210
211 /**
212 Describes the current state of this watch. The exact details of said
213 description are unspecified and subject to change.
214 */
215 public String toString()
216 {
217 String str = myname;
218
219 str += ": Cum.Time=[" + cumulativeTime() + " ms]" +
220 "; Start=[" + startTime + "]";
221
222 if (! running)
223 str += "; Stop=[" + stopTime + "]";
224 else
225 str += "; Elapsed=[" + time() + " ms]";
226
227 return str;
228 }
229
230 public static void main(String[] args)
231 {
232 fc.util.Watch t1 = new fc.util.Watch("Watch 1");
233 t1.start();
234
235 new Thread(new Runnable() {
236 public void run() {
237 try {
238 Watch t2 = new Watch();
239 t2.start(); Thread.currentThread().sleep(20); t2.stop();
240 System.out.println("t2.toString():" + t2);
241 }
242 catch (Exception e) { e.printStackTrace(); }
243 }
244 }).start();
245
246 //following should return -1
247 System.out.println("Watch 1, total time taken:" + t1.time());
248
249 System.out.println("Watch 1, time=" + t1.time());
250 System.out.println("Watch 1, before-being-stopped, toString():" + t1);
251 t1.stop();
252 System.out.println("Watch 1, is running ? " + t1.isRunning() );
253 System.out.println("Watch 1, after-being-stopped, toString():" + t1);
254 System.out.println("Watch 1, elapsed time:" + t1.time());
255 System.out.println("Watch 1, cumulative time taken:" + t1.cumulativeTime());
256 System.out.println("Watch 1, elapsed time:" + t1.time());
257
258 new Thread(new Runnable() {
259 public void run() {
260 try {
261 Watch t2 = new Watch();
262 t2.start();
263 Thread.currentThread().sleep(250);
264 t2.stop();
265 System.out.println("After sleeping 250ms: time in seconds: " + t2.getTimeInSeconds());
266 t2.start();
267 Thread.currentThread().sleep(500);
268 System.out.println("After sleeping 750ms: time in seconds: " + t2.getTimeInSeconds());
269 Thread.currentThread().sleep(500);
270 System.out.println("After sleeping 1250ms: time in seconds: " + t2.getTimeInSeconds());
271 Thread.currentThread().sleep(500);
272 System.out.println("After sleeping 1750ms: time in seconds: " + t2.getTimeInSeconds());
273 Thread.currentThread().sleep(1000);
274 System.out.println("After sleeping 2750ms: time in seconds: " + t2.getTimeInSeconds());
275 }
276 catch (Exception e) { e.printStackTrace(); }
277 }
278 }).start();
279 }
280
281 } //~class Watch