16

I want to use the highest possible resolution timer using c#. For example, I want to raise an event every 11 ticks (I've heard that tick is the highest possible counter in pc). I tried timer and found that minimum elapsed time is in milliseconds. I looked at stopwatch but stopwatch doesn't raise events.

Thanks.

pgSystemTester
  • 8,979
  • 2
  • 23
  • 49
Syaiful Nizam Yahya
  • 4,196
  • 11
  • 51
  • 71

3 Answers3

19

Using a multimedia timer should give you about 1000 events per second. This code should help you on the way.

     public delegate void TimerEventHandler(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);

    /// <summary>
    /// A multi media timer with millisecond precision
    /// </summary>
    /// <param name="msDelay">One event every msDelay milliseconds</param>
    /// <param name="msResolution">Timer precision indication (lower value is more precise but resource unfriendly)</param>
    /// <param name="handler">delegate to start</param>
    /// <param name="userCtx">callBack data </param>
    /// <param name="eventType">one event or multiple events</param>
    /// <remarks>Dont forget to call timeKillEvent!</remarks>
    /// <returns>0 on failure or any other value as a timer id to use for timeKillEvent</returns>
    [DllImport("winmm.dll", SetLastError = true,EntryPoint="timeSetEvent")]
    static extern UInt32 timeSetEvent(UInt32 msDelay, UInt32 msResolution, TimerEventHandler handler, ref UInt32 userCtx, UInt32 eventType);

    /// <summary>
    /// The multi media timer stop function
    /// </summary>
    /// <param name="uTimerID">timer id from timeSetEvent</param>
    /// <remarks>This function stops the timer</remarks>
    [DllImport("winmm.dll", SetLastError = true)]
    static extern void timeKillEvent(  UInt32 uTimerID );

Do stop these timers after running them. They are quite heavy on your system*. Do catch all exceptions and don't let them escape your event handler.

*Starting more then 5 timers will seriously slow down most systems! Execute as little as possible code in the event handlers and make sure the executing code is faster then 1 millisecond or face serious problems. I started a delegate every 10-50 ticks to increase a label display.

A normal thread switch that occurs on a Thread.Sleep will leave one thread-slot free of your code and will take about 40 milliseconds. You can also increase the thread switch frequency with some NT kernel calls, but please, don't do that.

JYelton
  • 35,664
  • 27
  • 132
  • 191
CodingBarfield
  • 3,392
  • 2
  • 27
  • 54
14

First off, you need to realize that it's extremely difficult, if not impossible, to do exact timing on a computer because of limitations exposed both by the hardware and software. The good news is that this kind of precision is rarely necessary. Ten ticks is an insanely small amount of time. Very little work is getting done by the CPU in this interval, and it's never going to be statistically significant.

For reference, the Windows clock has an accuracy of around 10 milliseconds (less on earlier versions). Wrapping your code with calls to DateTime.UtcNow isn't going to do any better than that.

In your question, you talk about wanting to "raise an event." The problem is that the only type of time-keeping object that raises an event at specific intervals is the Timer object. It's available in 3 different incarnations in the .NET Framework (System.Timers.Timer, System.Threading.Timer, and System.Windows.Forms.Timer), all of which have their own unique use scenarios and relative quirks, but none of them guarantee precision anywhere close to what you're asking for. They're not even designed to do so, and neither are there any equivalent functions exposed by the Windows API that are going to provide this type of precision.

The reason I asked why you were wanting to do this and if you're attempting to benchmark is because that changes the entire game. The .NET Framework (as of version 2.0) provides a Stopwatch object that is expressly designed to accurately measure elapsed time for a situation like benchmarking or performance profiling. The Stopwatch simply wraps the Windows API functions QueryPerformanceFrequency and QueryPerformanceCounter (which should confirm my suggestion as to its intended use). We used to have to P/Invoke these functions to access this type of functionality in earlier versions of the Framework, but it's now conveniently built in. If you need a timer with a relatively high resolution for benchmarking, the Stopwatch is your best bet. In theory, it can provide you with sub-microsecond timing.

But it's not without its problems. It doesn't raise any events, so if your current design relies on event handling, you're going to have to rethink it. And, it's not guaranteed to be perfectly accurate, either. Sure, it may have the highest possible resolution given hardware constraints, but that doesn't mean it will necessarily meet your stated requirements. For example, it may be unreliable on a multiple processor system where Start and Stop have to be executed on the same processor. It shouldn't matter, but it does. It's also subject to being unreliable on processors that can throttle their clock speed up and down. And dare I even mention that the call to QueryPerformanceCounter itself is going to take some time—about 5 microseconds even on a modern 2+ GHz processor, which prevents you from actually being able to achieve that sub-microsecond timing that sounded good in theory. Then again, any reasonable code profiler would consider that amount of time negligible because, well, it is.
(See also: http://www.devsource.com/c/a/Techniques/High-Performance-Timing-under-Windows/2/)

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Thanks for the lenghty explaination. if, for example, i use real time os, can i get that kind of high precision timer? is windows server a real time os? Thanks. – Syaiful Nizam Yahya Nov 18 '10 at 17:13
  • 2
    If you use a RTOS, you might have a chance of a high resolution timer. However, a real time OS doesn't mean things happen immediately, but that they happen within a known time limit, so you still may not be able to time as precise as you're thinking. As for Windows being a RTOS, definitely not. – David Yaw Nov 18 '10 at 17:57
  • 1
    @publicENEMY: David Yaw's response is correct. Even the Server versions of Windows are not real-time operating systems (I run Windows Server as a workstation, it's not that much different). It's also worth pointing out that even if you overcame the software limitations exposed by the OS, you'll still have to contend with the limitations of common PC hardware. If you're considering switching OS's, there *must* be a better way to do what you're trying to achieve. – Cody Gray - on strike Nov 19 '10 at 01:23
  • 1
    Windows never said RealTimeOS on the box it shipped on! .Net only updates it Timevalue once every 40ms or so. – CodingBarfield Dec 20 '10 at 13:20
  • 1
    I fail to see how Stopwatch helps - that provides high resolution _timing_ - it do not raise events at a high resolution – markmnl Dec 19 '13 at 01:29
4

The various timer classes use a larger granularity. Both Threading.Timer and Timers.Timer use 1/64 second, which is 15.625 milliseconds.

If the 'tick' you're referring to is the 100 nanosecond tick, used by the DateTime class, TimeSpan class, and output by the Stopwatch, then the 11 tick length you're asking about is 1,100 nanoseconds, or 1.1 microseconds. To the best of my knowledge, there's no built-in timer that will give you that resolution. If you really do want an event to happen every 1.1 microseconds, you're going to have to remove the idea of a 'timer', and instead think in terms of a short delay. Make a thread high priority, and run your event in a loop. Don't call Thread.Sleep(), since I believe 1.1 microseconds is smaller than the timeslice of the system scheduler. You'll need to do a delay loop instead.

Also, realize that the time interval you're asking about is very, very small. 1.1 microseconds is only 2,200 processor cycles on a 2 GHz processor. Not an insignificant amount, but not a lot of time to get much work done. If you're talking the 1 tick that you said in your comment, that's only 200 processor cycles: That's about enough time to do a few dozen math operations, and maybe call one function.

David Yaw
  • 27,383
  • 4
  • 60
  • 93
  • The tick that interest me is the stopwatch.frequency kinda tick. In other words, processor cycle tick. – Syaiful Nizam Yahya Nov 18 '10 at 09:37
  • 3
    Processor cycle tick, e.g., 2 GHz? That's 0.5 nanoseconds. All except the simplest processor instructions take multiple processor cycles. For example, you might be able to increment an integer in one cycle, but an `if` statement? No way, that's on the order of 10 processor cycles, 5 nanoseconds. There's no way to check a timer at that frequency, much less get any work done. – David Yaw Nov 18 '10 at 16:40
  • 4
    Wait, I take that back. There is a way to have a timer with a frequency of 1 processor cycle: Set the thread to high priority and do `while(true) { ... }` – David Yaw Nov 18 '10 at 16:41
  • 4
    @David Yaw. Last time I checked, while (true) should still execute a short jump to the beginning of the loop, which takes 1 processor cycle, since there is no way to get an instruction executed in less than 1 processor cycle. In the assembly level of programming, an if statement executes differently, according to what you compare to. Comparing to the accumulator is the fastest "if" possible(CMP EAX). The comparison itself takes 1 or 2 cycles(IIRC) and then you need another cycle for a short jump...so, no luck. Asking for the absolutely impossible is just that...Impossible. – ThunderGr Sep 26 '13 at 09:32