Question

I am trying to implement a time service that will report time with greater accuracy than 1ms. I thought an easy solution would be to take an initial measurement and use StopWatch to add a delta to it. The problem is that this method seems to diverge extremely fast from wall time. For example, the following code attempts to measure the divergence between Wall Time and my High Resolution Clock:

public static void Main(string[] args)
{
    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
    DateTime baseDateTime = DateTime.UtcNow;
    s.Start();
    long counter = 0;
    while(true)
    {
        DateTime utcnow = DateTime.UtcNow;
        DateTime hpcutcnow = baseDateTime + s.Elapsed;
        Console.WriteLine(String.Format("{0}) DT:{1} HP:{2} DIFF:{3}", 
            ++counter, utcnow, hpcutcnow, utcnow - hpcutcnow));
        Thread.Sleep(1000);
    }
}

I am diverging at a rate of about 2ms/minute on fairly recent sever hardware.

Is there another time facility in windows that I am not aware of that will be more accurate? If not, is there a better approach to creating a high resolution clock or a 3rd party library I should be using?

Était-ce utile?

La solution

Getting an accurate clock is difficult. Stopwatch has a very high resolution, but it is not accurate, deriving its frequency from a signal in the chipset. Which operates at typical electronic part tolerances. Cut-throat competition in the hardware business preempted the expensive crystal oscillators with a guaranteed and stable frequency.

DateTime.UtcNow isn't all that accurate either, but it gets help. Windows periodically contacts a time service, the default one is time.windows.com to obtain an update of a high quality clock. And uses it to recalibrate the machine's clock, inserting small adjustments to get the clock to catch up or slow down.

You need lots of bigger tricks to get it accurate down to a millisecond. You can only get a guarantee like that for code that runs in kernel mode, running at interrupt priority so it cannot get pre-empted by other code and with its code and data pages page-locked so it can't get hit with page faults. Commercial solutions use a GPS radio to read the clock signal of the GPS satellites, backed up by an oscillator that runs in an oven to provide temperature stability. Reading such a clock is the hard problem, you don't have much use for a sub-millisecond clock source when your program that uses it can get pre-empted by the operating system just as it obtained the time and not start running again until ~45 msec later. Or worse.

DateTime.UtcNow is accurate to 15.625 milliseconds and stable over very long periods thanks to the time service updates. Going lower than that just doesn't make much sense, you can't get the execution guarantee you need in user mode to take advantage of it.

Autres conseils

Apparently in Windows 8/Server 2012 a new API was added specifically for getting high resolution timestamps, the GetSystemTimePreciseAsFileTime API. I haven't had a chance to play around with this, but it looks promising.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top