chrono::count

143 views
Skip to first unread message

Bjorn Reese

unread,
Mar 14, 2017, 4:42:55 PM3/14/17
to std-pr...@isocpp.org
I want to gauge if there is interest in the following.

The value returned by chrono::duration<Rep,Period>::count() is the
tick count in units of Period. If we want this count in another unit,
we must use chrono::duration_cast.

We could add a convenience function to return the tick count in another
unit directly. For example:

chrono::seconds s{2};
auto ms = chrono::count<chrono::milliseconds>(s);
assert(ms == 2000);

Another overload can be added for chrono::time_point

auto now = chrono::steady_clock::now();
auto ms = chrono::count<chrono::milliseconds>(now);

Example implementations are:

template <typename ToDuration, typename Rep, typename Period>
typename ToDuration::rep count(const chrono::duration<Rep, Period>& d)
{
return chrono::duration_cast<ToDuration, Rep, Period>(d).count();
}

template <typename ToDuration, typename Clock, typename Duration>
typename ToDuration::rep count(const chrono::time_point<Clock,
Duration>& t)
{
return chrono::duration_cast<T, typename Duration::rep, typename
Duration::period>(t.time_since_epoch()).count();
}

Howard Hinnant

unread,
Mar 14, 2017, 5:02:11 PM3/14/17
to std-pr...@isocpp.org
Personally I’d vote against it. I regularly help people who are learning <chrono> and one of the most common mistakes I see is overuse of the .count() (and .time_since_epoch()) function. These should be considered “escape hatches” out of the type-safe chrono library, mainly for use in interfacing with code not aware of chrono. The .count() is nothing but a cast from a time duration to an arithmetic type.

Something that encourages this cast, or adds more complication under the hood, is something I don’t think we want to do. Instead we want to encourage C++ programmers to stay _in_ the type-safe chrono system. If programmers do so, they are more likely to have their time-related logic errors be caught at compile time by the type system.

chrono::seconds s{2};
chrono::milliseconds ms = s;
assert(ms == 2000ms);
assert(ms == 2s);

Howard

signature.asc

Bjorn Reese

unread,
Mar 14, 2017, 5:34:49 PM3/14/17
to std-pr...@isocpp.org
On 03/14/2017 10:02 PM, Howard Hinnant wrote:

> Personally I’d vote against it. I regularly help people who are learning <chrono> and one of the most common mistakes I see is overuse of the .count() (and .time_since_epoch()) function. These should be considered “escape hatches” out of the type-safe chrono library, mainly for use in interfacing with code not aware of chrono. The .count() is nothing but a cast from a time duration to an arithmetic type.

While I tend to agree with the "escape hatch" comment, we do
unfortunately have to use this escape hatch quite often, not out of
joy, but out of necessity.

One use-case is to get the current time and then manipulate it -- e.g.
with drift calculations -- before turning it back into a time_point.

Another use-case is to use durations as input to statistical methods
that have no knowledge of chrono. Some of these calculations will later
result in a duration (e.g. the mean of all durations.)

We use the count() function that I suggested, and it removed a whole
category of errors. I would like to urge you to reconsider your
position.

Howard Hinnant

unread,
Mar 14, 2017, 5:55:55 PM3/14/17
to std-pr...@isocpp.org
I will definitely reconsider my position. I would like to hear more about the errors you encountered. I also find myself wondering why this simpler syntax did not suffice:

chrono::seconds s{2};
auto ms = chrono::milliseconds{s}.count();
assert(ms == 2000);

Was it the need to convert to coarser units prior to the cast? Overuse of duration_cast (when an implicit conversion would do) is another common mistake I see. Overuse of duration_cast leads to the hiding of those conversions that have truncation errors under the hood. In case you have to track down an error that you suspect is caused by truncation, it is easier if those conversions that didn’t require duration_cast didn’t use it.

Howard

signature.asc

Avi Kivity

unread,
Mar 15, 2017, 5:28:14 AM3/15/17
to std-pr...@isocpp.org


On 03/14/2017 10:52 PM, Bjorn Reese wrote:
> I want to gauge if there is interest in the following.
>
> The value returned by chrono::duration<Rep,Period>::count() is the
> tick count in units of Period. If we want this count in another unit,
> we must use chrono::duration_cast.
>
> We could add a convenience function to return the tick count in another
> unit directly. For example:
>
> chrono::seconds s{2};
> auto ms = chrono::count<chrono::milliseconds>(s);

You can write


auto ms = s / 1ms;

> assert(ms == 2000);
>
> Another overload can be added for chrono::time_point
>
> auto now = chrono::steady_clock::now();
> auto ms = chrono::count<chrono::milliseconds>(now);

auto ms = now.time_since_epoch() / 1ms;

Bjorn Reese

unread,
Mar 18, 2017, 7:40:12 AM3/18/17
to std-pr...@isocpp.org
On 03/14/2017 10:55 PM, Howard Hinnant wrote:

> I will definitely reconsider my position. I would like to hear more about the errors you encountered.

Most errors occurred in calculations that used both duration and
floating-point numbers. These calculations used <cmath> so they were
done with double. Sometimes they needed to use a constant (e.g.
a threshold value) that was specified as a duration. We used .count()
on those constants. If one of these constants was declared as, say,
chrono::milliseconds, and somebody later changed it to chrono::seconds
the calculations would be off by a factor of 1000.

> I also find myself wondering why this simpler syntax did not suffice:
>
> chrono::seconds s{2};
> auto ms = chrono::milliseconds{s}.count();

That will solve the duration case. It is less attractive for the
time_point case, but I realize that this is insufficient motivation for
a proposal.

> Was it the need to convert to coarser units prior to the cast? Overuse of duration_cast (when an implicit conversion would do) is another common mistake I see. Overuse of duration_cast leads to the hiding of those conversions that have truncation errors under the hood. In case you have to track down an error that you suspect is caused by truncation, it is easier if those conversions that didn’t require duration_cast didn’t use it.

I suggested duration_cast because I thought that was the way to convert
between duration types.

Howard Hinnant

unread,
Mar 18, 2017, 11:32:31 AM3/18/17
to std-pr...@isocpp.org
Lack of good tutorial material on <chrono> has been a problem. Here is my attempt to help in that department:

https://www.youtube.com/watch?v=P32hvk8b13M

Howard

signature.asc
Reply all
Reply to author
Forward
0 new messages