0
votes

I've been reading up about this, and the numbers don't add up. On my operating system (Windows), I can check the resolution of the system clock like this:

LARGE_INTEGER largeInt; // Basically a struct/union containing a long long
QueryPerformanceFrequency(&largeInt);
// largeInt now holds the frequency of my system's clock, it's 3903987
// This ends up being a resolution of about 256 nanoseconds

All is good, but now I want to use std::chrono to check the same details. According to cppreference.com and a popular answer on this site, the period of a std::chrono clock is a compile-time ratio consisting of a numerator and denominator which specifies how many seconds there are between ticks.

cppreference.com:

period: a std::ratio representing the tick period(i.e.the number of seconds per tick)

And from the a stack overflow answer:

The minimum representable duration is high_resolution_clock::period::num / high_resolution_clock::period::den seconds. You can print it like this:

std::cout <<
(double)std::chrono::high_resolution_clock::period::num /   
std::chrono::high_resolution_clock::period::den;

So I tried:

// On Windows the result is typedeffed as intmax_t, which is a typedef for a long long
    intmax_t numerator = std::chrono::high_resolution_clock::period::num;
    intmax_t denominator = std::chrono::high_resolution_clock::period::den;
    // numerator is 1 and denominator is one billion, which would suggest a 
    // tick period of one nanosecond?

According to what's been explained my system's clock is capable of one nanosecond resolution? The OS doesn't seem to think so. I've also tried some other tools that support that my system's clock frequency is around 3903987, and so I don't see how it could manage a resolution finer than that.

I'm not sure whether the frequency changes with CPU power settings / boost mode or not, though high_resolution_clock::is_steady results as true. I restarted my computer twice and got frequency counters of 3903994 and 3903991, so each time booting up this number seems to change. I guess this wouldn't be ideal to calculate the clock at compile time, as opposed to the start of running the program.

So is there way to get the actual resolution/frequency of your system clock with std::chrono?

1
This seems to be something you have to read up on in your processor manufacturer's manual, not something that can be tested via software to reasonable accuracy. Also modern processors change their frequency all the time, so the value would too.nwp
@nwp So there's no such thing as a reliably consistent clock? I know that processors run at different speeds, but as far as a timekeeping system, there's no standard among hardware that gives the same results?Zebrafish
Clocks are surprisingly complicated beasts. You can get the current time in some precision, but the result becomes wrong immediately. What do you actually want to achieve? Micro benchmarks?nwp
@nwp No, it's just I want to implement a timekeeping system, and I'm currently using either the WINAPI, SDL library which abstracts away the platform specific calls and just lets you get the time nice and easy, or, seeing as though C++ is really becoming standardised these days I figured I may as well write the thing in std::chrono and trust that the standard library will handle it the right way based on where it's compiled. I'm not sure this will be possible with a such a variable frequency. I know that a library like SDL will simply call the platform-specific API,Zebrafish
so SDL_GetPerformanceFrequency will call the Windows specific function, and so on. I thought the C++ standard library could manage the same thing.Zebrafish

1 Answers

0
votes

period::num and period::den just tell you what units HPC is in.

On your system, its units are nanoseconds. The "tick" isn't the unit that the clock increases by, but rather the unit the clock time is measured in.

It does not measure "processor cycles", it measures nanoseconds. Its job is to relatively consistently give you the current time in nanoseconds.

Now, if the CPU is running at one cycle every 256 nanoseconds, then two calls to high_resolution_clock::now() and another won't be less than that apart (as they take more than one cycle!).

C++ does not expose the clock time of your CPU. It isn't all that useful.

If you want to record two time points, use clock::now() for your clock. If you want the best resolution the std library can pull off, use high_performance_clock. If having clock times that are 100% guaranteed to never go backwards, use steady_clock (after checking that its resolution is sufficient).

You can convert these time points into system clock, and from that to go time_t if you want calendar time. (Converting between clocks requires you have a common time point in both in my experience; you should generate this common time point once and reuse it)

If you need more resolution than system clock permits, you can convert time points to system clock, that to time_t, that back to system clock and back to your clock, subtract the difference, and display that difference in a unit like nanoseconds.

Here is a SO answer that does a bunch of this stuff.

What chrono provides mainly is a library to make working with different clock systems easy and type safe. It has durations and time points, each of which carry their units with them so accidentally adding seconds-as-nanoseconds won't happen.