Use stopwatch instead of QPC directly.
This commit is contained in:
parent
8315ec8a16
commit
36e91adeaa
281
Timer.cs
281
Timer.cs
@ -5,7 +5,284 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
public class Timer
|
|
||||||
|
public class MicroStopwatch : System.Diagnostics.Stopwatch
|
||||||
|
{
|
||||||
|
readonly double _microSecPerTick
|
||||||
|
= 1000000D / System.Diagnostics.Stopwatch.Frequency;
|
||||||
|
|
||||||
|
public MicroStopwatch()
|
||||||
|
{
|
||||||
|
if (!System.Diagnostics.Stopwatch.IsHighResolution)
|
||||||
|
{
|
||||||
|
throw new Exception("On this system the high-resolution " +
|
||||||
|
"performance counter is not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ElapsedMicroseconds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (long)(ElapsedTicks * _microSecPerTick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MicroTimer class
|
||||||
|
/// </summary>
|
||||||
|
public class MicroTimer
|
||||||
|
{
|
||||||
|
public delegate void MicroTimerElapsedEventHandler(
|
||||||
|
object sender,
|
||||||
|
MicroTimerEventArgs timerEventArgs);
|
||||||
|
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
|
||||||
|
|
||||||
|
System.Threading.Thread _threadTimer = null;
|
||||||
|
long _ignoreEventIfLateBy = long.MaxValue;
|
||||||
|
long _timerIntervalInMicroSec = 0;
|
||||||
|
bool _stopTimer = true;
|
||||||
|
|
||||||
|
public MicroTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public MicroTimer(long timerIntervalInMicroseconds)
|
||||||
|
{
|
||||||
|
Interval = timerIntervalInMicroseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Interval
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return System.Threading.Interlocked.Read(
|
||||||
|
ref _timerIntervalInMicroSec);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
System.Threading.Interlocked.Exchange(
|
||||||
|
ref _timerIntervalInMicroSec, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long IgnoreEventIfLateBy
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return System.Threading.Interlocked.Read(
|
||||||
|
ref _ignoreEventIfLateBy);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
System.Threading.Interlocked.Exchange(
|
||||||
|
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (_threadTimer != null && _threadTimer.IsAlive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
if (Enabled || Interval <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopTimer = false;
|
||||||
|
|
||||||
|
System.Threading.ThreadStart threadStart = delegate()
|
||||||
|
{
|
||||||
|
NotificationTimer(ref _timerIntervalInMicroSec,
|
||||||
|
ref _ignoreEventIfLateBy,
|
||||||
|
ref _stopTimer);
|
||||||
|
};
|
||||||
|
|
||||||
|
_threadTimer = new System.Threading.Thread(threadStart);
|
||||||
|
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
|
||||||
|
_threadTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_stopTimer = true;
|
||||||
|
|
||||||
|
if (_threadTimer != null && _threadTimer.ManagedThreadId ==
|
||||||
|
System.Threading.Thread.CurrentThread.ManagedThreadId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Enabled)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.SpinWait(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationTimer(ref long timerIntervalInMicroSec,
|
||||||
|
ref long ignoreEventIfLateBy,
|
||||||
|
ref bool stopTimer)
|
||||||
|
{
|
||||||
|
int timerCount = 0;
|
||||||
|
long nextNotification = 0;
|
||||||
|
|
||||||
|
MicroStopwatch microStopwatch = new MicroStopwatch();
|
||||||
|
microStopwatch.Start();
|
||||||
|
|
||||||
|
while (!stopTimer)
|
||||||
|
{
|
||||||
|
long callbackFunctionExecutionTime =
|
||||||
|
microStopwatch.ElapsedMicroseconds - nextNotification;
|
||||||
|
|
||||||
|
long timerIntervalInMicroSecCurrent =
|
||||||
|
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
|
||||||
|
long ignoreEventIfLateByCurrent =
|
||||||
|
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
|
||||||
|
|
||||||
|
nextNotification += timerIntervalInMicroSecCurrent;
|
||||||
|
timerCount++;
|
||||||
|
long elapsedMicroseconds = 0;
|
||||||
|
|
||||||
|
while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
|
||||||
|
< nextNotification)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.SpinWait(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
long timerLateBy = elapsedMicroseconds - nextNotification;
|
||||||
|
|
||||||
|
if (timerLateBy >= ignoreEventIfLateByCurrent)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroTimerEventArgs microTimerEventArgs =
|
||||||
|
new MicroTimerEventArgs(timerCount,
|
||||||
|
elapsedMicroseconds,
|
||||||
|
timerLateBy,
|
||||||
|
callbackFunctionExecutionTime);
|
||||||
|
MicroTimerElapsed(this, microTimerEventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
microStopwatch.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MicroTimer Event Argument class
|
||||||
|
/// </summary>
|
||||||
|
public class MicroTimerEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
// Simple counter, number times timed event (callback function) executed
|
||||||
|
public int TimerCount { get; private set; }
|
||||||
|
|
||||||
|
// Time when timed event was called since timer started
|
||||||
|
public long ElapsedMicroseconds { get; private set; }
|
||||||
|
|
||||||
|
// How late the timer was compared to when it should have been called
|
||||||
|
public long TimerLateBy { get; private set; }
|
||||||
|
|
||||||
|
// Time it took to execute previous call to callback function (OnTimedEvent)
|
||||||
|
public long CallbackFunctionExecutionTime { get; private set; }
|
||||||
|
|
||||||
|
public MicroTimerEventArgs(int timerCount,
|
||||||
|
long elapsedMicroseconds,
|
||||||
|
long timerLateBy,
|
||||||
|
long callbackFunctionExecutionTime)
|
||||||
|
{
|
||||||
|
TimerCount = timerCount;
|
||||||
|
ElapsedMicroseconds = elapsedMicroseconds;
|
||||||
|
TimerLateBy = timerLateBy;
|
||||||
|
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class Timer
|
||||||
|
{
|
||||||
|
MicroStopwatch m_watch;
|
||||||
|
private long startTime;
|
||||||
|
private long stopTime;
|
||||||
|
private long freq;
|
||||||
|
private long freq_millis;
|
||||||
|
|
||||||
|
public Timer()
|
||||||
|
{
|
||||||
|
m_watch = new MicroStopwatch();
|
||||||
|
//startTime = m_watch.ElapsedMicroseconds;
|
||||||
|
//stopTime = m_watch.ElapsedMicroseconds;
|
||||||
|
freq = 1000 * 1000;
|
||||||
|
freq_millis = freq / 1000;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the timer
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
startTime = m_watch.ElapsedMicroseconds;
|
||||||
|
stopTime = m_watch.ElapsedMicroseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the timer
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
stopTime = m_watch.ElapsedMicroseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Seconds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
long current = m_watch.ElapsedMicroseconds;
|
||||||
|
return (double)( current - startTime ) / freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
long current = m_watch.ElapsedMicroseconds;
|
||||||
|
return ( current - startTime ) / freq_millis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Duration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)( stopTime - startTime ) / (double)freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long DurationMS
|
||||||
|
{
|
||||||
|
get { return ( stopTime - startTime ) / freq_millis; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class TimerWin
|
||||||
{
|
{
|
||||||
[DllImport("Kernel32.dll")]
|
[DllImport("Kernel32.dll")]
|
||||||
private static extern bool QueryPerformanceCounter(
|
private static extern bool QueryPerformanceCounter(
|
||||||
@ -22,7 +299,7 @@ namespace lib
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|
||||||
public Timer()
|
public TimerWin()
|
||||||
{
|
{
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
stopTime = 0;
|
stopTime = 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user