blob: aa36a302520c797e65e5ea2d568e369b362ddda6 [file] [log] [blame]
// $Id$
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 Org.Apache.Etch.Bindings.Csharp.Util
{
/// <summary>
/// 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.
/// </summary>
public class Timer
{
/// <summary>
/// Constructs the Timer. The timer is not started.
/// </summary>
public Timer()
{
// nothing to do.
}
/// <summary>
/// Initializes the startTime of this timer.
/// </summary>
/// <returns>returns this timer.</returns>
public Timer Init()
{
startTime = Nanos;
return this;
}
/// <summary>
///
/// </summary>
/// <returns>the elapsed time in nanos since the last init.</returns>
public long ElapsedNanos()
{
if ( startTime == long.MinValue)
throw new Exception( "Timer not started" );
return GetNanosSince( startTime );
}
/// <summary>
///
/// </summary>
/// <returns>the elapsed time in micros since the last init.</returns>
public long ElapsedMicros()
{
return ElapsedNanos() / NANOS_PER_MICRO;
}
/// <summary>
///
/// </summary>
/// <returns>the elapsed time in millis since the last init.</returns>
public long ElapsedMillis()
{
return ElapsedNanos() / NANOS_PER_MILLI;
}
/// <summary>
///
/// </summary>
/// <returns>the elapsed time in seconds since the last init.</returns>
public double ElapsedSeconds()
{
return ElapsedNanos() / NANOS_PER_SECOND;
}
private long startTime = long.MinValue;
/// <summary>
/// Number of nanoseconds per microsecond.
/// </summary>
public const long NANOS_PER_MICRO = 1000;
/// <summary>
/// Number of nanoseconds per milliseconds.
/// </summary>
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
/// <summary>
/// Number of nanoseconds per second.
/// </summary>
public const double NANOS_PER_SECOND = 1000000000.0;
//////////////////////
// STATIC INTERFACE //
//////////////////////
public static long Nanos
{
get
{
return DateTime.Now.Ticks * NANOS_PER_TICK;
}
}
/// <summary>
///
/// </summary>
/// <returns>the starting point of a timing test in millis.</returns>
public static long currentTimeMillis()
{
return DateTime.Now.Ticks / TICKS_PER_MILLI;
}
/// <summary>
///
/// </summary>
/// <param name="startTime">a value returned by getStartTime.</param>
/// <returns>the number of nanos which have passed since startTime.</returns>
/// <see cref="Nanos"/>
public static long GetNanosSince( long startTime )
{
return Nanos - startTime;
}
/// <summary>
///
/// </summary>
/// <param name="startTime">a value returned by getStartTime.</param>
/// <returns>the number of micros which have passed since startTime.</returns>
/// <see cref="Nanos"/>
public static long GetMicrosSince( long startTime )
{
return GetNanosSince( startTime ) / NANOS_PER_MICRO;
}
/// <summary>
///
/// </summary>
/// <param name="startTime">a value returned by getStartTime.</param>
/// <returns>the number of millis which have passed since startTime.</returns>
/// <see cref="Nanos"/>
public static long GetMillisSince( long startTime )
{
return GetNanosSince( startTime ) / NANOS_PER_MILLI;
}
/// <summary>
///
/// </summary>
/// <param name="startTime">a value returned by getStartTime.</param>
/// <returns>the number of seconds which have passed since startTime.</returns>
/// <see cref="Nanos"/>
public static double GetSecondsSince( long startTime )
{
return GetNanosSince( startTime ) / NANOS_PER_SECOND;
}
/// <summary>
///
/// </summary>
/// <returns>returns the minimum value of many invocations of
/// getNanosSince( getStartTime() ).</returns>
public static long GetResolution()
{
long r = long.MaxValue;
for ( int i = 0; i < 100000; i++ )
{
r = Math.Min( r, GetNanosSince( Nanos ) );
}
return r;
}
/// <summary>
///
/// </summary>
/// <param name="s">the number of seconds</param>
/// <returns>a nice text description of the amount of time</returns>
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";
}
}
}