blob: 469534fd17d0adacd5ab27e769747dfd74d09196 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_TIME_H_
2#define AOS_TIME_H_
brians343bc112013-02-10 01:53:46 +00003
4#include <stdint.h>
brians57dd5822013-02-27 21:44:15 +00005#include <sys/time.h>
James Kuszmaul651fc3f2019-05-15 21:14:25 -07006#include <time.h>
Brian4a424a22014-04-02 11:52:45 -07007
Austin Schuh793d6b92016-05-01 13:28:14 -07008#include <chrono>
brians343bc112013-02-10 01:53:46 +00009#include <ostream>
James Kuszmaul651fc3f2019-05-15 21:14:25 -070010#include <thread>
11#include <type_traits>
brians343bc112013-02-10 01:53:46 +000012
John Park33858a32018-09-28 23:05:48 -070013#include "aos/macros.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -070014#include "aos/type_traits/type_traits.h"
brians343bc112013-02-10 01:53:46 +000015
16namespace aos {
Austin Schuh793d6b92016-05-01 13:28:14 -070017
18class monotonic_clock {
19 public:
20 typedef ::std::chrono::nanoseconds::rep rep;
21 typedef ::std::chrono::nanoseconds::period period;
22 typedef ::std::chrono::nanoseconds duration;
23 typedef ::std::chrono::time_point<monotonic_clock> time_point;
24
25 static monotonic_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080026 // This clock is still subject to rate adjustments based on adjtime, so it is
27 // not steady.
28 static constexpr bool is_steady = false;
29
30 // Returns the epoch (0).
31 static constexpr monotonic_clock::time_point epoch() {
32 return time_point(zero());
33 }
34
35 static constexpr monotonic_clock::duration zero() { return duration(0); }
36
37 static constexpr time_point min_time{
38 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080039 static constexpr time_point max_time{
40 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Brian Silvermana3688802019-02-16 19:31:26 -080041};
42
43class realtime_clock {
44 public:
45 typedef ::std::chrono::nanoseconds::rep rep;
46 typedef ::std::chrono::nanoseconds::period period;
47 typedef ::std::chrono::nanoseconds duration;
48 typedef ::std::chrono::time_point<monotonic_clock> time_point;
49
50#ifdef __linux__
51 static monotonic_clock::time_point now() noexcept;
52#endif // __linux__
53 static constexpr bool is_steady = false;
Austin Schuh793d6b92016-05-01 13:28:14 -070054
55 // Returns the epoch (0).
56 static constexpr monotonic_clock::time_point epoch() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070057 return time_point(zero());
Austin Schuh793d6b92016-05-01 13:28:14 -070058 }
Austin Schuh8aec1ed2016-05-01 13:29:20 -070059
60 static constexpr monotonic_clock::duration zero() { return duration(0); }
Austin Schuh858c0212016-11-25 17:23:30 -080061
62 static constexpr time_point min_time{
63 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080064 static constexpr time_point max_time{
65 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Austin Schuh793d6b92016-05-01 13:28:14 -070066};
67
brians343bc112013-02-10 01:53:46 +000068namespace time {
69
Brian Silvermanc03a30c2019-02-16 18:21:56 -080070#ifdef __linux__
71
Austin Schuh6a6f90c2016-11-25 21:36:42 -080072// Enables returning the mock time value for Now instead of checking the system
73// clock.
74void EnableMockTime(monotonic_clock::time_point now);
75// Calls SetMockTime with the current actual time.
76void UpdateMockTime();
77// Sets now when time is being mocked.
78void SetMockTime(monotonic_clock::time_point now);
79// Convenience function to just increment the mock time by a certain amount in
80// a thread safe way.
81void IncrementMockTime(monotonic_clock::duration amount);
82// Disables mocking time.
83void DisableMockTime();
84
Austin Schuhf2a50ba2016-12-24 16:16:26 -080085// Sets the global offset for all times so monotonic_clock::now() will return
Brian Silvermand0575692015-02-21 16:24:02 -050086// now.
87// There is no synchronization here, so this is only safe when only a single
88// task is running.
89// This is only allowed when the shared memory core infrastructure has been
90// initialized in this process.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080091void OffsetToNow(const monotonic_clock::time_point now);
Brian Silvermand0575692015-02-21 16:24:02 -050092
Austin Schuhf2a50ba2016-12-24 16:16:26 -080093// Construct a time representing the period of hertz.
94constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
95 return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
96 ::std::chrono::seconds(1)) /
97 hertz;
98}
99
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700100template <typename Scalar>
101constexpr Scalar TypedDurationInSeconds(monotonic_clock::duration dt) {
102 return ::std::chrono::duration_cast<::std::chrono::duration<Scalar>>(dt)
103 .count();
104}
105
106constexpr double DurationInSeconds(monotonic_clock::duration dt) {
107 return TypedDurationInSeconds<double>(dt);
108}
109
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800110// RAII class that freezes monotonic_clock::now() (to avoid making large numbers
111// of syscalls to find the real time).
Brian Silvermanb407c672014-04-09 11:58:37 -0700112class TimeFreezer {
113 public:
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800114 TimeFreezer() { EnableMockTime(monotonic_clock::now()); }
115 ~TimeFreezer() { DisableMockTime(); }
Brian Silvermanb407c672014-04-09 11:58:37 -0700116
117 private:
118 DISALLOW_COPY_AND_ASSIGN(TimeFreezer);
119};
120
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800121#endif // __linux__
122
Neil Balch229001a2018-01-07 18:22:52 -0800123// Converts a monotonic_clock::duration into a timespec object.
124struct timespec to_timespec(::aos::monotonic_clock::duration duration);
125
126// Converts a monotonic_clock::time_point into a timespec object as time since
127// epoch.
128struct timespec to_timespec(::aos::monotonic_clock::time_point time);
129
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800130namespace time_internal {
131
132template <class T>
133struct is_duration : std::false_type {};
134template <class Rep, class Period>
135struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
136
137} // namespace time_internal
138
139// Returns the greatest duration t representable in ToDuration that is less or
140// equal to d.
141// Implementation copied from
142// https://en.cppreference.com/w/cpp/chrono/duration/floor.
143// TODO(Brian): Remove once we have C++17 support.
144template <class To, class Rep, class Period,
145 class = std::enable_if_t<time_internal::is_duration<To>{}>>
146constexpr To floor(const std::chrono::duration<Rep, Period> &d) {
147 To t = std::chrono::duration_cast<To>(d);
148 if (t > d) return t - To{1};
149 return t;
150}
151
152// Returns the value t representable in ToDuration that is the closest to d. If
153// there are two such values, returns the even value (that is, the value t such
154// that t % 2 == 0).
155// Implementation copied from
156// https://en.cppreference.com/w/cpp/chrono/duration/round.
157// TODO(Brian): Remove once we have C++17 support.
158template <class To, class Rep, class Period,
159 class = std::enable_if_t<
160 time_internal::is_duration<To>{} &&
161 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
162constexpr To round(const std::chrono::duration<Rep, Period> &d) {
163 To t0 = aos::time::floor<To>(d);
164 To t1 = t0 + To{1};
165 auto diff0 = d - t0;
166 auto diff1 = t1 - d;
167 if (diff0 == diff1) {
168 if (t0.count() & 1) return t1;
169 return t0;
170 } else if (diff0 < diff1) {
171 return t0;
172 }
173 return t1;
174}
175
176// Returns the nearest time point to tp representable in ToDuration, rounding to
177// even in halfway cases, like std::chrono::round in C++17.
178// Implementation copied from
179// https://en.cppreference.com/w/cpp/chrono/time_point/round.
180// TODO(Brian): Remove once we have C++17 support.
181template <class To, class Clock, class FromDuration,
182 class = std::enable_if_t<
183 time_internal::is_duration<To>{} &&
184 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
185constexpr std::chrono::time_point<Clock, To> round(
186 const std::chrono::time_point<Clock, FromDuration> &tp) {
187 return std::chrono::time_point<Clock, To>{
188 aos::time::round<To>(tp.time_since_epoch())};
189}
190
brians343bc112013-02-10 01:53:46 +0000191} // namespace time
192} // namespace aos
193
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800194#ifdef __linux__
195
Austin Schuh793d6b92016-05-01 13:28:14 -0700196namespace std {
197namespace this_thread {
198// Template specialization for monotonic_clock, since we can use clock_nanosleep
199// with TIMER_ABSTIME and get very precise absolute time sleeps.
200template <>
201void sleep_until(const ::aos::monotonic_clock::time_point &end_time);
202
203} // namespace this_thread
204} // namespace std
205
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800206#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -0700207
John Park33858a32018-09-28 23:05:48 -0700208#endif // AOS_TIME_H_