1

I write two timer in C++ and Python, and find out that C++'s is not very accurate compared with Python's.
Here is C++'s code:

#include <chrono>
#include <iomanip> // setprecision
#include <iostream>

using namespace std;

// from: https://stackoverflow.com/a/1658429/6611263
#ifdef _WIN32
    #include <windows.h>

    void sleep(unsigned milliseconds)
    {
        Sleep(milliseconds);
    }
#else
    #include <unistd.h>

    void sleep(unsigned milliseconds)
    {
        usleep(milliseconds * 1000); // takes microseconds
    }
#endif

// from: https://stackoverflow.com/a/29560999/6611263
double time()
{
    double fractional_seconds_since_epoch
        = std::chrono::duration_cast<std::chrono::duration<double>>(
            std::chrono::system_clock::now().time_since_epoch()).count();
    return fractional_seconds_since_epoch;
}

void test_timer()
{
    double t0 = time();
    for (int i=0; i<10; i++)
    {
        sleep(1000);
        double duration = time() - t0;
        cout << "duration: " << fixed << setprecision(4) << duration << "s\n";
    }
}

int main()
{
    test_timer();
    return 0;
}

C++'s result is here:

duration: 1.0014s
duration: 2.0038s
duration: 3.0072s
duration: 4.0096s
duration: 5.0119s
duration: 6.0143s
duration: 7.0167s
duration: 8.0191s
duration: 9.0205s
duration: 10.0219s

Python's code is here:

import time

def test_timer():
    t0 = time.time()
    for i in range(10):
        time.sleep(1)
        duration = time.time() - t0
        print("duration: {:.4f}s".format(duration))
        pass
    pass

def main():
    test_timer()
    pass

if __name__ == '__main__':
    main()
    pass

Python's result is here:

duration: 1.0004s
duration: 2.0008s
duration: 3.0012s
duration: 4.0016s
duration: 5.0019s
duration: 6.0023s
duration: 7.0027s
duration: 8.0031s
duration: 9.0035s
duration: 10.0039s

So is there way to record time more accurate in C++? Thank you in advance.
N.B. Environment: WIN 10 x64, C++17, Python 3.7

cmjdxy
  • 396
  • 1
  • 2
  • 15
  • 3
    You are not just measuring the time of the sleep. You are also measuring all the other stuff (Ex: getting the current time, printing the msg). – 001 Dec 05 '19 at 02:47
  • 1
    You could also store the time values in an array, then print the results after the loop has completed. – 001 Dec 05 '19 at 02:48
  • 1
    With g++ 9.2, on Linux, Ryzen Threadripper CPUs, I get: 1.0001s, 2.0002s, 3.0003s, 4.0004s, etc... Scout's honor! Try getting rid of `iostream`s and replace it with `printf`, perhaps, or `std::to_chars`. iostreams are well known pigs and have a lot of overhead. – Sam Varshavchik Dec 05 '19 at 02:50
  • I tried, and the result is indeed better. Thank you! @Mopp – cmjdxy Dec 05 '19 at 03:26
  • I tried, and the result is indeed better, thought not better than yours. Maybe my machine is not very competitive. Thank you! @Varshavchik – cmjdxy Dec 05 '19 at 03:29
  • Most end user OSes are not real time systems. Sleeping is approximate not exact, and system clocks don't have the 1ms precision to them. – Remy Lebeau Dec 05 '19 at 04:25

2 Answers2

4

So is there way to record time more accurate in C++?

Yes. Use std::this_thread::sleep_until instead of sleep.

By sleeping until a time point, instead of for a time duration, you no longer accumulate loop overhead with each iteration. There will still be some inaccuracy, but it doesn't grow.

Below I show how to do this. Additionally I show how to stay within the type-safe <chrono> type system right up until the final point of printing duration:

#include <chrono>
#include <iomanip> // setprecision
#include <iostream>
#include <thread>

using namespace std;

void test_timer()
{
    auto next = 0s;
    auto t0 = chrono::system_clock::now();
    for (int i=0; i<10; i++)
    {
        this_thread::sleep_until(t0 + ++next);
        chrono::duration<double> duration = chrono::system_clock::now() - t0;
        cout << "duration: " << fixed << setprecision(4) << duration.count() << "s\n";
    }
}

int main()
{
    test_timer();
}

For me this just output:

duration: 1.0017s
duration: 2.0009s
duration: 3.0040s
duration: 4.0007s
duration: 5.0010s
duration: 6.0015s
duration: 7.0008s
duration: 8.0030s
duration: 9.0012s
duration: 10.0032s
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
0

First of as mentioned std::this_thread::sleep_for is not good to test time measurement;

This function may block for longer than sleep_duration due to scheduling or resource contention delays.

Also instead of std::chrono::system_clock I suggest to use std::chrono::high_resolution_clock

bertubezz
  • 361
  • 1
  • 8