123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- /*
- * Copyright 2016-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #pragma once
- #include <chrono>
- #include <stdexcept>
- #include <utility>
- #include <folly/Chrono.h>
- #include <folly/portability/Time.h>
- namespace folly {
- using monotonic_clock = std::chrono::steady_clock;
- /**
- * Calculates the duration of time intervals. Prefer this over directly using
- * monotonic clocks. It is very lightweight and provides convenient facilitles
- * to avoid common pitfalls.
- *
- * There are two type aliases that should be preferred over instantiating this
- * class directly: `coarse_stop_watch` and `stop_watch`.
- *
- * Arguments:
- * - Clock: the monotonic clock to use when calculating time intervals
- * - Duration: (optional) the duration to use when reporting elapsed time.
- * Defaults to the clock's duration.
- *
- * Example 1:
- *
- * coarse_stop_watch<std::chrono::seconds> watch;
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
- *
- * auto const ttl = 60_s;
- * if (watch.elapsed(ttl)) {
- * process_expiration();
- * }
- *
- * Example 2:
- *
- * struct run_every_n_seconds {
- * using callback = std::function<void()>;
- * run_every_n_seconds(std::chrono::seconds period, callback action)
- * period_(period),
- * action_(std::move(action))
- * {
- * // watch_ is correctly initialized to the current time
- * }
- *
- * void run() {
- * while (true) {
- * if (watch_.lap(period_)) {
- * action_();
- * }
- * std::this_thread::yield();
- * }
- * }
- *
- * private:
- * stop_watch<> watch_;
- * std::chrono::seconds period_;
- * callback action_;
- * };
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- template <typename Clock, typename Duration = typename Clock::duration>
- struct custom_stop_watch {
- using clock_type = Clock;
- using duration = Duration;
- using time_point = std::chrono::time_point<clock_type, duration>;
- static_assert(
- std::ratio_less_equal<
- typename clock_type::duration::period,
- typename duration::period>::value,
- "clock must be at least as precise as the requested duration");
- static_assert(
- Clock::is_steady,
- "only monotonic clocks should be used to track time intervals");
- /**
- * Initializes the stop watch with the current time as its checkpoint.
- *
- * Example:
- *
- * stop_watch<> watch;
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- custom_stop_watch() : checkpoint_(clock_type::now()) {}
- /**
- * Initializes the stop watch with the given time as its checkpoint.
- *
- * NOTE: this constructor should be seldomly used. It is only provided so
- * that, in the rare occasions it is needed, one does not have to reimplement
- * the `custom_stop_watch` class.
- *
- * Example:
- *
- * custom_stop_watch<monotonic_clock> watch(monotonic_clock::now());
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- explicit custom_stop_watch(typename clock_type::time_point checkpoint)
- : checkpoint_(std::move(checkpoint)) {}
- /**
- * Updates the stop watch checkpoint to the current time.
- *
- * Example:
- *
- * struct some_resource {
- * // ...
- *
- * void on_reloaded() {
- * time_alive.reset();
- * }
- *
- * void report() {
- * std::cout << "resource has been alive for " << time_alive.elapsed();
- * }
- *
- * private:
- * stop_watch<> time_alive;
- * };
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- void reset() {
- checkpoint_ = clock_type::now();
- }
- /**
- * Tells the elapsed time since the last update.
- *
- * The stop watch's checkpoint remains unchanged.
- *
- * Example:
- *
- * stop_watch<> watch;
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed() << std::endl;
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- duration elapsed() const {
- return std::chrono::duration_cast<duration>(
- clock_type::now() - checkpoint_);
- }
- /**
- * Tells whether the given duration has already elapsed since the last
- * checkpoint.
- *
- * Example:
- *
- * auto const ttl = 60_s;
- * stop_watch<> watch;
- *
- * do_something();
- *
- * std::cout << "has the TTL expired? " std::boolalpha<< watch.elapsed(ttl);
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- template <typename UDuration>
- bool elapsed(UDuration&& amount) const {
- return clock_type::now() - checkpoint_ >= amount;
- }
- /**
- * Tells the elapsed time since the last update, and updates the checkpoint
- * to the current time.
- *
- * Example:
- *
- * struct some_resource {
- * // ...
- *
- * void on_reloaded() {
- * auto const alive = time_alive.lap();
- * std::cout << "resource reloaded after being alive for " << alive;
- * }
- *
- * private:
- * stop_watch<> time_alive;
- * };
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- duration lap() {
- auto lastCheckpoint = checkpoint_;
- checkpoint_ = clock_type::now();
- return std::chrono::duration_cast<duration>(checkpoint_ - lastCheckpoint);
- }
- /**
- * Tells whether the given duration has already elapsed since the last
- * checkpoint. If so, update the checkpoint to the current time. If not,
- * the checkpoint remains unchanged.
- *
- * Example:
- *
- * void run_every_n_seconds(
- * std::chrono::seconds period,
- * std::function<void()> action
- * ) {
- * for (stop_watch<> watch;; ) {
- * if (watch.lap(period)) {
- * action();
- * }
- * std::this_thread::yield();
- * }
- * }
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- template <typename UDuration>
- bool lap(UDuration&& amount) {
- auto now = clock_type::now();
- if (now - checkpoint_ < amount) {
- return false;
- }
- checkpoint_ = now;
- return true;
- }
- /**
- * Returns the current checkpoint
- */
- typename clock_type::time_point getCheckpoint() const {
- return checkpoint_;
- }
- private:
- typename clock_type::time_point checkpoint_;
- };
- /**
- * A type alias for `custom_stop_watch` that uses a coarse monotonic clock as
- * the time source. Refer to the documentation of `custom_stop_watch` for full
- * documentation.
- *
- * Arguments:
- * - Duration: (optional) the duration to use when reporting elapsed time.
- * Defaults to the clock's duration.
- *
- * Example:
- *
- * coarse_stop_watch<std::chrono::seconds> watch;
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- template <typename Duration = folly::chrono::coarse_steady_clock::duration>
- using coarse_stop_watch =
- custom_stop_watch<folly::chrono::coarse_steady_clock, Duration>;
- /**
- * A type alias for `custom_stop_watch` that uses a monotonic clock as the time
- * source. Refer to the documentation of `custom_stop_watch` for full
- * documentation.
- *
- * Arguments:
- * - Duration: (optional) the duration to use when reporting elapsed time.
- * Defaults to the clock's duration.
- *
- * Example:
- *
- * stop_watch<std::chrono::seconds> watch;
- * do_something();
- * std::cout << "time elapsed: " << watch.elapsed().count() << std::endl;
- *
- * @author: Marcelo Juchem <marcelo@fb.com>
- */
- template <typename Duration = std::chrono::steady_clock::duration>
- using stop_watch = custom_stop_watch<std::chrono::steady_clock, Duration>;
- } // namespace folly
|