diff --git a/Timer.cs b/Timer.cs index b60287f..caa8716 100644 --- a/Timer.cs +++ b/Timer.cs @@ -5,7 +5,284 @@ using System.Threading; 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); + } + } + } + + /// + /// MicroTimer class + /// + 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(); + } + } + + /// + /// MicroTimer Event Argument class + /// + 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")] private static extern bool QueryPerformanceCounter( @@ -22,7 +299,7 @@ namespace lib // Constructor - public Timer() + public TimerWin() { startTime = 0; stopTime = 0;