Wednesday, January 16, 2013

Windows Time Keeping: Environment.TickCount, DateTime.UtcNow.Ticks, StopWatch, or QueryPerformanceCounter?

http://www.codeproject.com/Articles/2635/High-Performance-Timer-in-C

High-Performance Timer in C#, by

<quote>

High resolution timing is supported in Win32 by the QueryPerformanceCounter() and QueryPerformanceFrequency() API methods. This timer functions has much better resolution than the "standard" millisecond-based timer calls, like the GetTickCount() method. On the other side there is also a little bit overhead when calling this "unmanaged" API methods from C#, but it's better than using the very imprecise GetTickCount() API function. 


</quote>



http://connect.microsoft.com/VisualStudio/feedback/details/622002/low-resolution-stopwatch-behaves-incorrectly

Low-resolution StopWatch behaves incorrectly by Cory Nelson


Stopwatch has two modes: high-resolution and low-resolution.

<quote>
The Stopwatch class is meant to measure elapsed time, independent of the current system time. This means that if an operation takes 100ms, and the system time is advanced 2 seconds, it will still return just 100ms.

When Stopwatch is in high-resolution mode it depends on QueryPerformanceCounter, which provides that behavior. When Stopwatch is in low-resolution mode it depends on DateTime, which does not.

This is inconsistent and, in low-resolution mode, simply wrong behavior. Instead, low-resolution mode should use Environment.TickCount, which is a low-resolution equivalent to QueryPerformanceCounter that provides the correct behavior. 
</quote>



http://stackoverflow.com/questions/243351/environment-tickcount-vs-datetime-now

Environment.TickCount vs DateTime.Now

<quote by="
Joel V. Earnest-DeYoung">
Environment.TickCount is based on GetTickCount() WinAPI function. It's in milliseconds But the actual precision of it is about 15.6 ms. So you can't measure shorter time intervals (or you'll get 0)
DateTime.Ticks is based on GetSystemTimeAsFileTime() WinAPI function. It's in 100s nanoseconds (tenths of microsoconds). The actual precision of DateTime.Ticks depends on the system. On XP, the increment of system clock is about 15.6 ms, the same as in Environment.TickCount. On Windows 7 its precision is 1 ms (while Environemnt.TickCount's is still 15.6 ms)
Stopwatch is based on QueryPerformanceCounter() WinAPI function (but if high-resolution performance counter is not supported by your system, DateTime.Ticks is used)
Before using StopWatch notice two problems:
  • it can be unreliable on multiprocessor systems (see MS kb895980, kb896256)
  • it is unreliable if CPU frequency varies (read this article)
You can evaluate the precision on your system with simple test:
static void Main(string[] args)
{
    const int Counts = 3500000;
    long x = DateTime.UtcNow.Ticks;
    int k;
    for (int i = 0; i < Counts; i++) ;
    long y = DateTime.UtcNow.Ticks;

    int xx = Environment.TickCount;
    for (int i = 0; i < Counts; i++) ;
    int yy = Environment.TickCount;

    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < Counts; i++);
    sw.Stop();
    long yyy = sw.ElapsedTicks;

    Console.WriteLine("DateTime:\t{0} ms", (y-x)/(10000.0));
    Console.WriteLine("Environment:\t{0} ms", (yy - xx));
    Console.WriteLine("StopWatch:\t{0} ms", (yyy * 1000.0)/ Stopwatch.Frequency );
    Console.ReadKey();
}
Adjust Counts according to your system speed to see the differences on small intervals (within several milliseconds). And compile in DEBUG so loops won't be optimized away.
 </quote>

Questions:
  • where is it mentioned that TickCount resolution is ~15msec?