How to change setWaitableTimer accuracy on Windows 10 20H1 and later

  c++, windows

There seems to have been a change to timer resolution in Windows 10 20H1 (https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/).

If you want to use sleep() then reasonable accuracy can still be obtained by using the timeBeginPeriod() function. This approach doesn’t seem to work with the waitable timers. Does anyone know of a way of improving the accuracy of these timers?

This is an extract from the test program I am using

// class Results omitted for clarity - it sums the duration calls to timerCallback() and divides it by the number of times it was called.

   class Program
    {
        static Results m_Results = new Results();

        // Windows API function imports
        [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
        public static extern uint TimeBeginPeriod(uint uMilliseconds);
        [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
        public static extern uint TimeEndPeriod(uint uMilliseconds);
        [DllImport("kernel32.dll")]
        public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, CallBack pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
        // callback definition
        public delegate bool CallBack(IntPtr lpArg, int dwTimerLowValue, int dwTimerHighValue);


        // Main method, run when the application is run
        static void Main(string[] args)
        {
            SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, false, "MyWaitabletimer");
            CallBack myCallBack = new CallBack(Program.timerCallback);  // This function records the time its executed in a global list
            const int period = 40;              // Fire the timer every 40 mS
            long duetime = period * -10000;     // Keep firing the timer for 4 seconds
            TimeBeginPeriod(1);                 // *** This call appears to make no difference.
            SetWaitableTimer(handle, ref duetime, period, myCallBack, IntPtr.Zero, false);
            TimeEndPeriod(1);                   // *** This call appears to make no difference.

            Thread.Sleep(4000);
            Console.WriteLine("count = {0}", m_Results.getCount());
            Console.WriteLine("total duration = {0}", m_Results.getTotalDuration());
            Console.WriteLine("average = {0}", m_Results.getResults());
            Console.WriteLine("Tests complete");
            Console.ReadKey();
        }
        public static bool timerCallback(IntPtr lpArg, int dwTimerLowValue, int dwTimerHighValue)
        {
            m_Results.addDifference(DateTime.Now.Millisecond);    
            return true;
        }

When I run the code I get a count of 84, 85 or 86, a total duration <4000 and an average between 46 and 47 mS.

Is my testing method incorrect?
I appreciate it won’t always be exactly 40mS but I can get the Sleep call accurate to within .1 of a mS. Is there some command to enable better accuracy?

BTW – I tried the code in C++, but I can’t get the timerFunc() to trigger, event when waiting objects.

Source: Windows Questions

LEAVE A COMMENT