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/ewma.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/monlib/metrics/ewma.cpp')
-rw-r--r-- | library/cpp/monlib/metrics/ewma.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/library/cpp/monlib/metrics/ewma.cpp b/library/cpp/monlib/metrics/ewma.cpp new file mode 100644 index 0000000000..8a296c3225 --- /dev/null +++ b/library/cpp/monlib/metrics/ewma.cpp @@ -0,0 +1,150 @@ +#include "ewma.h" +#include "metric.h" + +#include <atomic> +#include <cmath> + +namespace NMonitoring { +namespace { + constexpr auto DEFAULT_INTERVAL = TDuration::Seconds(5); + + const double ALPHA1 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./1.); + const double ALPHA5 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./5.); + const double ALPHA15 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./15.); + + class TExpMovingAverage final: public IExpMovingAverage { + public: + explicit TExpMovingAverage(IGauge* metric, double alpha, TDuration interval) + : Metric_{metric} + , Alpha_{alpha} + , Interval_{interval.Seconds()} + { + Y_VERIFY(metric != nullptr, "Passing nullptr metric is not allowed"); + } + + ~TExpMovingAverage() override = default; + + // This method NOT thread safe + void Tick() override { + const auto current = Uncounted_.fetch_and(0); + const double instantRate = double(current) / Interval_; + + if (Y_UNLIKELY(!IsInitialized())) { + Metric_->Set(instantRate); + Init_ = true; + } else { + const double currentRate = Metric_->Get(); + Metric_->Set(Alpha_ * (instantRate - currentRate) + currentRate); + } + + } + + void Update(i64 value) override { + Uncounted_ += value; + } + + double Rate() const override { + return Metric_->Get(); + } + + void Reset() override { + Init_ = false; + Uncounted_ = 0; + } + + private: + bool IsInitialized() const { + return Init_; + } + + private: + std::atomic<i64> Uncounted_{0}; + std::atomic<bool> Init_{false}; + + IGauge* Metric_{nullptr}; + double Alpha_; + ui64 Interval_; + }; + + struct TFakeEwma: IExpMovingAverage { + void Tick() override {} + void Update(i64) override {} + double Rate() const override { return 0; } + void Reset() override {} + }; + +} // namespace + + TEwmaMeter::TEwmaMeter() + : Ewma_{MakeHolder<TFakeEwma>()} + { + } + + TEwmaMeter::TEwmaMeter(IExpMovingAveragePtr&& ewma) + : Ewma_{std::move(ewma)} + { + } + + TEwmaMeter::TEwmaMeter(TEwmaMeter&& other) { + if (&other == this) { + return; + } + + *this = std::move(other); + } + + TEwmaMeter& TEwmaMeter::operator=(TEwmaMeter&& other) { + Ewma_ = std::move(other.Ewma_); + LastTick_.store(other.LastTick_); + return *this; + } + + void TEwmaMeter::TickIfNeeded() { + constexpr ui64 INTERVAL_SECONDS = DEFAULT_INTERVAL.Seconds(); + + const auto now = TInstant::Now().Seconds(); + ui64 old = LastTick_.load(); + const auto secondsSinceLastTick = now - old; + + if (secondsSinceLastTick > INTERVAL_SECONDS) { + // round to the interval grid + const ui64 newLast = now - (secondsSinceLastTick % INTERVAL_SECONDS); + if (LastTick_.compare_exchange_strong(old, newLast)) { + for (size_t i = 0; i < secondsSinceLastTick / INTERVAL_SECONDS; ++i) { + Ewma_->Tick(); + } + } + } + } + + void TEwmaMeter::Mark() { + TickIfNeeded(); + Ewma_->Update(1); + } + + void TEwmaMeter::Mark(i64 value) { + TickIfNeeded(); + Ewma_->Update(value); + } + + double TEwmaMeter::Get() { + TickIfNeeded(); + return Ewma_->Rate(); + } + + IExpMovingAveragePtr OneMinuteEwma(IGauge* metric) { + return MakeHolder<TExpMovingAverage>(metric, ALPHA1, DEFAULT_INTERVAL); + } + + IExpMovingAveragePtr FiveMinuteEwma(IGauge* metric) { + return MakeHolder<TExpMovingAverage>(metric, ALPHA5, DEFAULT_INTERVAL); + } + + IExpMovingAveragePtr FiveteenMinuteEwma(IGauge* metric) { + return MakeHolder<TExpMovingAverage>(metric, ALPHA15, DEFAULT_INTERVAL); + } + + IExpMovingAveragePtr CreateEwma(IGauge* metric, double alpha, TDuration interval) { + return MakeHolder<TExpMovingAverage>(metric, alpha, interval); + } +} // namespace NMonitoring |