Time to time
[edited March 2020]
The C++11 standard defines a multi-platform framework to handle time information which can be used to represent full time with date or time differences suitable for timing code execution.
This means no more messing around with clock_gettime(), gettimeofday(), _QueryPerformanceCounter() or GetSystemTime().
This article does cover the use of C++11 features for computing elapsed time in different scenarios, for complete information on the subject do have a look at the standard specification document (ISO/IEC 14882:2011), chapter 20, sections 10 and 11.
After introducing some basic concepts the various types are analyzed bottom up starting with the basic types and ending with the clock type.
The source code referenced at the end of the post has sample code showing the usage of each of the types described below.
Basic Concepts
The time framework is defined in the <chrono>
include file.
Three clock types are provided:
- system: wall clock time, matches the system time
- steady: guarantees that the returned time value never decreases as physical time increases
- high_resolution: uses the shortest possible tick period, on most systems all clocks use a tick of one nanosecond anyway
A point in time is recorded into a time_point
instance.
A time span is stored into a duration
instance.
A difference between two time_point
s returns a duration instance.
A duration represents a number of ticks or periods.
The period represents the length of a tick in seconds and it is encoded with a rational constant.
The rational (numerator over denominator) constants used to describe a tick period in seconds are represented with the ratio type.
Facilities exist to compare and cast durations and time points as well as to convert to standard C types and print time information.
The steady clock is the preferred choice for timing code execution.
All the needed types and functions other than ratio are declared
inside the std::chrono
namespace.
ratio
is declared inside the std
namespace.
Rational constants
Rational constants i.e. $\frac{Numerator}{Denominator}$ are used hroughout the chrono framework to specify fractions of seconds. Also a number of predefined constants is available to specify commonly used units such as milli or micro.
Rational constants are declared as ratio
type instances.
template < intmax_t N, intmax_t D = 1 >
class ratio {
public:
typedef ratio< num, den > type;
static constexpr intmax_t num;
static constexpr intmax_t den;
};
The intmax_t
type is the integer type that able to represent the biggest
possible signed integer.
Numerator and denominator values are defined at compile time as integer numbers.
Arithmetic operations and comparisons can be executed at compile time through the ratio*_ functions and types.
Duration
The duration type represents a difference between points in time defined as a number of periods (ticks).
From the standard:
A duration type measures time between two points in time (time_points). A duration has a representation which holds a count of ticks and a tick period. The tick period is the amount of time which occurs from one tick to the next, in units of seconds. It is expressed as a rational constant using the template ratio.
The number of ticks is the representation type which can be an integer or a floating point number.
A period is an interval in seconds specified as a rational constant.
The following code defines a duration of ten milliseconds and prints out the number of periods in the duration.
//1/1000
using Milli = ratio<INTMAX_C(1), INTMAX_C(1000)>;
using Milliseconds = duration<intmax_t, Milli>;
//declare a duration of 10 periods where each period is equal
//to 1/1000 seconds i.e. ten milliseconds
Milliseconds ms(10);
//print the number of periods (ticks) in the duration instance
cout << ms.count() << endl;
The intmax_t
type is the integer type that can represent the biggest
possible signed integer.
INTMAX_C
is a macro that converts the integer constant into an
intmax_t
instance.
It is possible to use floating point values as the type that represents the number of tick counts as well.
You convert between durations with different representations and
period types by means of the duration_cast
function.
A duration can be converted to a duration with a different tick period only if the number of ticks is represented as a floating point number.
To detect if a tick count representation is a floating point type you
use the treat_as_floating_point
type trait:
using FloatNano = duration< double, nanoseconds >;
//check if floating point
static_assert(
treat_as_floating_point< FloatNano::rep >::value,
"Duration representation must be a floating point type&amp");
//if we get here it means the duration tick count type is
//a floating point type
FloatNano fd(500.0);
auto d = duration_cast<milliseconds>(fd); //0.0005 ms
The minimum, maximum and zero representation for a specific tick count type are returned by the min(), max() and zero() static methods found in the duration type.
Time point
template<
class Clock,
class Duration = typename Clock::duration
> class time_point;
The time_point
type is the representation of a point in time and it is
parametrized on the clock and duration types.
The reason for which the time_point type is dependent on the clock type is because the time point represents the number of periods (ticks) elapsed from the beginning of time and such beginning changes depending on the clock type: it could be e.g. the start of the current process or a specific point in physical time.
The dependency on the duration type is required because the time_point type is implemented as a duration representing the elapsed time since the beginning of time. Such duration is returned by the time_since_epoch() member. The default duration type is the duration type declared in the clock type.
You convert between time points with different durations with the
time_point_cast
function.
To convert a time_point
to a standard time_t
type use the static
member function to_time()
found in the clock type.
To print a time point you use the put_time()
library function.
You can also easily print a time_point
instance by first converting
it to time_t
:
#include <chrono>
#include <ctime>
...
using Clock = std::chrono::system_clock;
std::time_t now = Clock::to_time_t(Clock::now());
cout << std::ctime(now) << endl;
Clock
The clock type returns the time_point instance representing the current time whenever its static now() method is invoked.
The three clock types required to be available in C++11 STL implementations are:
- system_clock: tracks physical wall clock time; invoking now() on this clock at two different times does not guarantee that the second call to now() returns a time greater than the previous call to now()
- steady_clock: monotonic time function, the time returned by now() is always increasing
- high_resolution_clock: smallest possible period
On many systems the resolution period is one nanosecond for all clock types.
You have actually already seen all you need to know about clock usage in the previous section i.e. how to call the now() and to_time_t() static methods.
Now let’s look at some properties unique to each clock type.
The properties that identify a specific clock type are:
- period
- origin of time
- steadiness
The following code shows how to retrieve and print the above information given a clock type:
using Clock = std::chrono::system_clock;
using TimePoint = Clock::time_point;
const bool isSteady = Clock::is_steady;
//one period (tick) is equal to num/den seconds
const intmax_t periodNum = Clock::period::num;
const intmax_t periodDen = Clock::period::den;
//the default constructor for a time_point initializes
//it to the origin of time
std::time_t epoch = Clock::to_time_t(TimePoint());
Timing execution
You now have all the information required to easily time your own code.
For timing execution do use a clock which has an is_steady member set to true e.g. steady_clock.
using namespace std;
using namespace chrono;
using Timer = steady_clock;
using Time = Timer::time_point;
using Duration = Timer::duration;
using ms = ratio< INTMAX_C(1), INTMAX_C(1000) >;
auto Tick = []{ return Timer::now(); };
const Time begin = Tick();
//execute code
...
const Time end = Tick();
const Duration elapsed = end - begin;
cout << "Elapsed time: "
<< duration_cast< duration< intmax_t, ms > >(elapsed)
<< "ms" << endl;
Instead of your own ratio constant you can use the predefined constants: milli, micro, …
Instead of your own duration constant you can use the predefined constants: milliseconds, microseconds, …
e.g.:
...
//use std::chrono::milliseconds duration type
cout << duration_cast< milliseconds >(elapsed).count() << endl;
...
Checkout the ISO standard, cppreference or your own STL documentation for a complete list of such constants.
Code
Sample code showing the use of the various chrono types: Sample code
A minimal implementation of a C++11 compliant timer class: [Timer](https://github.com/ugovaretto/cpp11-scratch/tree/master/training/timer