diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/monlib/metrics/timer.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/monlib/metrics/timer.h')
-rw-r--r-- | library/cpp/monlib/metrics/timer.h | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/library/cpp/monlib/metrics/timer.h b/library/cpp/monlib/metrics/timer.h new file mode 100644 index 0000000000..5c4e26e37b --- /dev/null +++ b/library/cpp/monlib/metrics/timer.h @@ -0,0 +1,127 @@ +#pragma once + +#include "metric.h" + +#include <util/generic/typetraits.h> + +#include <chrono> + + +namespace NMonitoring { + + /** + * A timing scope to record elapsed time since creation. + */ + template <typename TMetric, + typename Resolution = std::chrono::milliseconds, + typename Clock = std::chrono::high_resolution_clock> + class TMetricTimerScope { + public: + explicit TMetricTimerScope(TMetric* metric) + : Metric_(metric) + , StartTime_(Clock::now()) + { + Y_ENSURE(Metric_); + } + + TMetricTimerScope(TMetricTimerScope&) = delete; + TMetricTimerScope& operator=(const TMetricTimerScope&) = delete; + + TMetricTimerScope(TMetricTimerScope&& other) { + *this = std::move(other); + } + + TMetricTimerScope& operator=(TMetricTimerScope&& other) { + Metric_ = other.Metric_; + other.Metric_ = nullptr; + StartTime_ = std::move(other.StartTime_); + + return *this; + } + + void Record() { + Y_VERIFY_DEBUG(Metric_); + if (Metric_ == nullptr) { + return; + } + + auto duration = std::chrono::duration_cast<Resolution>(Clock::now() - StartTime_).count(); + if constexpr (std::is_same<TMetric, TGauge>::value) { + Metric_->Set(duration); + } else if constexpr (std::is_same<TMetric, TIntGauge>::value) { + Metric_->Set(duration); + } else if constexpr (std::is_same<TMetric, TCounter>::value) { + Metric_->Add(duration); + } else if constexpr (std::is_same<TMetric, TRate>::value) { + Metric_->Add(duration); + } else if constexpr (std::is_same<TMetric, THistogram>::value) { + Metric_->Record(duration); + } else { + static_assert(TDependentFalse<TMetric>, "Not supported metric type"); + } + + Metric_ = nullptr; + } + + ~TMetricTimerScope() { + if (Metric_ == nullptr) { + return; + } + + Record(); + } + + private: + TMetric* Metric_{nullptr}; + typename Clock::time_point StartTime_; + }; + + /** + * @brief A class that is supposed to use to measure execution time of an asynchronuous operation. + * + * In order to be able to capture an object into a lambda which is then passed to TFuture::Subscribe/Apply, + * the object must be copy constructible (limitation of the std::function class). So, we cannot use the TMetricTimerScope + * with the abovementioned functions without storing it in a shared pointer or somewhere else. This class works around this + * issue with wrapping the timer with a auto_ptr-like hack Also, Record is const so that one doesn't need to make every lambda mutable + * just to record time measurement. + */ + template <typename TMetric, + typename Resolution = std::chrono::milliseconds, + typename Clock = std::chrono::high_resolution_clock> + class TFutureFriendlyTimer { + public: + explicit TFutureFriendlyTimer(TMetric* metric) + : Impl_{metric} + { + } + + TFutureFriendlyTimer(const TFutureFriendlyTimer& other) + : Impl_{std::move(other.Impl_)} + { + } + + TFutureFriendlyTimer& operator=(const TFutureFriendlyTimer& other) { + Impl_ = std::move(other.Impl_); + } + + TFutureFriendlyTimer(TFutureFriendlyTimer&&) = default; + TFutureFriendlyTimer& operator=(TFutureFriendlyTimer&& other) = default; + + void Record() const { + Impl_.Record(); + } + + private: + mutable TMetricTimerScope<TMetric, Resolution, Clock> Impl_; + }; + + template <typename TMetric> + TMetricTimerScope<TMetric> ScopeTimer(TMetric* metric) { + return TMetricTimerScope<TMetric>{metric}; + } + + template <typename TMetric> + TFutureFriendlyTimer<TMetric> FutureTimer(TMetric* metric) { + return TFutureFriendlyTimer<TMetric>{metric}; + } +} |