// $Id$ // // Copyright 2007-2008 Cisco Systems Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. using System; namespace Etch.Util { /// /// Timer enables making high precision interval tests. In the usual /// scenario, some code is going to be bracketed by calls to /// initialize a timer and later get the elapsed time since the init. /// /// Trying to use the system clock (System.currentTimeMillis) is /// problematic because periodic system time adjustments (by ntp, /// windows time, etc.) will invalidate any interval testing based /// on the system clock. Also, the system clock resolution is not /// all that good (15 ms typically on a windows box). /// /// Timer tmr = new Timer().init(); /// foo(); /// long ns = tmr.elapsedNanos(); /// System.out.println( "foo() took "+ns+" nanos" ); /// /// Timer keeps state, initialized by init(), and used by elapsedBlah() /// and thus is thread safe as long as calls to init() are serialized. /// /// For lower cost timing needs, Timer supports a set of static interfaces. /// /// long t0 = Timer.getStartTime(); /// foo(); /// long ns = Timer.getNanosSince( t0 ); /// System.out.println( "foo() took "+ns+" nanos" ); /// /// Note: reading the high precision clock (which all these methods /// ultimately do) takes about 1,487 nanoseconds on Windows XP Pro /// running on a Dell Precision 370 workstation using jdk 1.5.0_04. /// By comparison, a method call takes about 1.97 nanoseconds. Also, /// on the above platform, the resolution of the timer is 1,396 ns. /// Could be that the resolution is smaller, but we'll never know it /// because just getting the value from the OS is the dominant factor. /// public class Timer { /// /// Constructs the Timer. The timer is not started. /// public Timer() { // nothing to do. } /// /// Initializes the startTime of this timer. /// /// returns this timer. public Timer Init() { startTime = Nanos; return this; } /// /// /// /// the elapsed time in nanos since the last init. public long ElapsedNanos() { if ( startTime == long.MinValue) throw new Exception( "Timer not started" ); return GetNanosSince( startTime ); } /// /// /// /// the elapsed time in micros since the last init. public long ElapsedMicros() { return ElapsedNanos() / NANOS_PER_MICRO; } /// /// /// /// the elapsed time in millis since the last init. public long ElapsedMillis() { return ElapsedNanos() / NANOS_PER_MILLI; } /// /// /// /// the elapsed time in seconds since the last init. public double ElapsedSeconds() { return ElapsedNanos() / NANOS_PER_SECOND; } private long startTime = long.MinValue; /// /// Number of nanoseconds per microsecond. /// public const long NANOS_PER_MICRO = 1000; /// /// Number of nanoseconds per milliseconds. /// public const long NANOS_PER_MILLI = 1000000; public const long TICKS_PER_MILLI = 10000; // 100 ns per tick public const long NANOS_PER_TICK = 100; // 100 ns per tick /// /// Number of nanoseconds per second. /// public const double NANOS_PER_SECOND = 1000000000.0; ////////////////////// // STATIC INTERFACE // ////////////////////// public static long Nanos { get { return DateTime.Now.Ticks * NANOS_PER_TICK; } } /// /// /// /// the starting point of a timing test in millis. public static long currentTimeMillis() { return DateTime.Now.Ticks / TICKS_PER_MILLI; } /// /// /// /// a value returned by getStartTime. /// the number of nanos which have passed since startTime. /// public static long GetNanosSince( long startTime ) { return Nanos - startTime; } /// /// /// /// a value returned by getStartTime. /// the number of micros which have passed since startTime. /// public static long GetMicrosSince( long startTime ) { return GetNanosSince( startTime ) / NANOS_PER_MICRO; } /// /// /// /// a value returned by getStartTime. /// the number of millis which have passed since startTime. /// public static long GetMillisSince( long startTime ) { return GetNanosSince( startTime ) / NANOS_PER_MILLI; } /// /// /// /// a value returned by getStartTime. /// the number of seconds which have passed since startTime. /// public static double GetSecondsSince( long startTime ) { return GetNanosSince( startTime ) / NANOS_PER_SECOND; } /// /// /// /// returns the minimum value of many invocations of /// getNanosSince( getStartTime() ). public static long GetResolution() { long r = long.MaxValue; for ( int i = 0; i < 100000; i++ ) { r = Math.Min( r, GetNanosSince( Nanos ) ); } return r; } /// /// /// /// the number of seconds /// a nice text description of the amount of time public static String HowLong( int s ) { if ( s < 60 ) return s.ToString() + "s"; int m = s / 60; if ( m < 60 ) return m.ToString() + "m" + ( s%60 ) + "s"; int h = m / 60; if (h < 24) return h.ToString() + "h " + ( m%60 ) + "m"; int h_ = h / 24; return h_.ToString() + "d " + ( h%24 ) + "h"; } } }