2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <folly/portability/Time.h>
26 #ifdef CLOCK_MONOTONIC_COARSE
27 struct monotonic_coarse_clock {
28 typedef std::chrono::milliseconds::rep rep;
29 typedef std::chrono::milliseconds::period period;
30 typedef std::chrono::milliseconds duration;
31 typedef std::chrono::time_point<monotonic_coarse_clock> time_point;
32 constexpr static bool is_steady = true;
34 static time_point now() {
36 auto ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
38 throw std::runtime_error("Error using CLOCK_MONOTONIC_COARSE.");
41 duration((ts.tv_sec * 1000) + ((ts.tv_nsec / 1000) / 1000)));
45 using monotonic_coarse_clock = std::chrono::steady_clock;
48 using monotonic_clock = std::chrono::steady_clock;
51 * Calculates the duration of time intervals. Prefer this over directly using
52 * monotonic clocks. It is very lightweight and provides convenient facilitles
53 * to avoid common pitfalls.
55 * There are two type aliases that should be preferred over instantiating this
56 * class directly: `coarse_stop_watch` and `stop_watch`.
59 * - Clock: the monotonic clock to use when calculating time intervals
60 * - Duration: (optional) the duration to use when reporting elapsed time.
61 * Defaults to the clock's duration.
65 * coarse_stop_watch<std::seconds> watch;
67 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
69 * auto const ttl = 60_s;
70 * if (watch.elapsed(ttl)) {
71 * process_expiration();
76 * struct run_every_n_seconds {
77 * using callback = std::function<void()>;
78 * run_every_n_seconds(std::chrono::seconds period, callback action)
80 * action_(std::move(action))
82 * // watch_ is correctly initialized to the current time
87 * if (watch_.lap(period_)) {
90 * std::this_thread::yield();
95 * stop_watch<> watch_;
96 * std::chrono::seconds period_;
100 * @author: Marcelo Juchem <marcelo@fb.com>
102 template <typename Clock, typename Duration = typename Clock::duration>
103 struct custom_stop_watch {
104 using clock_type = Clock;
105 using duration = Duration;
106 using time_point = std::chrono::time_point<clock_type, duration>;
109 std::ratio_less_equal<
110 typename clock_type::duration::period,
111 typename duration::period>::value,
112 "clock must be at least as precise as the requested duration");
116 "only monotonic clocks should be used to track time intervals");
119 * Initializes the stop watch with the current time as its checkpoint.
123 * stop_watch<> watch;
125 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
127 * @author: Marcelo Juchem <marcelo@fb.com>
129 custom_stop_watch() : checkpoint_(clock_type::now()) {}
132 * Initializes the stop watch with the given time as its checkpoint.
134 * NOTE: this constructor should be seldomly used. It is only provided so
135 * that, in the rare occasions it is needed, one does not have to reimplement
136 * the `custom_stop_watch` class.
140 * custom_stop_watch<monotonic_clock> watch(monotonic_clock::now());
142 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
144 * @author: Marcelo Juchem <marcelo@fb.com>
146 explicit custom_stop_watch(typename clock_type::time_point checkpoint)
147 : checkpoint_(std::move(checkpoint)) {}
150 * Updates the stop watch checkpoint to the current time.
154 * struct some_resource {
157 * void on_reloaded() {
158 * time_alive.reset();
162 * std::cout << "resource has been alive for " << time_alive.elapsed();
166 * stop_watch<> time_alive;
169 * @author: Marcelo Juchem <marcelo@fb.com>
172 checkpoint_ = clock_type::now();
176 * Tells the elapsed time since the last update.
178 * The stop watch's checkpoint remains unchanged.
182 * stop_watch<> watch;
184 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
186 * @author: Marcelo Juchem <marcelo@fb.com>
188 duration elapsed() const {
189 return std::chrono::duration_cast<duration>(
190 clock_type::now() - checkpoint_);
194 * Tells whether the given duration has already elapsed since the last
199 * auto const ttl = 60_s;
200 * stop_watch<> watch;
204 * std::cout << "has the TTL expired? " std::boolalpha<< watch.elapsed(ttl);
206 * @author: Marcelo Juchem <marcelo@fb.com>
208 template <typename UDuration>
209 bool elapsed(UDuration&& amount) const {
210 return clock_type::now() - checkpoint_ >= amount;
214 * Tells the elapsed time since the last update, and updates the checkpoint
215 * to the current time.
219 * struct some_resource {
222 * void on_reloaded() {
223 * auto const alive = time_alive.lap();
224 * std::cout << "resource reloaded after being alive for " << alive;
228 * stop_watch<> time_alive;
231 * @author: Marcelo Juchem <marcelo@fb.com>
234 auto lastCheckpoint = checkpoint_;
236 checkpoint_ = clock_type::now();
238 return std::chrono::duration_cast<duration>(checkpoint_ - lastCheckpoint);
242 * Tells whether the given duration has already elapsed since the last
243 * checkpoint. If so, update the checkpoint to the current time. If not,
244 * the checkpoint remains unchanged.
248 * void run_every_n_seconds(
249 * std::chrono::seconds period,
250 * std::function<void()> action
252 * for (stop_watch<> watch;; ) {
253 * if (watch.lap(period)) {
256 * std::this_thread::yield();
260 * @author: Marcelo Juchem <marcelo@fb.com>
262 template <typename UDuration>
263 bool lap(UDuration&& amount) {
264 auto now = clock_type::now();
266 if (now - checkpoint_ < amount) {
275 typename clock_type::time_point checkpoint_;
279 * A type alias for `custom_stop_watch` that uses a coarse monotonic clock as
280 * the time source. Refer to the documentation of `custom_stop_watch` for full
284 * - Duration: (optional) the duration to use when reporting elapsed time.
285 * Defaults to the clock's duration.
289 * coarse_stop_watch<std::seconds> watch;
291 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
293 * @author: Marcelo Juchem <marcelo@fb.com>
295 template <typename Duration = monotonic_coarse_clock::duration>
296 using coarse_stop_watch = custom_stop_watch<monotonic_coarse_clock, Duration>;
299 * A type alias for `custom_stop_watch` that uses a monotonic clock as the time
300 * source. Refer to the documentation of `custom_stop_watch` for full
304 * - Duration: (optional) the duration to use when reporting elapsed time.
305 * Defaults to the clock's duration.
309 * stop_watch<std::seconds> watch;
311 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
313 * @author: Marcelo Juchem <marcelo@fb.com>
315 template <typename Duration = monotonic_clock::duration>
316 using stop_watch = custom_stop_watch<monotonic_clock, Duration>;