logging: add numbered INFO* log level values
[folly.git] / folly / stop_watch.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #pragma once
18
19 #include <chrono>
20 #include <stdexcept>
21 #include <utility>
22
23 #include <folly/Chrono.h>
24 #include <folly/portability/Time.h>
25
26 namespace folly {
27
28 using monotonic_clock = std::chrono::steady_clock;
29
30 /**
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.
34  *
35  * There are two type aliases that should be preferred over instantiating this
36  * class directly: `coarse_stop_watch` and `stop_watch`.
37  *
38  * Arguments:
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.
42  *
43  * Example 1:
44  *
45  *  coarse_stop_watch<std::chrono::seconds> watch;
46  *  do_something();
47  *  std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
48  *
49  *  auto const ttl = 60_s;
50  *  if (watch.elapsed(ttl)) {
51  *    process_expiration();
52  *  }
53  *
54  * Example 2:
55  *
56  *  struct run_every_n_seconds {
57  *    using callback = std::function<void()>;
58  *    run_every_n_seconds(std::chrono::seconds period, callback action)
59  *      period_(period),
60  *      action_(std::move(action))
61  *    {
62  *      // watch_ is correctly initialized to the current time
63  *    }
64  *
65  *    void run() {
66  *      while (true) {
67  *        if (watch_.lap(period_)) {
68  *          action_();
69  *        }
70  *        std::this_thread::yield();
71  *      }
72  *    }
73  *
74  *  private:
75  *    stop_watch<> watch_;
76  *    std::chrono::seconds period_;
77  *    callback action_;
78  *  };
79  *
80  * @author: Marcelo Juchem <marcelo@fb.com>
81  */
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>;
87
88   static_assert(
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");
93
94   static_assert(
95       Clock::is_steady,
96       "only monotonic clocks should be used to track time intervals");
97
98   /**
99    * Initializes the stop watch with the current time as its checkpoint.
100    *
101    * Example:
102    *
103    *  stop_watch<> watch;
104    *  do_something();
105    *  std::cout << "time elapsed: " << watch.elapsed() << std::endl;
106    *
107    * @author: Marcelo Juchem <marcelo@fb.com>
108    */
109   custom_stop_watch() : checkpoint_(clock_type::now()) {}
110
111   /**
112    * Initializes the stop watch with the given time as its checkpoint.
113    *
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.
117    *
118    * Example:
119    *
120    *  custom_stop_watch<monotonic_clock> watch(monotonic_clock::now());
121    *  do_something();
122    *  std::cout << "time elapsed: " << watch.elapsed() << std::endl;
123    *
124    * @author: Marcelo Juchem <marcelo@fb.com>
125    */
126   explicit custom_stop_watch(typename clock_type::time_point checkpoint)
127       : checkpoint_(std::move(checkpoint)) {}
128
129   /**
130    * Updates the stop watch checkpoint to the current time.
131    *
132    * Example:
133    *
134    *  struct some_resource {
135    *    // ...
136    *
137    *    void on_reloaded() {
138    *      time_alive.reset();
139    *    }
140    *
141    *    void report() {
142    *      std::cout << "resource has been alive for " << time_alive.elapsed();
143    *    }
144    *
145    *  private:
146    *    stop_watch<> time_alive;
147    *  };
148    *
149    * @author: Marcelo Juchem <marcelo@fb.com>
150    */
151   void reset() {
152     checkpoint_ = clock_type::now();
153   }
154
155   /**
156    * Tells the elapsed time since the last update.
157    *
158    * The stop watch's checkpoint remains unchanged.
159    *
160    * Example:
161    *
162    *  stop_watch<> watch;
163    *  do_something();
164    *  std::cout << "time elapsed: " << watch.elapsed() << std::endl;
165    *
166    * @author: Marcelo Juchem <marcelo@fb.com>
167    */
168   duration elapsed() const {
169     return std::chrono::duration_cast<duration>(
170         clock_type::now() - checkpoint_);
171   }
172
173   /**
174    * Tells whether the given duration has already elapsed since the last
175    * checkpoint.
176    *
177    * Example:
178    *
179    *  auto const ttl = 60_s;
180    *  stop_watch<> watch;
181    *
182    *  do_something();
183    *
184    *  std::cout << "has the TTL expired? " std::boolalpha<< watch.elapsed(ttl);
185    *
186    * @author: Marcelo Juchem <marcelo@fb.com>
187    */
188   template <typename UDuration>
189   bool elapsed(UDuration&& amount) const {
190     return clock_type::now() - checkpoint_ >= amount;
191   }
192
193   /**
194    * Tells the elapsed time since the last update, and updates the checkpoint
195    * to the current time.
196    *
197    * Example:
198    *
199    *  struct some_resource {
200    *    // ...
201    *
202    *    void on_reloaded() {
203    *      auto const alive = time_alive.lap();
204    *      std::cout << "resource reloaded after being alive for " << alive;
205    *    }
206    *
207    *  private:
208    *    stop_watch<> time_alive;
209    *  };
210    *
211    * @author: Marcelo Juchem <marcelo@fb.com>
212    */
213   duration lap() {
214     auto lastCheckpoint = checkpoint_;
215
216     checkpoint_ = clock_type::now();
217
218     return std::chrono::duration_cast<duration>(checkpoint_ - lastCheckpoint);
219   }
220
221   /**
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.
225    *
226    * Example:
227    *
228    *  void run_every_n_seconds(
229    *    std::chrono::seconds period,
230    *    std::function<void()> action
231    *  ) {
232    *    for (stop_watch<> watch;; ) {
233    *      if (watch.lap(period)) {
234    *        action();
235    *      }
236    *      std::this_thread::yield();
237    *    }
238    *  }
239    *
240    * @author: Marcelo Juchem <marcelo@fb.com>
241    */
242   template <typename UDuration>
243   bool lap(UDuration&& amount) {
244     auto now = clock_type::now();
245
246     if (now - checkpoint_ < amount) {
247       return false;
248     }
249
250     checkpoint_ = now;
251     return true;
252   }
253
254   /**
255    * Returns the current checkpoint
256    */
257   typename clock_type::time_point getCheckpoint() const {
258     return checkpoint_;
259   }
260
261  private:
262   typename clock_type::time_point checkpoint_;
263 };
264
265 /**
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
268  * documentation.
269  *
270  * Arguments:
271  *  - Duration: (optional) the duration to use when reporting elapsed time.
272  *              Defaults to the clock's duration.
273  *
274  * Example:
275  *
276  *  coarse_stop_watch<std::chrono::seconds> watch;
277  *  do_something();
278  *  std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
279  *
280  * @author: Marcelo Juchem <marcelo@fb.com>
281  */
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>;
285
286 /**
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
289  * documentation.
290  *
291  * Arguments:
292  *  - Duration: (optional) the duration to use when reporting elapsed time.
293  *              Defaults to the clock's duration.
294  *
295  * Example:
296  *
297  *  stop_watch<std::chrono::seconds> watch;
298  *  do_something();
299  *  std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
300  *
301  * @author: Marcelo Juchem <marcelo@fb.com>
302  */
303 template <typename Duration = std::chrono::steady_clock::duration>
304 using stop_watch = custom_stop_watch<std::chrono::steady_clock, Duration>;
305 } // namespace folly