using System;
using System.Runtime.InteropServices;namespace Bluebit.Utility
{
/// <summary>The %PerformanceTimer% class can be used to measure intervals of time.</summary>
/// <remarks>
/// <para>Normally you will use the <strong>PerformanceTimer</strong> class is as
/// follows:</para>
/// <list type="bullet">
/// <item>Create a new instance of the %PerformanceTimer% class.</item>
/// <item>Call the
/// <a href="Bluebit.Learning~Bluebit.Utility.PerformanceTimer~StartTimer.html">StartTimer</a>
/// method.</item>
/// <item>Execute any code you need to measure its duration in time.</item>
/// <item>Call the
/// <a href="Bluebit.Learning~Bluebit.Utility.PerformanceTimer~StopTimer.html">StopTimer</a>
/// method.</item>
/// <item>Read the
/// <a href="Bluebit.Learning~Bluebit.Utility.PerformanceTimer~Duration.html">Duration</a>
/// property to get the cumulative elapsed time the timer has been running. You may
/// also read this property while the timer is running.</item>
/// <item>Call the
/// <a href="Bluebit.Learning~Bluebit.Utility.PerformanceTimer~Reset.html">Reset</a>
/// method to set the
/// <a href="Bluebit.Learning~Bluebit.Utility.PerformanceTimer~Duration.html">Duration</a>
/// property to 0.</item>
/// </list>
/// </remarks>
public class PerformanceTimer
{
/////////////////////
#region PRIVATE FIELDS
private long _freq; // internal performance-counter frequency, in counts per second
private long _bias; // the time it takes to execute a StartTimer and a StopTimer command.
private long _start; // last time the timer was started
private long _stop; // last time the timer was stopped
private long _duration; // cumulative elapsed time.
private bool _running; // current state of the timer.
#endregion
/////////////////////
#region EXTERNAL DECLARATIONS
[DllImport("kernel32.dll")]
extern static short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
extern static short QueryPerformanceFrequency(ref long x);
#endregion
/////////////////////
#region CONSTRUCTOR
/// <summary>Creates a new instance of the %PerformanceTimer% class</summary>
public PerformanceTimer()
{
QueryPerformanceFrequency(ref _freq);
if (_freq == 0)
throw new ApplicationException("The installed hardware does not support a high-resolution performance counter.");
// calculate the _bias; the first result maybe inaccurate
StartTimer();
StopTimer();
StartTimer();
StopTimer();
_bias = _stop - _start;
_duration = 0;
}
#endregion
/////////////////////
#region PUBLIC METHODS
/// <summary>Starts the timer.</summary>
public void StartTimer()
{
if (!_running)
{
_running = true;
QueryPerformanceCounter(ref _start);
}
}
/// <summary>
/// Stops the timer.
/// </summary>
public void StopTimer()
{
if (_running)
{
QueryPerformanceCounter(ref _stop);
long d = _stop - _start - _bias;
d = (d > 0) ? d : 0;
_duration += d;
_running = false;
}
}
/// <summary>
/// Resets the timer.
/// </summary>
/// <remarks>
/// The %Reset% method sets the %Duration% of the timer to zero. If the timer is
/// running it is stopped.
/// </remarks>
public void Reset()
{
if (_running) StopTimer();
_duration = 0;
}
#endregion
/////////////////////
#region PUBLIC PROPERTIES
/// <summary>Gets the cumulative elapsed time the timer has been running.</summary>
/// <value>
/// A %System.Double% representing the number of seconds the timer has been
/// running.
/// </value>
public double Duration
{
get
{
if (_running)
{
QueryPerformanceCounter(ref _stop);
long d = _stop - _start - _bias;
d = (d > 0) ? d : 0;
return (double)(_duration + d) / (double)_freq;
}
return (double)_duration / (double)_freq;
}
}
/// <summary>
/// Gets the current performance-counter frequency, in counts per second.
/// </summary>
public long Frequency
{
get { return _freq; }
}
/// <summary>
/// Gets the current state of the timer.
/// </summary>
/// <value>
/// <strong>true</strong> if timer is running, <strong>false</strong> if timer is
/// stopped.
/// </value>
/// <remarks>
/// The %StartTimer% method sets this property to <strong>true</strong> whereas the
/// %StopTimer% method sets it to <strong>false</strong>
/// </remarks>
public bool IsRunning
{
get { return _running; }
}
#endregion
/////////////////////
}
}