Can I replace SDL_GetTicks with std::chrono::high_resolution_clock? - c++

Checking new stuff from C++, I have found the std::chrono library.
I am wondering if std::chrono::high_resolution_clock could be a good replacement for SDL_GetTicks?

The advantage of going with std::chrono::high_resolution_clock is to keep away from storing time points and time durations in a Uint32. The std::chrono library comes with a wide variety of std::chrono::durations that you should use instead. This will make code more readable, and less ambiguous:
Uint32 t0 = SDL_GetTicks();
// ...
Uint32 t1 = SDL_GetTicks();
// ...
// Is t1 a time point or time duration?
Uint32 d = t1 -t0;
// What units does d have?
vs:
using namespace std::chrono;
typedef high_resolution_clock Clock;
Clock::time_point t0 = Clock::now();
// ...
Clock::time_point t1 = Clock::now();
// ...
// Is t1 has type time_point. It can't be mistaken for a time duration.
milliseconds d = t1 - t0;
// d has type milliseconds
The typed system for holding points in time and time durations has no overhead with respect to just storing things in a Uint32. Except maybe that things will be stored in an Int64 instead. But even that you could customize if you really wanted to:
typedef duration<Uint32, milli> my_millisecond;
You can inspect the precision of the high_resolution_clock with:
cout << high_resolution_clock::period::num << '/'
<< high_resolution_clock::period::den << '\n';

SDL_GetTicks returns milliseconds so it is totally possible to use std::chrono instead, but mind the units conversion necessary. It may not be as simple as SDL_GetTicks. Also, the starting point won't be the same.

Related

Time-stamping using std::chrono - How to 'filter' data based on relative time?

I want to time-tag a stream of data I produce, for which I want to use std::chrono::steady_clock.
These time-stamps are stored with the data ( as array of uint64 values?), and I will later need to process these time-stamps again.
Now, I haven't been using the std::chrono library at all so far, so I do need a bit of help on the syntax and best practices with this library.
I can get & store values using:
uint64_t timestamp = std::chrono::steady_clock::now().time_since_epoch().count();
but how do I best:
On reading the data create a timepoint from the uint64 ?
Get the ticks-per-second (uint64) value for the steady_clock?
Find a "cut-off" timepoint (as uint64) that lies a certain time (in seconds) prior a given timepoint?
Code snippets for the above would be appreciated.
I want to combine the three above essentially to do the following: Having an array of (increasing) time-stamp values (as uint64), I want to truncate it such that all data 'older' than last-time-stamp minus X seconds is thrown away.
Let's have a look at the features you might use in the cppreference documentation for chrono.
First off, you need to decide which clock you want to use. There is the steady_clock which you suggested, the high_resolution_clock and the system_clock.
high_resolution_clock is implementation dependent, so let's put this away unless we really need it. The steady_clock is guaranteed to be monotonic, but there is no guarantee of the meaning for the value you are getting. It's ideal for sorting events or measuring their intervals, but you can't get a timepoint out of it.
On the other hand, system_clock has a meaning, it's the UNIX epoch, so you can get a time value out of it, but is not guaranteed to be monotonic.
To get the period (duration of one tick) of a steady_clock, you have the period member:
auto period = std::chrono::steady_clock::period();
std::cout << "Clock period " << period.num << " / " << period.den << " seconds" << std::endl;
std::cout << "Clock period " << static_cast<double>(period.num) / period.den << " seconds" << std::endl;
Assuming you want to filter events that happened in the last few seconds using steady_clock values, you first need to compute the number of ticks in the time period you want and subtract it from now. Something along the lines of:
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t t_c = std::chrono::system_clock::to_time_t(now - std::chrono::seconds(10));
And use t_c as cutoff point.
However, do not rely on std::chrono::steady_clock::now().time_since_epoch().count(); to get something meaningful - is just a number. The epoch for the steady_clock is usually the boot time. If you need a time, you should use system_clock (keeping in mind that is not monotonous).
C++20a introduces some more clocks, which are convertible to time.
As it took me far too long to figure it out from various sources today, I'm going to post my solution here as self-answer. ( I would appreciate comments on it, in case something is not correct or could be done better.)
Getting a clock's period in seconds and ticks-per-second value
using namespace std::chrono;
auto period = system_clock::period();
double period_s = (double) period.num / period.den;
uint64 tps = period.den / period.num;
Getting a clock's timepoint (now) as uint64 value for time-stamping a data stream
using namespace std::chrono;
system_clock::time_point tp_now = system_clock::now();
uint64 nowAsTicks = tp_now.time_since_epoch().count();
Getting a clock's timepoint given a stored uint64 value
using namespace std::chrono;
uint64 givenTicks = 12345; // Whatever the value was
system_clock::time_point tp_recreated = system_clock::time_point{} + system_clock::duration(givenTicks);
uint64 recreatedTicks = tp_now.time_since_epoch().count();
Assert( givenTicks == recreatedTicks ); // has to be true now
The last ( uint64 to timepoint ) was troubling me the most. The key-insights needed were:
(On Win10) The system_clock uses a time-resolution of 100 nanoseconds. Therefore one can not directly add std::chrono::nanoseconds to its native time points. (std::chrono:system_clock_time_point)
However, because the ticks are 100's of nanoseconds, one can also not use the next higher duration unit (microseconds) as it cannot be represent as an integer value.
One could use use an explicit cast to microseconds, but that would loose the 0.1us resolution of the the tick.
The proper way is to use the system_clock's own duration and directly initialize it with the stored tick value.
In my search I found the following resources most helpful:
Lecture of Howard Hinnant on YouTube - extremely helpful. I wish I would have started here.
cppreference.com on time_point and duration and time_since_epoch
cplusplus.com on steady clock and time_point
A nice place to look as usual is the reference manual :
https://en.cppreference.com/w/cpp/chrono
In this case you are looking for :
https://en.cppreference.com/w/cpp/chrono/clock_time_conversion
Since really you are using a clock with "epoch" 1/1/70 as origin and ms as unit.
Then just use arithmetic on durations to do the cutoff things you want :
https://en.cppreference.com/w/cpp/chrono/duration
There are code examples at bottom of each linked page.

What is the std::chrono::time_point equivalent of std::numeric_limits::infinity()?

Suppose I want to call my_func() periodically at CALL_PERIOD intervals
auto last_call_time = CHRONO_NEGATIVE_INFINITY;
while (true)
{
if (std::chrono::system_clock::now() - last_call_time > CALL_PERIOD)
{
last_call_time = std::chrono::system_clock::now();
my_func();
}
}
What would be an appropriate CHRONO_NEGATIVE_INFINITY such that the line
std::chrono::system_clock::now() - last_call_time > CALL_PERIOD
will always evaluate true on the first run?
I've tried time_point::min() but that doesn't seem to work
One of the main reasons to have a type like std::optional is so that we don't have to have hacks like picking a specific value to mean "not a value":
std::optional<std::chrono::system_clock::time_point> last_call_time;
while (true)
{
auto curr = std::chrono::system_clock::now()
if (!last_call_time || (curr - *last_call_time) > CALL_PERIOD)
{
last_call_time = std::chrono::system_clock::now();
my_func();
}
}
If C++17 is not available to you, and/or you're just dead-set on using the old hack of picking a special value, you can get the clock's rep type and compute the minimum possible integer of it:
using sys_clock = std::chrono::system_clock;
constexpr auto min_int = std::numeric_limits<sys_clock::rep>::min();
constexpr sys_clock::duration min_duration(min_int);
sys_clock::time_point min_time(min_duration);
Of course, min_time is still a valid time, so it's unlike any "infinity" representation for floats.
The rationale that there is no time_point::infinity equivalent is that time_points are simple wrappers around arithmetic types. Simplistic wrappers lead to the highest performing code. And this same rationale is also a clue that for special cases, time_point::infinity actually does exist!
Let me elaborate further on that entirely confusing first paragraph...
system_clock::time_point is a simple wrapper around a duration. Exactly which duration is unspecified, but let's just say it is nanoseconds. And nanoseconds is a simple wrapper around a 64 bit signed integer (say long long).
long long has no representation of +/- INFINITY. But it does have a minimum value: -9223372036854775808.
A shortcut for putting this value into a duration (say nanoseconds) is nanoseconds::min(), and a shortcut to putting this value into system_clock::time_point is system_clock::time_point::min().
However when you do so, it is an invitation for plain old signed integral overflow. After all:
cout << (10 - numeric_limits<long long>::min() > 1) << '\n';
overflows and prints out 0 (false). And that's precisely why:
auto CHRONO_NEGATIVE_INFINITY = system_clock::time_point::min();
didn't work.
There are several ways to get your code to work. Which is best for your application is up to you. But now that <chrono> is just a little less mysterious, you can better make that decision.
Perhaps the easiest way is to set CHRONO_NEGATIVE_INFINITY to something that isn't quite so negative so that you don't risk overflow:
auto CHRONO_NEGATIVE_INFINITY = std::chrono::system_clock::now() - CALL_PERIOD;
C++20 standardizes the existing practice that system_clock's epoch is 1970-01-01, so here's another possibility (that works back to C++11):
// Set CHRONO_NEGATIVE_INFINITY to 1970-01-01 00:00:00 UTC
auto CHRONO_NEGATIVE_INFINITY = std::chrono::system_clock::time_point{};
But let's say that for some reason you really, really need a time_point that is infinitely in the past. You can do that too, it just takes a little more work. float and double are arithmetic types too, and they do have a representation of INFINITY! So you can just build a time_point out of one of those types.
using dsec = std::chrono::duration<double>;
using tp_dsec = std::chrono::time_point<std::chrono::system_clock, dsec>;
auto CHRONO_NEGATIVE_INFINITY = tp_dsec{dsec{-INFINITY}};
The first line makes dsec a name for double-based-seconds. The second line makes tp_dsec a name for a system_clock-based time_point using dsec as its representation. And then the third line just stuffs negative infinity into a tp_dsec. The rest of your code will implicitly convert to double-based time_points and durations when doing the test.
If you rewrite your test like this:
auto last_call_time = std::chrono::system_clock::min();
...
if (std::chrono::system_clock::now() - CALL_PERIOD > last_call_time)
you shouldn't overflow.
Use 0:
std::chrono::duration CALL_PERIOD(std::chrono::seconds(2));
std::chrono::steady_clock::time_point last_call_time; //auto init to 0,
// or can use explicit initialization to 0:
// std::chrono::steady_clock::time_point last_call_time(std::chrono::seconds(0));
while (true)
{
auto now = std::chrono::steady_clock::now();
if (now - last_call_time > CALL_PERIOD)
{
last_call_time = now;
my_func();
}
}

How To Return Elapsed Time From steady_clock as a Primitive Data Type (double)

First and foremost, let me say that I just starting using this library yesterday, so my understanding of it is still fairly basic. I'm trying to capture the FPS of a vision processing program I'm creating and output it to a screen using the chrono library. In my case, I need to cast the elapsed time taken after I start a steady_clock to a double (or some other numerical typedef I could treat like a double). I looked through reference documentation and tried working with the duration_cast and time_point_cast functions, but neither of those seem to be what I'm looking for.
My question is; is there any way to simply cast the numerical value of a clock's current state in seconds to a primitive data type?
Any help would be appreciated.
Like this:
#include <chrono>
#include <iostream>
#include <thread>
int main()
{
using namespace std::literals;
// measure time now
auto start = std::chrono::system_clock::now();
// wait some time
std::this_thread::sleep_for(1s);
// measure time again
auto end = std::chrono::system_clock::now();
// define a double-precision representation of seconds
using fsecs = std::chrono::duration<double, std::chrono::seconds::period>;
// convert from clock's duration type
auto as_fseconds = std::chrono::duration_cast<fsecs>(end - start);
// display as decimal seconds
std::cout << "duration was " << as_fseconds.count() << "s\n";
}
example output:
duration was 1.00006s
You could do it using the duration::count function.
For example you could get the duration in the number of milliseconds, and then divide the count by 1000.0 to get the number of seconds as a double.

How can I get a high resolution time stamp as a double?

I am trying to use the follow code:
std::chrono::high_resolution_clock::now();
to get a time stamp, but I need it as a double, but it isn't a support data type, auto works, but I cannot manipulate it.
Your "time stamp" is what the <chrono> library calls a time_point. A time_point is a collection of a clock, and duration. And a duration is a collection of a representation and period.
You have specified two out of these three:
clock == high_resolution_clock
representation == double
period == ?
Your period can be nano (ratio<1, 1000000000>), milli (ratio<1, 1000>), seconds (ratio<1>), minutes (ratio<60>) or any other rational relationship to seconds.
Let's say for example that you wanted a time stamp using double as the representation and seconds as the period. This would look like this:
using clock = std::chrono::high_resolution_clock;
using dsec = std::chrono::duration<double>;
using tps = std::chrono::time_point<clock, dsec>;
tps tp = clock::now();
The time_point emitted by high_resolution_clock::now() will implicitly convert to your time_point using a representation of double and a period of ratio<1>. It will hold fractional seconds since the epoch of high_resolution_clock.
In general, because your destination type has a floating point representation, all time_point source types will implicitly convert to it. To convert in the reverse direction, you would need to use std::chrono::time_point_cast<some-duration>(source-time_point).
If instead you wanted to hold double-based nanoseconds, that would look like:
using clock = std::chrono::high_resolution_clock;
using dns = std::chrono::duration<double, std::nano>;
using tpns = std::chrono::time_point<clock, dns>;
tpns tp = clock::now();
As a guideline, I recommend using either system_clock or steady_clock, but not high_resolution_clock. Use system_clock if your time_point needs to have some relationship with the civil calendar, or needs to maintain meaning across processes. Use steady_clock if your time_point is used only across short durations within the same process.
high_resolution_clock is (de-facto) always an alias to either system_clock or steady_clock. So you might as well use one of the latter, and know what you're getting.
using clock = std::chrono::system_clock;
using dsec = std::chrono::duration<double>;
using tps = std::chrono::time_point<clock, dsec>;
tps tp = clock::now();
std::chrono::high_resolution_clock::now() returns an std::time_point<std::chrono::high_resolution_clock>. Here, you can choose whether you want to express this time point in nanoseconds, microseconds, milliseconds, and so on, using a std::chrono::duration, and ultimately convert this to a double:
std::chrono::time_point<std::chrono::high_resolution_clock> tp = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::micro> dur = tp;
double micros = dur.count();
Here you can replace std::micro with whatever resolution you desire.

Estimating time left in C++11

I'm writing a progress bar class that outputs an updated progress bar every n ticks to an std::ostream:
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), ticks_occured(0),
_begin(std::chrono::steady_clock::now())
...
void tick()
{
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
...
}
}
private:
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
std::chrono::steady_clock::time_point _begin;
...
}
I would like to also output the time remaining. I found a formula on another question that states time remaining is (variable names changed to fit my class):
time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
The parts I would like to fill in for my class are the time_left and the time_taken, using C++11's new <chrono> header.
I know I need to use a std::chrono::steady_clock, but I'm not sure how to integrate it into code. I assume the best way to measure the time would be a std::uint64_t as nanoseconds.
My questions are:
Is there a function in <chrono> that will convert the nanoseconds into an std::string, say something like "3m12s"?
Should I use the std::chrono::steady_clock::now() each time I update my progress bar, and subtract that from _begin to determine time_left?
Is there a better algorithm to determine time_left
Is there a function in that will convert the nanoseconds into
an std::string, say something like "3m12s"?
No. But I'll show you how you can easily do this below.
Should I use the std::chrono::steady_clock::now() each time I update
my progress bar, and subtract that from _begin to determine time_left?
Yes.
Is there a better algorithm to determine time_left
Yes. See below.
Edit
I had originally misinterpreted "ticks" as "clock ticks", when in actuality "ticks" has units of work and _ticks_occurred/_total_ticks can be interpreted as %job_done. So I've changed the proposed progress_bar below accordingly.
I believe the equation:
time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
is incorrect. It doesn't pass a sanity check: If _ticks_occured == 1 and _total_ticks is large, then time_left approximately equals (ok, slightly less) time_taken. That doesn't make sense.
I am rewriting the above equation to be:
time_left = time_taken * (1/percent_done - 1)
where
percent_done = _ticks_occurred/_total_ticks
Now as percent_done approaches zero, time_left approaches infinity, and when percent_done approaches 1, 'time_left approaches 0. When percent_done is 10%, time_left is 9*time_taken. This meets my expectations, assuming a roughly linear time cost per work-tick.
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), _ticks_occurred(0),
_begin(std::chrono::steady_clock::now())
// ...
{}
void tick()
{
using namespace std::chrono;
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
// somehow _ticks_occurred is updated here and is not zero
duration time_taken = Clock::now() - _begin;
float percent_done = (float)_ticks_occurred/_total_ticks;
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
minutes minutes_left = duration_cast<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::duration duration;
typedef Clock::rep rep;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
Traffic in std::chrono::durations whenever you can. That way <chrono> does all the conversions for you. typedefs can ease the typing with the long names. And breaking down the time into minutes and seconds is as easy as shown above.
As bames53 notes in his answer, if you want to use my <chrono_io> facility, that's cool too. Your needs may be simple enough that you don't want to. It is a judgement call. bames53's answer is a good answer. I thought these extra details might be helpful too.
Edit
I accidentally left a bug in the code above. And instead of just patch the code above, I thought it would be a good idea to point out the bug and show how to use <chrono> to fix it.
The bug is here:
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
and here:
typedef Clock::duration duration;
In practice steady_clock::duration is usually based on an integral type. <chrono> calls this the rep (short for representation). And when percent_done is greater than 50%, the factor being multiplied by time_taken is going to be less than 1. And when rep is integral, that gets cast to 0. So this progress_bar only behaves well during the first 50% and predicts 0 time left during the last 50%.
The key to fixing this is to traffic in durations that are based on floating point instead of integers. And <chrono> makes this very easy to do.
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
duration now has the same tick period as steady_clock::duration but uses a float for the representation. And now the computation for time_left can leave off the static_cast:
duration time_left = time_taken * (1/percent_done - 1);
Here's the whole package again with these fixes:
class progress_bar
{
public:
progress_bar(uint64_t ticks)
: _total_ticks(ticks), _ticks_occurred(0),
_begin(std::chrono::steady_clock::now())
// ...
{}
void tick()
{
using namespace std::chrono;
// test to see if enough progress has elapsed
// to warrant updating the progress bar
// that way we aren't wasting resources printing
// something that hasn't changed
if (/* should we update */)
{
// somehow _ticks_occurred is updated here and is not zero
duration time_taken = Clock::now() - _begin;
float percent_done = (float)_ticks_occurred/_total_ticks;
duration time_left = time_taken * (1/percent_done - 1);
minutes minutes_left = duration_cast<minutes>(time_left);
seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n";
}
}
private:
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
std::uint64_t _total_ticks;
std::uint64_t _ticks_occurred;
time_point _begin;
//...
};
Nothing like a little testing... ;-)
The chrono library includes types for representing durations. You shouldn't convert that to a flat integer of some 'known' unit. When you want a known unit just use the chrono types, e.g. 'std::chrono::nanoseconds', and duration_cast. Or create your own duration type using a floating point representation and one of the SI ratios. E.g. std::chrono::duration<double,std::nano>. Without duration_cast or a floating point duration rounding is prohibited at compile time.
The IO facilities for chrono didn't make it into C++11, but you can get source from here. Using this you can just ignore the duration type, and it will print the right units. I don't think there's anything there to that will show the time in minutes, seconds, etc., but such a thing shouldn't be too hard to write.
I don't know that there's too much reason to be concerned about calling steady_clock::now() frequently, if that's what your asking. I'd expect most platforms to have a pretty fast timer for just that sort of thing. It does depend on the implementation though. Obviously it's causing an issue for you, so maybe you could only call steady_clock::now() inside the if (/* should we update */) block, which should put a reasonable limit on the call frequency.
Obviously there are other ways to estimate the time remaining. For example instead of taking the average over the progress so far (which is what the formula you show does), you could take the average from the last N ticks. Or do both and take a weighted average of the two estimates.