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>milliseconds</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 Watch 019objects or alternatively, higher level synchronization. 020<p> 021Note: This class <i>used</i> to be called "Timer" but changed to Watch to 022avoid 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*/ 028public class Watch 029{ 030 String myname; 031volatile boolean running = false; 032 long startTime = -1; 033 long stopTime; 034 long cumulativeTime; 035 036public Watch(String name) { 037 this.myname = name; 038 } 039 040public Watch() { 041 this("DefaultWatch/" + Thread.currentThread().getName()); 042 } 043 044/** 045Start measuring time. Call this method just before calling the 046method/code to be instrumented. This method does <b>not</b> reset the 047Watch, 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*/ 053public Watch start() { 054 startTime = System.currentTimeMillis(); 055 running = true; 056 return this; 057 } 058 059/** Stop measuring the time */ 060public void stop() { 061 stopTime = System.currentTimeMillis(); 062 cumulativeTime += (stopTime - startTime); 063 running = false; 064 } 065 066/** 067Returns the time elapsed since the Watch was started. If the watch was 068started and stopped, returns the time (in milliseconds) between the 069start/stop interval. 070 071@throws RuntimeException if the watch was never started before calling 072 this method. 073*/ 074public 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/** 086This method is an alias for {@link #time} method. 087*/ 088public long getTime() 089 { 090 return time(); 091 } 092 093/** 094Useful 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*/ 098public 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/** 111This method is an alias for {@link #timeInSeconds} method. 112*/ 113public long getTimeInSeconds() 114 { 115 return timeInSeconds(); 116 } 117 118/** 119This method is an alias for {@link #timeInSeconds} method. 120*/ 121public long seconds() 122 { 123 return timeInSeconds(); 124 } 125 126/** 127This method is an alias for {@link #timeInSeconds} method. 128*/ 129public long elapsed() 130 { 131 return timeInSeconds(); 132 } 133 134 135/** 136This method is an alias for {@link #timeInSeconds} method. 137*/ 138public long timeSeconds() 139 { 140 return timeInSeconds(); 141 } 142 143 144/** 145This method is an alias for {@link #getTimeInMillis} method. 146*/ 147public double timeMillis() 148 { 149 return getTimeInMillis(); 150 } 151 152 153/** 154Useful in NanoWatch and other subclasses. Not really useful here, returns 155the same value as {@link #getTime}/{@link #time} functions instead. 156<p> 157This method is defined here so all watches have a common interface and 158any instance can be bound to a variable of type <code>Watch</code>. 159*/ 160public double getTimeInMillis() 161 { 162 return getTime() * 1.0D; 163 } 164 165/** 166Returns the total time recorded by this Watch (across several starts/stops) 167*/ 168public long cumulativeTime() 169 { 170 if (! running) 171 return cumulativeTime; 172 173 return cumulativeTime + (System.currentTimeMillis() - startTime); 174 } 175 176/** 177Reset all values to zero. This method should be called before this object is 178used <b>again</b>. Does not restart the timer, call start again when start the 179timer. 180*/ 181public void reset() 182 { 183 startTime = stopTime = 0; 184 } 185 186 187/** 188Reset all values to zero and restarts the timer. 189*/ 190public void restart() 191 { 192 reset(); 193 start(); 194 } 195 196/** Is the Watch currently running ? */ 197public boolean isRunning() { 198 return running; 199 } 200 201/** Get the start time (in milliseconds since Jan 1, 1970)*/ 202protected long getStart() { 203 return startTime; 204 } 205 206/** Get the stop time, (in milliseconds since Jan 1, 1970) */ 207protected long getStop() { 208 return stopTime; 209 } 210 211/** 212Describes the current state of this watch. The exact details of said 213description are unspecified and subject to change. 214*/ 215public 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 230public 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