4

I have looked into several topics to try to get some ideas on how to make a reliable clock with C or C++. However, I also saw some functions used the processor's ticks and ticks per second to calculate the end result, which I think could be a problem on a CPU with auto-overclock like the one I have. I also saw one of them reset after a while, thus is not really reliable.

The idea is to make a (preferably cross-platform) clock like an in-game one, with a precision better than a second in order to be able to add the elapsed time in the "current session" with the saved time at the end of the program. This would be to count the time spent on a console game that does not have an in-game clock, and on the long run to perhaps integrate it to actual PC games.

It should be able to run without taking too much or all of the CPU's time (or a single core's time for multi-core CPUs) as it would be quite bad to use all these resources just for the clock, and also on systems with auto-overclock (which could otherwise cause inaccurate results).

The program I would like to implement this feature into currently looks like this, but I might re-code it in C (since I have to get back to learning how to code in C++):

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
    cout << "In game" << endl;
    system("PAUSE");
    return 0;
}

On a side-note, I still need to get rid of the PAUSE feature which is Windows-specific, but I think that can be taken care of with a simple "while (char != '\n')" loop.

What I have already skimmed through:

(Edit: Extra research, in particular for a C implementation:

The problem is that it is not clear whether some of the mentioned methods, like Boost or SDL2, behave properly with auto-overclock in particular.

TL;DR : What cross-platform function should I use to make an accurate, sub-second precise counter in C/C++ that could work on multi-core and/or auto-overclocking processors please?

Thanks in advance.

Coroice
  • 51
  • 6
  • 2
    Sounds to me like you want [std::chrono::steady_clock](http://en.cppreference.com/w/cpp/chrono/steady_clock). – Jesper Juhl Dec 26 '17 at 15:21
  • 4
    upvote for all the research – Jean-François Fabre Dec 26 '17 at 15:26
  • Sounds like it could be what I'm looking for indeed... If I understood the documentation properly, you can set a specific period that's independent from the CPU's ticks, is that correct? If it's the case, then it might just be perfect. – Coroice Dec 26 '17 at 15:28
  • 2
    `std::chrono::steady_clock` does not get set to anything. At any given point, it tells you what the value of the clock is. It's up to you to measure the clock at the beginning and at the end of the interval, and compute the elapsed time accordingly. – Sam Varshavchik Dec 26 '17 at 15:30
  • Oh, ok then. Thanks for the clarification! But does it risk being affected by the CPU's frequency or not? This is what I'm worrying about, since I think it could lead to pretty big differences between the wall clock time and the time counted by the clock over more or less long periods (an hour for instance). – Coroice Dec 26 '17 at 15:41
  • 1
    @Coroice `std::chrono::steady_clock` is a monotonically increasing clock that is not affected by outside factors like CPU speed or the user adjusting date/time settings or similar - yes. – Jesper Juhl Dec 26 '17 at 16:47
  • This is still a **C++** question with the accepted answer. I have zero idea on how to apply any of this knowledge in my C programs. – Antti Haapala -- Слава Україні Dec 26 '17 at 17:03
  • Thanks again for the clarification! And I agree it would also be interesting to have the equivalent for a C program, even though I already have the answer for a C++ one. Is `clock_gettime()` reliable enough (and portable)? – Coroice Dec 26 '17 at 22:20
  • `omp_get_wtime()` is what I normally use. – Z boson Dec 27 '17 at 09:19
  • `omp_get_wtime()` seems to depend on the wall clock and to have a resolution of a second; it's good enough in some cases, but not really what I was looking for. Plus it sounds like it could measure the effective execution time, rather than having a duration between two points in time (at the beginning and end of the program respectively). `omp_get_wtick()` might be better for sub-second precision, but again, is it compatible with auto-overclock? – Coroice Dec 27 '17 at 11:18
  • Can't edit the previous post so I have to write a new comment: `omp_get_wtick()` seems to also have a resolution of a second, so it's not good for all cases... – Coroice Dec 27 '17 at 11:27
  • `omp_get_wtime()` has a resolution better than a micro second. I don't know where you got the idea that it has a resolution of second. Actually, it's just calls other functions. With GCC it calls `clock_gettime`. It's implementation defined but it has been precise for me. It's the most convenient cross platform and cross compiler (GCC, Claing, ICC, MSVC) method of I know to get the wall time. I would not use it for a big project but for small things (especially on SO ) it works great. I did have one problem with it once though https://stackoverflow.com/a/43277581/2542702 – Z boson Dec 28 '17 at 08:56
  • Sorry for the late reply... It's my bad, I misunderstood the documentation, as it says "Returns a value in seconds of the time elapsed from some point", but it's actually a float with a better precision. And `clock_gettime` seems to work monotonically as well, so auto-OC shouldn't cause issues... Thanks a lot for the clarification, I'll keep this function in mind for C projects! – Coroice Jan 05 '18 at 14:02

1 Answers1

2

The std::chrono::high_resolution_clock seems to be what you are looking for. On most modern CPUs it is going to be steady monotonically increased clock which would not be affected by overclocking of the CPU.

Just keep in mind that it can't be used to tell time. It is only good for telling the time intervals, which is a great difference. For example:

using clock = std::chrono::high_resolution_clock;
auto start = clock::now();
perform_operation();
auto end = clock::now();
auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
std::cout << "Operation took " << us << " microseconds.\n";

If the clock checking itself is a performance-sensitive operation, you will have to resort to platform-specific tricks, of which the most popular is reading CPU tick counter directly (RDTSC in Intel family). This is very fast, and on modern CPUs very accurate way of measuring time intervals.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • It looks like both the high-resolution clock and steady clock from the chrono library could be what I need; the only "problem" after that might be the conversion from seconds to minutes and hours. Thank you very much! – Coroice Dec 26 '17 at 15:47
  • 2
    The problem with `std::chrono::high_resolution_clock` vs `std::chrono::steady_clock` is that the former is not guaranteed to never go backwards in time. The way *I* read OPs question, they want a steadily increasing clock that's not affected by the user adjusting the current date/time or CPUs changing frequency etc etc. `steady_clock` is just that , but `high_resolution_clock` is not (guaranteed to be). – Jesper Juhl Dec 26 '17 at 16:21
  • 1
    @Coroice the conversion between units of time is simple. See http://en.cppreference.com/w/cpp/chrono/duration/duration_cast – Richard Hodges Dec 26 '17 at 16:39
  • @JesperJuhl like I said, on most modern platforms the high resolution clock is monotonically increased (and is in fact synonymous with steady_clock). – SergeyA Dec 26 '17 at 18:47
  • @SergeyA sure, but that is not guaranteed. If you want a *guaranteed* monotonically increasing clock, then `std::steady_clock` is what you want. – Jesper Juhl Dec 26 '17 at 18:54
  • 2
    gcc aliases `high_resolution_clock` to `system_clock`. Everyone else (libc++ / VS) aliases it to `steady_clock`. I recommend choosing either `system_clock` or `steady_clock` in order to make code more portable. `system_clock` is good if you need to relate a time to a human calendar (i.e. a wall clock). `steady_clock` is good if you need only durations between two time points and/or a guarantee that time advances monotonically (i.e. a stopwatch). – Howard Hinnant Dec 26 '17 at 18:54
  • It looks like I might not need the extra precision of `std::chrono::high_resolution_clock`, plus it *might* have side-effects (even though likely negligible, but still), so I think I am going to stick with `steady_clock`. The assisted conversion is nice to have, though. Thanks for the extra info! – Coroice Dec 26 '17 at 22:12