0

I am trying to use a while loop to create a timer that consistently measures out 3000μs (3 ms) and while it works most of the time, other times the timer can be late by as much as 500μs. Why does this happen and is there a more precise way to make a timer like this?

int getTime() {
    chrono::microseconds μs = chrono::duration_cast< chrono::microseconds >(
        chrono::system_clock::now().time_since_epoch() //Get time since last epoch in μs
        );
    return μs.count(); //Return as integer
}

int main()
{
    int target = 3000, difference = 0;
    while (true) {
        int start = getTime(), time = start;
        while ((time-start) < target) {
            time = getTime();
        }
        difference = time - start;
        if (difference - target > 1) { //If the timer wasn't accurate to within 1μs
            cout << "Timer missed the mark by " + to_string(difference - target) + " microseconds" << endl; //Log the delay
        }
    }
    return 0;
}

I would expect this code to log delays that are consistently within 5 or so μs, but the console output looks like this.

Edit to clarify: I'm running on Windows 10 Enterprise Build 16299, but the behavior persists on a Debian virtual machine.

  • 1
    Are you running on RTOS? If not, do not expect anything. – SergeyA Apr 23 '19 at 19:26
  • Windows 10 Enterprise Build 16299, although the behavior persists on a Debian virtual machine. – Aayla Pozho Apr 23 '19 at 19:28
  • 4
    On a multitasking OS, when your application is running an endless loop like that and never sleeps, the OS might put it on hold arbitrarily to give other processes a time slice aswell. That could be a reason. – Unimportant Apr 23 '19 at 19:29
  • Possible duplicate of [What is the best, most accurate timer in C++?](https://stackoverflow.com/questions/5521146/what-is-the-best-most-accurate-timer-in-c) – Max Voisard Apr 23 '19 at 19:35
  • Possible duplicate of https://stackoverflow.com/q/37444594/2785528. See also my answer at https://stackoverflow.com/a/37445086/2785528. – 2785528 Apr 23 '19 at 20:08

2 Answers2

1

You need to also take into account other running processes. The operating system is likely preempting your process to give CPU time to those other processes/threads, and will non-deterministically return control to your process/thread running this timer.

Granted, this is not 100% true when we consider real-time operating systems or flat-schedulers. But this is likely the case in your code if you're running on a general purpose machine.

jhill515
  • 894
  • 8
  • 26
  • So this is more a problem with running my code on windows than it is a problem with my code? – Aayla Pozho Apr 23 '19 at 19:34
  • 1
    Pretty much, real-time operating system means you can have deterministic performance and Windows definitely isn't one. Microprocessor's with no OS are the only place I know you can guarantee accuracy within only a couple clock cycles. ROS for robots and a few other linux variants can get you probably under a microsecond, but not sure what the lower limit on their accuracy is over having no OS. – Chase R Lewis Apr 23 '19 at 19:38
  • Note that ROS itself isn't an operating system, but a *meta operating system*. Its scheduler runs in parallel with the OS scheduler too. – jhill515 Apr 23 '19 at 21:52
-1

Since you are running on Windows, that RTOS is responsible for keeping time through NTP, as C++ has no built-in functions for it. Check out this Windows API for the SetTimer() function: http://msdn.microsoft.com/en-us/library/ms644906(v=vs.85).aspx.

If you want the best and most high-resolution clock through C++, check out the chrono library:

#include <iostream>
#include <chrono>
#include "chrono_io"

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    auto t1 = Clock::now();
    auto t2 = Clock::now();
    std::cout << t2-t1 << '\n';
}
Max Voisard
  • 1,685
  • 1
  • 8
  • 18
  • Measurements on my older Dell, with Lubuntu 18.04, g++ 7.3.0: 3.95 n seconds per 'time(nullptr)' event; 1.288 µ seconds per 'Posix clock_gettime (CLOCK_REALTIME, &ts);' event; 1.382 µ seconds per 'HRClk_t:now()' event. chrono high-resolution-clock is not too much slower than 'Posix clock'. – 2785528 Apr 23 '19 at 21:07
  • If you're using Ubuntu, keep in mind time will be calculated at different speeds than Windows because of different kernel processes. Posix is unique to Linux only and can't be supported on Windows unlike chrono. You also run into the year 2038 problem with Posix. – Max Voisard Apr 23 '19 at 21:17