package vroom.common.utilities; /** * The class <code>Stopwatch</code> provides a stopwatch with nanosecond * accuracy, pause and resume functionalities, and various methods to convert a * time to a string. * <p> * Creation date: Oct 11, 2011 - 5:21:44 PM * * @author Andres L. Medaglia, <a href="http://uniandes.edu.co">Universidad de * Los Andes</a>, Victor Pillac, <a * href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a * href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 5.0 */ public class Stopwatch implements ICloneable<Stopwatch> { /** The number of milliseconds in a day. */ public final static int MS_IN_DAY = 86400000; /** The number of nanoseconds in a day. */ public final static long NS_IN_DAY = 86400000000000l; /** The number of milliseconds in an hour. */ public final static int MS_IN_HOUR = 3600000; /** The number of nanoseconds in an hour. */ public final static long NS_IN_HOUR = 3600000000000l; /** The number of milliseconds in a minute. */ public final static int MS_IN_MIN = 60000; /** The number of nanoseconds in a minute. */ public final static long NS_IN_MIN = 60000000000l; /** The number of nanoseconds in a millisecond (10e6). */ public final static long NS_IN_MS = 1000000l; /** The number of nanoseconds in a millisecond (10e6). */ public final static double NS_IN_MS_D = 1000000d; /** The number of nanoseconds in a second (10e9). */ public final static long NS_IN_S = 1000000000l; /** The number of nanoseconds in a second (10e9). */ public final static double NS_IN_S_D = 1000000000d; /** Time when the stopwatch starts. */ private long mStartTime; /** Time when the stopwatch has been paused. */ private long mPauseTime; /** Time when the stopwatch has been stops. */ private long mEndTime; /** A timout for this stopwatch. */ private long mTimeout; /** * Set the timeout for this instance. * * @param timeout * the new timout * @see #isTimedout() */ public void setTimout(long timeout) { mTimeout = timeout; } /** * Get the timeout value for this instance. * * @return the number of ms after which the {@link #hasTimedOut()} method * will return <code>true</code> */ public long getTimeout() { return mTimeout; } /** * Timeout of this stopwatch. * <p/> * Compare the current running time to the timeout value * * @return <code>true</code> if the stopwatch has timed out * @see #setTimout(long) */ public boolean hasTimedOut() { if (mStartTime < 0) { return false; // throw new // IllegalStateException("The stopwatch has not been started"); } return readTimeMS() > mTimeout; } /** An accumulated time used when pausing/resuming (in nanoseconds). */ private long mAccumulated; /** * Constructor. * * @since JDK1.3.1 */ public Stopwatch() { mStartTime = -1; mEndTime = -1; mPauseTime = -1; mTimeout = Long.MAX_VALUE; } /** * Creates a new <code>stopwatch</code> with the given timeout value. * * @param timeout * the timeout for this stopwatch (in ms) * @see Stopwatch#hasTimedOut() */ public Stopwatch(long timeout) { this(); setTimout(timeout); } /** * Started state. * * @return {@code true} if the stopwatch is started, {@code false} otherwise */ public boolean isStarted() { return mStartTime >= 0; } /** * Stopped state. * * @return {@code true} if the stopwatch is stopped, {@code false} otherwise */ public boolean isStopped() { return mEndTime >= 0; } /** * Resume a paused stopwatch. */ public void resume() { if (mStartTime < 0) throw new IllegalStateException("Stopwatch is not started"); else if (mPauseTime < 0) throw new IllegalStateException("Stopwatch is not paused"); else if (mEndTime > 0) throw new IllegalStateException("Stopwatch is stopped"); else { mStartTime = System.nanoTime(); mEndTime = -1; mPauseTime = -1; } } /** * Starts the stopwatch. */ public void start() { if (mEndTime > 0) throw new IllegalStateException( "Stopwatch is stopped - restart first"); if (mStartTime > 0) if (mPauseTime > 0) throw new IllegalStateException( "Stopwatch is already started and paused, use resume instead"); else throw new IllegalStateException("Stopwatch is already started"); if (mPauseTime >= 0) { mAccumulated += mPauseTime - mStartTime; } mStartTime = System.nanoTime(); mEndTime = -1; mPauseTime = -1; } /** * Restart this stopwatch, erasing possible accumulated time. */ public void restart() { reset(); start(); } /** * Stops the stopwatch. * <p> * This method prevents further calls to {@link #pause()}, {@link #resume()} * , and {@link #start()} until {@link #reset()} is called * </p> * <p> * If the stopwatch was paused the final time is the time at which the * stopwatch was paused * </p> */ public void stop() { if (mEndTime > 0) throw new IllegalStateException("Stopwatch is already stopped"); else if (mStartTime < 0) throw new IllegalStateException("Stopwatch is not started"); if (mPauseTime > 0) { // Virtually resume and stop the time at the last pause time mEndTime = mPauseTime; mStartTime = mPauseTime; mPauseTime = -1; } else { mEndTime = System.nanoTime(); } } /** * Pause the stopwatch, that can latter be resumed with a call to * {@link #resume()}. */ public void pause() { if (mEndTime > 0) throw new IllegalStateException("Stopwatch is stopped"); else if (mStartTime < 0) throw new IllegalStateException("Stopwatch is not started"); else if (mPauseTime > 0) throw new IllegalStateException("Stopwatch is already paused"); mPauseTime = System.nanoTime(); mAccumulated += mPauseTime - mStartTime; } /** * Sets the accumulated time on this timer. * * @param time * the accumulated time to be set (in ns) */ public void setAccumulatedTime(long time) { if (mPauseTime < 0) throw new IllegalStateException("Stopwatch must be paused first"); mAccumulated = time; } /** * Reset this stopwatch. */ public void reset() { mStartTime = -1; mEndTime = -1; mPauseTime = -1; mAccumulated = 0; } /** * Read the elapsed time on this stopwatch (in nanoseconds): * <ul> * <li>If the stopwatch is not started: returns {@code 0}</li> * <li>If the stopwatch is stopped: returns the total final elapsed time</li> * <li>If the stopwatch is paused: returns the total elapsed time at the * time it was paused</li> * <li>If the stopwatch is running: returns the current elapsed time</li>. * * @return the elapsed time on this stopwatch (in nanoseconds) */ public long readTime() { if (mStartTime < 0) return 0; else if (mEndTime > 0) return mEndTime - mStartTime + mAccumulated; else if (mPauseTime > 0) return mAccumulated; else return System.nanoTime() - mStartTime + mAccumulated; } /** * Read the elapsed time on this stopwatch (in milliseconds). * * @return the elapsed time on this stopwatch (in milliseconds) * @see #readTime() */ public double readTimeMS() { return readTime() / NS_IN_MS_D; } /** * Read the elapsed time on this stopwatch (in seconds). * * @return the elapsed time on this stopwatch (in seconds) * @see #readTime() */ public double readTimeS() { return readTime() / NS_IN_S_D; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { if (!isStarted()) { if (mTimeout != Long.MAX_VALUE && mTimeout != Integer.MAX_VALUE) { return String.format("not started, timeout:%sms", getTimeout()); } else { return "not started"; } } else { if (mTimeout != Long.MAX_VALUE && mTimeout != Integer.MAX_VALUE) { return String.format("%.0f/%sms", readTimeMS(), getTimeout()); } else { return String.format("%.0fms", readTimeMS()); } } } /** * Remaining time before the timeout. * * @return the time remaining before timeout */ public long getRemainingTime() { if (mTimeout == Long.MAX_VALUE) { return Long.MAX_VALUE; } else { return (long) (getTimeout() - readTimeMS()); } } /** * Remaining time before the timeout, in seconds. * * @return the time remaining before timeout, in seconds */ public long getRemainingTimeSec() { if (mTimeout == Long.MAX_VALUE) { return Long.MAX_VALUE; } else { return (long) (getTimeout() / 1000 - readTimeS()); } } /** * Read the elapsed time and return an human friendly string. * * @return the elapsed time in an human friendly string */ public String readTimeString() { return Utilities.Time.millisecondsToString((long) readTimeMS(), 3, false, false); } /** * Read the elapsed time and return an human friendly string. * * @param maxDigits * the number of digits to show * @param showMS * <code>true</code> if ms should be displayed, * <code>false</code> otherwise * @param showAll * <code>false</code> to show only non-null values * @return the elapsed time in an human friendly string */ public String readTimeString(int maxDigits, boolean showMS, boolean showAll) { return Utilities.Time.millisecondsToString((long) readTimeMS(), maxDigits, showMS, showAll); } /** The R ostopwatch. */ private final ReadOnlyStopwatch mROstopwatch = new ReadOnlyStopwatch(); /** * Read only proxy to this stopwatch. * * @return a read only stopwatch linked to this instance */ public ReadOnlyStopwatch getReadOnlyStopwatch() { return mROstopwatch; } /** * <code>ReadOnlystopwatch</code> is a proxy that provides read only access * to a stopwatch * <p> * Creation date: 18/08/2010 - 16:27:36. * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de * Los Andes</a>-<a href="http://copa.uniandes.edu.co">Copa</a> <a * href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp" * >SLP</a> * @version 1.0 */ public class ReadOnlyStopwatch { /** * Get the timeout value for this instance. * * @return the number of ms after which the {@link #hasTimedOut()} * method will return <code>true</code> */ public long getTimeout() { return Stopwatch.this.getTimeout(); } /** * Timeout of this stopwatch. * <p/> * Compare the current running time to the timeout value * * @return <code>true</code> if the stopwatch has timed out * @see #setTimout(long) */ public boolean hasTimedOut() { return Stopwatch.this.hasTimedOut(); } /** * Read the elapsed time on this stopwatch (in milliseconds). * * @return the elapsed time on this stopwatch (in milliseconds) * @see Stopwatch#readTime() */ public double readTimeMS() { return Stopwatch.this.readTimeMS(); } /** * Read the elapsed time on this stopwatch (in seconds). * * @return the elapsed time on this stopwatch (in seconds) * @see Stopwatch#readTime() */ public double readTimeS() { return Stopwatch.this.readTimeS(); } /** * Read the elapsed time on this stopwatch (in nanoseconds). * * @return the elapsed time on this stopwatch (in nanoseconds) * @see Stopwatch#readTime() */ public long readTime() { return Stopwatch.this.readTime(); } /** * Elapsed time in a human friendly string. * * @return a string describing the current elapsed time */ public String readTimeString() { return Stopwatch.this.readTimeString(); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return Stopwatch.this.toString(); } } /* * (non-Javadoc) * * @see java.lang.Object#clone() */ @Override public Stopwatch clone() { Stopwatch clone = new Stopwatch(); clone.mStartTime = mStartTime; clone.mEndTime = mEndTime; clone.mAccumulated = mAccumulated; clone.mTimeout = mTimeout; return clone; } }