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