1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 2 // This source code is licensed under both the GPLv2 (found in the 3 // COPYING file in the root directory) and Apache 2.0 License 4 // (found in the LICENSE.Apache file in the root directory). 5 // 6 #pragma once 7 #include "monitoring/statistics.h" 8 #include "rocksdb/env.h" 9 10 namespace ROCKSDB_NAMESPACE { 11 // Auto-scoped. 12 // Records the measure time into the corresponding histogram if statistics 13 // is not nullptr. It is also saved into *elapsed if the pointer is not nullptr 14 // and overwrite is true, it will be added to *elapsed if overwrite is false. 15 class StopWatch { 16 public: 17 StopWatch(Env* const env, Statistics* statistics, const uint32_t hist_type, 18 uint64_t* elapsed = nullptr, bool overwrite = true, 19 bool delay_enabled = false) env_(env)20 : env_(env), 21 statistics_(statistics), 22 hist_type_(hist_type), 23 elapsed_(elapsed), 24 overwrite_(overwrite), 25 stats_enabled_(statistics && 26 statistics->get_stats_level() >= 27 StatsLevel::kExceptTimers && 28 statistics->HistEnabledForType(hist_type)), 29 delay_enabled_(delay_enabled), 30 total_delay_(0), 31 delay_start_time_(0), 32 start_time_((stats_enabled_ || elapsed != nullptr) ? env->NowMicros() 33 : 0) {} 34 ~StopWatch()35 ~StopWatch() { 36 if (elapsed_) { 37 if (overwrite_) { 38 *elapsed_ = env_->NowMicros() - start_time_; 39 } else { 40 *elapsed_ += env_->NowMicros() - start_time_; 41 } 42 } 43 if (elapsed_ && delay_enabled_) { 44 *elapsed_ -= total_delay_; 45 } 46 if (stats_enabled_) { 47 statistics_->reportTimeToHistogram( 48 hist_type_, (elapsed_ != nullptr) 49 ? *elapsed_ 50 : (env_->NowMicros() - start_time_)); 51 } 52 } 53 DelayStart()54 void DelayStart() { 55 // if delay_start_time_ is not 0, it means we are already tracking delay, 56 // so delay_start_time_ should not be overwritten 57 if (elapsed_ && delay_enabled_ && delay_start_time_ == 0) { 58 delay_start_time_ = env_->NowMicros(); 59 } 60 } 61 DelayStop()62 void DelayStop() { 63 if (elapsed_ && delay_enabled_ && delay_start_time_ != 0) { 64 total_delay_ += env_->NowMicros() - delay_start_time_; 65 } 66 // reset to 0 means currently no delay is being tracked, so two consecutive 67 // calls to DelayStop will not increase total_delay_ 68 delay_start_time_ = 0; 69 } 70 GetDelay()71 uint64_t GetDelay() const { return delay_enabled_ ? total_delay_ : 0; } 72 start_time()73 uint64_t start_time() const { return start_time_; } 74 75 private: 76 Env* const env_; 77 Statistics* statistics_; 78 const uint32_t hist_type_; 79 uint64_t* elapsed_; 80 bool overwrite_; 81 bool stats_enabled_; 82 bool delay_enabled_; 83 uint64_t total_delay_; 84 uint64_t delay_start_time_; 85 const uint64_t start_time_; 86 }; 87 88 // a nano second precision stopwatch 89 class StopWatchNano { 90 public: 91 explicit StopWatchNano(Env* const env, bool auto_start = false) env_(env)92 : env_(env), start_(0) { 93 if (auto_start) { 94 Start(); 95 } 96 } 97 Start()98 void Start() { start_ = env_->NowNanos(); } 99 100 uint64_t ElapsedNanos(bool reset = false) { 101 auto now = env_->NowNanos(); 102 auto elapsed = now - start_; 103 if (reset) { 104 start_ = now; 105 } 106 return elapsed; 107 } 108 109 uint64_t ElapsedNanosSafe(bool reset = false) { 110 return (env_ != nullptr) ? ElapsedNanos(reset) : 0U; 111 } 112 113 private: 114 Env* const env_; 115 uint64_t start_; 116 }; 117 118 } // namespace ROCKSDB_NAMESPACE 119