Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to measure elapsed time without being affected by changes in system time

Tags:

c++

chrono

I want to measure elapsed time in seconds. With std::chrono::steady_clock I do it. However it suffers from system time changes.

Wasn't steady_clock supposed to not being affected by changes in system time?

How can I do that?

Here is the code:

#include <iostream>
#include <chrono>
#include <time.h>

std::chrono::steady_clock::time_point t = std::chrono::steady_clock::now();

/* Change system time */
std::time_t tnow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
tnow -= 20;
std::cout << "stime: " << stime(&tnow) << std::endl;
/********************************************************/

sleep(5);
std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
std::cout << "ELAPSED: " << std::chrono::duration_cast<std::chrono::seconds>(t2-t).count() << std::endl;

This results:

stime: 0
ELAPSED: -15

What I wanted to get was:

ELAPSED: 5

Edit:

I have added C tag, because it seems that it is a kernel (or buildroot of board) bug. So, how could I achieve this without chrono? I mean, in a straight way (without having to watch system time changes).

How was the people living before chrono?

like image 853
Mert Mertce Avatar asked Jul 23 '20 12:07

Mert Mertce


1 Answers

You can file a bug with your vendor.

From the standard:

Objects of class steady_­clock represent clocks for which values of time_­point never decrease as physical time advances and for which values of time_­point advance at a steady rate relative to real time. That is, the clock may not be adjusted.

If you can find a reliable source of monotonic time on your system, you can easily wrap that source in a custom chrono::clock and subsequently still make use of the type-safe chrono system. For example:

#include <chrono>

struct MyClock
{
    using duration                  = std::chrono::nanoseconds;
    using rep                       = duration::rep;
    using period                    = duration::period;
    using time_point                = std::chrono::time_point<MyClock>;
    static constexpr bool is_steady = true;

    static time_point now() noexcept
    {
        using namespace std::chrono;
        timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        return time_point{seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec}};
    }
};

Now you can say things like:

MyClock::time_point t = MyClock::now();
// ...
MyClock::time_point t2 = MyClock::now();
std::cout << "ELAPSED: " << std::chrono::duration_cast<std::chrono::seconds>(t2-t).count() << std::endl;
like image 155
Howard Hinnant Avatar answered Oct 13 '22 20:10

Howard Hinnant