“One should always aim at being interesting, rather than exact.”
― Voltaire
Applications that perform frequent timestamp requests are affected by the CPU cost of reading the clock. If the operation is repeated multiple times, the accumulated cost can have an impact on the overall performance of the application.
Many use cases do not need high resolution clocks. For example resolution of hundreds milliseconds or even seconds is fine for the following cases:
Some of the platforms provide coarse timers that are more than 70 times faster than the existing standard library clocks [benchmark]. Due to such drastic performance difference some code bases to minimize CPU usage already use coarse clocks. Moreover it is a common pattern to try to use a coarse clock first and than fallback to precise clock if the resolution is not enough:
bool is_expired(std::chrono::steady_clock::time_point deadline) { auto max_time = coarse_steady_clock() + coarse_steady_clock_resolution(); if (max_time < deadline) { return false; } return deadline < std::chrono::steady_clock::now() }
Here are some projects that use coarse clocks and/or resolutions:
To sum up: coarse clocks are much more CPU efficient in some cases. Ability to get the coarse clock resolution makes them useful even in more cases.
Implementing a coarse clock by just dropping sub-seconds from a more precise clock is fine and still could save a few CPU cycles due to avoiding computations of sub-seconds.
duration
and time_point
types are same as in non-coarse clocks?Precise and coarse clocks could be used together (see example from motivation section). Same duration and timepoint types simplify code writing, as less type conversions is needed. Also clock could be a template parameter so same interfaces make it easier to write generic code that use different types of clocks.
A type TC meets the Cpp17TrivialResolutionClock requirements if
resolution()
returns positive duration that is the minimal non zero difference between two invocations of now()
,resolution()
does not throw exceptions.The types defined in [time.clock] meet the Cpp17TrivialResolutionClock requirements ([time.clock.req]) unless otherwise specified.
resolution()
after function now()
:static time_point now() noexcept; static duration resolution() noexcept;
namespace std::chrono { class coarse_steady_clock { public: using rep = steady_clock::rep; using period = steady_clock::period; using duration = steady_clock::duration; using time_point = steady_clock::time_point; static constexpr bool is_steady = true; static time_point now() noexcept; static duration resolution() noexcept; }; }
Objects of class coarse_steady_clock
represent clocks for which
values of time_point
never decrease as physical time advances and
for which values of time_point
advance at a steady rate relative to
real time. That is, the clock may not be adjusted.
Result of resolution()
is coarser
then the resolution of steady_clock
.
namespace std::chrono { class coarse_system_clock { public: using rep = system_clock::rep; using period = system_clock::period; using duration = system_clock::duration; using time_point = system_clock::time_point; static constexpr bool is_steady = system_clock::is_steady; static time_point now() noexcept; static duration resolution() noexcept; // mapping to/from C type time_t static time_t to_time_t(const time_point& t) noexcept { return system_clock::to_time_t(t); } static time_point from_time_t(time_t t) noexcept { return system_clock::from_time_t(t); } }; }
Objects of type coarse_system_clock
represent wall clock time
from the system-wide realtime clock and measure
time since 1970-01-01 00:00:00 UTC
excluding leap seconds.
This measure is commonly referred to as Unix time.
Result of resolution()
is coarser
then the resolution of system_clock
.