2 * Copyright 2017 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.
23 #include <folly/Chrono.h>
24 #include <folly/portability/Time.h>
28 using monotonic_clock = std::chrono::steady_clock;
31 * Calculates the duration of time intervals. Prefer this over directly using
32 * monotonic clocks. It is very lightweight and provides convenient facilitles
33 * to avoid common pitfalls.
35 * There are two type aliases that should be preferred over instantiating this
36 * class directly: `coarse_stop_watch` and `stop_watch`.
39 * - Clock: the monotonic clock to use when calculating time intervals
40 * - Duration: (optional) the duration to use when reporting elapsed time.
41 * Defaults to the clock's duration.
45 * coarse_stop_watch<std::chrono::seconds> watch;
47 * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
49 * auto const ttl = 60_s;
50 * if (watch.elapsed(ttl)) {
51 * process_expiration();
56 * struct run_every_n_seconds {
57 * using callback = std::function<void()>;
58 * run_every_n_seconds(std::chrono::seconds period, callback action)
60 * action_(std::move(action))
62 * // watch_ is correctly initialized to the current time
67 * if (watch_.lap(period_)) {
70 * std::this_thread::yield();
75 * stop_watch<> watch_;
76 * std::chrono::seconds period_;
80 * @author: Marcelo Juchem <marcelo@fb.com>
82 template <typename Clock, typename Duration = typename Clock::duration>
83 struct custom_stop_watch {
84 using clock_type = Clock;
85 using duration = Duration;
86 using time_point = std::chrono::time_point<clock_type, duration>;
89 std::ratio_less_equal<
90 typename clock_type::duration::period,
91 typename duration::period>::value,
92 "clock must be at least as precise as the requested duration");
96 "only monotonic clocks should be used to track time intervals");
99 * Initializes the stop watch with the current time as its checkpoint.
103 * stop_watch<> watch;
105 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
107 * @author: Marcelo Juchem <marcelo@fb.com>
109 custom_stop_watch() : checkpoint_(clock_type::now()) {}
112 * Initializes the stop watch with the given time as its checkpoint.
114 * NOTE: this constructor should be seldomly used. It is only provided so
115 * that, in the rare occasions it is needed, one does not have to reimplement
116 * the `custom_stop_watch` class.
120 * custom_stop_watch<monotonic_clock> watch(monotonic_clock::now());
122 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
124 * @author: Marcelo Juchem <marcelo@fb.com>
126 explicit custom_stop_watch(typename clock_type::time_point checkpoint)
127 : checkpoint_(std::move(checkpoint)) {}
130 * Updates the stop watch checkpoint to the current time.
134 * struct some_resource {
137 * void on_reloaded() {
138 * time_alive.reset();
142 * std::cout << "resource has been alive for " << time_alive.elapsed();
146 * stop_watch<> time_alive;
149 * @author: Marcelo Juchem <marcelo@fb.com>
152 checkpoint_ = clock_type::now();
156 * Tells the elapsed time since the last update.
158 * The stop watch's checkpoint remains unchanged.
162 * stop_watch<> watch;
164 * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
166 * @author: Marcelo Juchem <marcelo@fb.com>
168 duration elapsed() const {
169 return std::chrono::duration_cast<duration>(
170 clock_type::now() - checkpoint_);
174 * Tells whether the given duration has already elapsed since the last
179 * auto const ttl = 60_s;
180 * stop_watch<> watch;
184 * std::cout << "has the TTL expired? " std::boolalpha<< watch.elapsed(ttl);
186 * @author: Marcelo Juchem <marcelo@fb.com>
188 template <typename UDuration>
189 bool elapsed(UDuration&& amount) const {
190 return clock_type::now() - checkpoint_ >= amount;
194 * Tells the elapsed time since the last update, and updates the checkpoint
195 * to the current time.
199 * struct some_resource {
202 * void on_reloaded() {
203 * auto const alive = time_alive.lap();
204 * std::cout << "resource reloaded after being alive for " << alive;
208 * stop_watch<> time_alive;
211 * @author: Marcelo Juchem <marcelo@fb.com>
214 auto lastCheckpoint = checkpoint_;
216 checkpoint_ = clock_type::now();
218 return std::chrono::duration_cast<duration>(checkpoint_ - lastCheckpoint);
222 * Tells whether the given duration has already elapsed since the last
223 * checkpoint. If so, update the checkpoint to the current time. If not,
224 * the checkpoint remains unchanged.
228 * void run_every_n_seconds(
229 * std::chrono::seconds period,
230 * std::function<void()> action
232 * for (stop_watch<> watch;; ) {
233 * if (watch.lap(period)) {
236 * std::this_thread::yield();
240 * @author: Marcelo Juchem <marcelo@fb.com>
242 template <typename UDuration>
243 bool lap(UDuration&& amount) {
244 auto now = clock_type::now();
246 if (now - checkpoint_ < amount) {
255 * Returns the current checkpoint
257 typename clock_type::time_point getCheckpoint() const {
262 typename clock_type::time_point checkpoint_;
266 * A type alias for `custom_stop_watch` that uses a coarse monotonic clock as
267 * the time source. Refer to the documentation of `custom_stop_watch` for full
271 * - Duration: (optional) the duration to use when reporting elapsed time.
272 * Defaults to the clock's duration.
276 * coarse_stop_watch<std::chrono::seconds> watch;
278 * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
280 * @author: Marcelo Juchem <marcelo@fb.com>
282 template <typename Duration = folly::chrono::coarse_steady_clock::duration>
283 using coarse_stop_watch =
284 custom_stop_watch<folly::chrono::coarse_steady_clock, Duration>;
287 * A type alias for `custom_stop_watch` that uses a monotonic clock as the time
288 * source. Refer to the documentation of `custom_stop_watch` for full
292 * - Duration: (optional) the duration to use when reporting elapsed time.
293 * Defaults to the clock's duration.
297 * stop_watch<std::chrono::seconds> watch;
299 * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
301 * @author: Marcelo Juchem <marcelo@fb.com>
303 template <typename Duration = std::chrono::steady_clock::duration>
304 using stop_watch = custom_stop_watch<std::chrono::steady_clock, Duration>;