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.
Related
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.
How can one multiply a chrono timepoint by a scalar? It works for durations, but timepoints can't be multiplied by a scalar ("error: invalid operands to binary expression").
Context:
I have some code that in real life will run for a long time. For testing purposes, I want to be able to speed it up by a factor, so everything happens similarly, but just in fast forward.
I thought of making my own ScaledClock class, that returns values from chrono::steady_clock, but with a scaling parameter that can be set to something greater than 1 to achieve a speed up. Here is some code:
steady_clock::time_point ScaledClock::now() {
return steady_clock::now() * speedUp; // <--- error
}
void ScaledClock::sleep_for(steady_clock::duration duration) {
std::this_thread::sleep_for(duration / speedUp);
}
void ScaledClock::sleep_until(steady_clock::time_point time) {
std::this_thread::sleep_until(time / speedUp); // <--- error
}
If the speedUp is 2, for instance, then the program will always think that twice as much time has passed. It will also sleep for half as long. As long as I am disciplined about not using this class for all timing, I think it should work.
(Alternatively, if someone has a much better way of achieving this, I'd love to hear it).
Edit: copy of comment, because I think it is useful clarification:
en.cppreference.com/w/cpp/chrono/time_point:
Class template std::chrono::time_point represents a point in time. It
is implemented as if it stores a value of type Duration indicating the
time interval from the start of the Clock's epoch.
So I want all the times since the epoch doubled. If the epoch is not start of program execution, and my code happens to think that it is running in 4036, I'm not really bothered
You will need to store a starting point (now() e.g. at program start) and then determine the time passed since that starting point as a duration. You can then add this duration multiplied with your factor to the start point and return it as time point in your ScaledClock::now() function. Just like this:
#include <chrono>
#include <unistd.h>
int main() {
auto start = std::chrono::steady_clock::now();
sleep(1);
auto actualNow = std::chrono::steady_clock::now();
auto timePassed = actualNow - start;
auto timePassedScaled = timePassed * 2.0;
auto scaledNow = start + timePassedScaled;
return 0;
}
I'm using OpenCV to write a video file. For cv::VideoWriter to work correctly the call to the write() function has to happen exactly 30 times per second (for a 30fps video).
I found this code which uses the boost library to achieve this. I want to to the same but using std::chrono in my program. This is my implementation:
std::chrono::high_resolution_clock::time_point prev = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point current = prev;
long long difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();
while(recording){
while (difference < 1000000/30){
current = std::chrono::high_resolution_clock::now();
difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();
}
theVideoWriter.write(frameToRecord);
prev = prev + std::chrono::high_resolution_clock::duration(1000000000/30);
difference = std::chrono::duration_cast<std::chrono::microseconds>(current-prev).count();
}
theVideoWriter.release();
I'm not sure if thats the correct way to do this or if there is a more efficient way. Is there anything better than casting the duration to long long difference?
There is a basic tenant to working with chrono, which goes something like:
If you use count(), and/or you have conversion factors in your
chrono code, then you're trying too hard.
This is not your fault. There really is no good chrono tutorial and that is my bad, and I've recently decided I need to do something about that.
In your case, I recommend rewriting your code along the lines of the following:
First create a duration unit which represents the period of your frame rate:
using frame_period = std::chrono::duration<long long, std::ratio<1, 30>>;
Now when you say frame_period{1}, that means exactly 1/30 of a second.
The next thing to note is that chrono comparisons are always exact, as long as you stay in the chrono system. count() is a "trap door" for escaping out of the chrono system. Only escape out when you have no other choice. So...
auto prev = std::chrono::high_resolution_clock::now();
auto current = pref;
// Just get the difference, and don't worry about the units for now
auto difference = current-prev;
while(recording)
{
// Find out if the difference is less than one frame period
// This comparison will do all the conversions for you to get an exact answer
while (difference < frame_period{1})
{
current = std::chrono::high_resolution_clock::now();
// stay in "native units"...
difference = current-prev;
}
theVideoWriter.write(frameToRecord);
// This is a little tricky...
// prev + frame_period{1} creates a time_point with a complicated unit
// Use time_point_cast to convert (via truncation towards zero) back to
// the "native" duration of high_resolution_clock
using hr_duration = std::chrono::high_resolution_clock::duration;
prev = std::chrono::time_point_cast<hr_duration>(prev + frame_period{1});
// stay in "native units"...
difference = current-prev;
}
theVideoWriter.release();
The comments above are overly verbose once you get chrono. There's more comment than code above. But the above just works as you intended, with no need for "escaping out" of the chrono system.
Update
If you would want to initialize difference such that the inner loop won't be executed the first time, you could initialize it to something just over frame_period{1} instead of to 0. To do this, the utilities found here come in handy. Specifically ceil:
// round up
template <class To, class Rep, class Period>
To
ceil(const std::chrono::duration<Rep, Period>& d)
{
To t = std::chrono::duration_cast<To>(d);
if (t < d)
++t;
return t;
}
ceil is a replacement for duration_cast that will round up when the conversion is inexact, as opposed to truncate towards zero. Now you can say:
auto difference = ceil<hr_duration>(frame_period{1});
And you are guaranteed that difference >= frame_period{1}. Furthermore, it is known in practice that the duration of high_resolution_clock is nanoseconds, thus you can deduce (or test) that difference is actually initialized to 33,333,334ns, which is 2/3 of a nanosecond greater than 1/30 of a second, which equals frame_period{1}, which equals 33,333,333+1/3ns.
I have a duration
typedef std::chrono::high_resolution_clock Clock;
Clock::time_point beginTime;
Clock::time_point endTime;
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - beginTime);
And I get duration in std::chrono::milliseconds. But I need duration as float or long long. How to do that?
From the documentation
template<
class Rep,
class Period = std::ratio<1>
> class duration;
Class template std::chrono::duration represents a time interval. It
consists of a count of ticks of type Rep and a tick period, where the
tick period is a compile-time rational constant representing the
number of seconds from one tick to the next.
And:
count returns the count of ticks
So a duration stores a number of ticks of a specified period of time, and count will return that number using the underlying representation type. So if the duration's representation is long long, and the period is std::milli, then .count() will return a long long equal to the number of milliseconds represented by the duration.
In general you should avoid using weak types like float or long long to represent a duration. Instead you should stick with 'rich' types, such as std::chrono::milliseconds or an appropriate specialization of std::chrono::duration. These types aid correct usage and readability, and help prevent mistakes via type checking.
Underspecified / overly general:
– void increase_speed(double);
– Object obj; … obj.draw();
– Rectangle(int,int,int,int);
Better: – void increase_speed(Speed);
– Shape& s; … s.draw();
– Rectangle(Point top_left, Point bottom_right);
– Rectangle(Point top_left, Box_hw b);
— slide 18 from Bjarne's talk
std::chrono is "a consistent subset of a physical quantities library that handles only units of time and only those units of time with exponents equal to 0 and 1."
If you need to work with quantities of time you should take advantage of this library, or one that provides more complete unit systems, such as boost::units.
There are rare occasions where quantities must be degraded to weakly typed values. For example, when one must use an API that requires such types. Otherwise it should be avoided.
As float answer.
std::chrono's duration typedefs are integer. However, duration class can accept float.
See my duration typedefs:
https://github.com/faithandbrave/Shand/blob/master/shand/duration.hpp
...
template <class Rep>
using seconds_t = std::chrono::duration<Rep>;
using seconds_f = seconds_t<float>;
using seconds_d = seconds_t<double>;
using seconds_ld = seconds_t<long double>;
template <class Rep>
using minutes_t = std::chrono::duration<Rep, std::ratio<60>>;
using minutes_f = minutes_t<float>;
using minutes_d = minutes_t<double>;
using minutes_ld = minutes_t<long double>;
...
These durations usage is here:
#include <iostream>
#include <shand/duration.hpp>
int main()
{
std::chrono::seconds int_s(3);
shand::minutes_f float_m = int_s; // without `duration_cast`
std::cout << float_m.count() << std::endl; // 0.05
}
Currently I am using boost::rational<std::uint64> to keep track in my application.
Basically I have a clock that runs over a very long period of time and will be tick by different components of different time resolutions, e.g. 1/50s, 1/30s, 1001/30000s etc... I want to maintain perfect precision, i.e. no floating point. boost::rational works well for this purpose, however I think it would be better design to use std::chrono::duration for this.
My problem though is, how can I use std::chrono::duration here? Since it uses a compile time period I don't quite see how I can use it in my scenario where I need to maintain precision?
If I'm understanding your question, and if you know all of the different time resolutions at compile-time, then the following will do what you want. You can figure out the correct tick period by using common_type on all of your different time resolutions as shown below:
#include <cstdint>
#include <chrono>
struct clock
{
typedef std::uint64_t rep;
typedef std::common_type
<
std::chrono::duration<rep, std::ratio<1, 50>>,
std::chrono::duration<rep, std::ratio<1, 30>>,
std::chrono::duration<rep, std::ratio<1001, 30000>>
>::type duration;
typedef duration::period period;
typedef std::chrono::time_point<clock> time_point;
static const bool is_steady = true;
static time_point now()
{
// just as an example
using namespace std::chrono;
return time_point(duration_cast<duration>(steady_clock::now().time_since_epoch()));
}
};
This will compute at compile-time the largest tick period which will exactly represent each of your specified resolutions. For example with this clock one can exactly represent:
1/50 with 600 ticks.
1/30 with 1000 ticks.
1001/30000 with 1001 ticks.
The code below exercises this clock and uses the "chrono_io" facility described here to print out not only the run-time number of ticks of your clock, but also the compile-time units of your clock-tick:
#include <iostream>
#include <thread>
#include "chrono_io"
int main()
{
auto t0 = clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
auto t1 = clock::now();
std::cout << (t1-t0) << '\n';
}
For me this prints out:
633 [1/30000]seconds
Meaning: There were 633 clock ticks between calls to now() and the unit of each tick is 1/30000 of a second. If you don't want to be beholden to "chrono_io" you can inspect the units of your clock with clock::period::num and clock::period::den.
If your different time resolutions are not compile-time information, then your current solution with boost::rational is probably best.
You're allowed to set the period to 1 and use a floating point type for Rep.
I suspect that you can do the same thing with boost::rational, but you'll have to look quite closely at std::chrono, which I haven't done. Look at treat_as_floating_point and duration_values. Also try to figure out what the standard means by "An arithmetic type or a class emulating an arithmetic type".
One might reasonably argue that if boost::rational doesn't emulate an arithmetic type, then it's not doing its job. But it doesn't necessarily follow that it really does everything std::chrono::duration expects.