Home > Back-end >  Why does chrono::system_clock returns microseconds whereas clock_gettime returns nanoseconds
Why does chrono::system_clock returns microseconds whereas clock_gettime returns nanoseconds

Time:12-25

std::chrono::system_clock::time_since_epoch().count() gives me a result in microseconds.

I want the current time in nanoseconds. But I can't use high_resolution_clock because on my system it is an alias on steady_clock (the monotonic clock).

I know my system is nanoseconds capable, because if I use clock_gettime(CLOCK_REALTIME, &ts) I am getting a correct nanosecond-resolution epoch time.

How can I tell std::chrono to use the nanosecond resolution? I'd like to avoid using clock_gettime and stick to the cpp wrapper.

CodePudding user response:

I am getting a correct nanosecond-resolution epoch time.

Are you? clock_gettime is required to return a time in nanoseconds, regardless of what clock you're accessing. This doesn't mean that CLOCK_REALTIME actually provides this resolution. It may internally only have microsecond resolution and expresses nanoseconds by multiplying by 1000.

By contrast, the actual resolution of a chrono clock is specified by the implementation. It is not a mandated part of the UI; it can vary from system to system and from clock to clock. So if a particular implementation's system_clock::period is in microseconds, then that is all the resolution the implementation is willing to claim to provide.

Maybe the implementation could provide more resolution, but if it could, it would probably say so. So if it doesn't, then that means the implementation doesn't feel comfortable claiming to provide more resolution.

However, if you feel that clock_gettime really does provide better resolution (rather than simply giving more digits), you can just use that. In C 20, system_clock is explicitly UNIX time. As such, if you have a time in nanoseconds, you can convert it to a time_point<system_clock, nanoseconds>:

namespace chrono = std::chrono;

...

using nano_sys = chrono::time_point<chrono::system_clock, chrono::nanoseconds>;

auto sys_tp_ns = nano_sys(chrono::nanoseconds(time_in_nanoseconds));

CodePudding user response:

How can I tell std::chrono to use the nanosecond resolution?

This sounds like a good use for writing your own custom clock. It is much easier than it sounds:

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

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

    static time_point now()
    {
        timespec ts;
        if (clock_gettime(CLOCK_REALTIME, &ts))
            throw 1;
        using sec = std::chrono::seconds;
        return time_point{sec{ts.tv_sec} duration{ts.tv_sec}};
    }
};

Just have your now() call clock_gettime with CLOCK_REALTIME. Then package up the return in a chrono::time_point with nanoseconds resolution.

Warning, I just tried this on macOS and called now() twice in a row. It printed out the same number of nanoseconds each time. And there's no way that the call is executing in under a nanosecond. So I'm getting nanosecond precision, but not nanosecond accuracy.

If you would like my_clock to participate in the C 20 std::chrono::clock_cast facility (as suggested by Nicol Bolas in the comments below), add these two static member functions to my_clock:

template<typename Duration>
static
std::chrono::time_point<std::chrono::system_clock, Duration>
to_sys(const std::chrono::time_point<my_clock, Duration>& tp)
{
    return std::chrono::time_point<std::chrono::system_clock, Duration>
        {tp.time_since_epoch()};
}

template<typename Duration>
static
std::chrono::time_point<my_clock, Duration>
from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>& tp)
{
    return std::chrono::time_point<my_clock, Duration>{tp.time_since_epoch()};
}

Now you can say things like:

cout << clock_cast<system_clock>(my_clock::now()) << '\n';

You will also be able to clock_cast to or from all other C 20 and custom clocks that participate in the clock_cast facility.

CodePudding user response:

First of all, mind you that on GCC libstc std::chrono is just a thin wrapper of syntax sugar around clock_gettime(). You are talking about the same thing here. std::chrono uses clock_gettime().

    system_clock::time_point
    system_clock::now() noexcept
    {
      timespec tp;
      clock_gettime(CLOCK_REALTIME, &tp);
      return time_point(duration(chrono::seconds(tp.tv_sec)
                                   chrono::nanoseconds(tp.tv_nsec)));
    }

Source: https://code.woboq.org/gcc/libstdc -v3/src/c 11/chrono.cc.html

(above code was cleaned up)

So the precision is there, you just need to retrieve it in nanoseconds with

uint64_t utc_now_nanos() {
    std::chrono::steady_clock::time_point tp = std::chrono::steady_clock::now();
    return std::chrono::time_point_cast<std::chrono::nanoseconds>(tp).time_since_epoch().count();
}
  • Related