diff options
author | Sergey Polovko <sergey@polovko.me> | 2022-02-10 16:47:03 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:47:03 +0300 |
commit | 2e714b5ebd40a1f4cc31c27f1ad6e49ca6d895f5 (patch) | |
tree | b83306b6e37edeea782e9eed673d89286c4fef35 /library/cpp/monlib/counters | |
parent | 3e0b762a82514bac89c1dd6ea7211e381d8aa248 (diff) | |
download | ydb-2e714b5ebd40a1f4cc31c27f1ad6e49ca6d895f5.tar.gz |
Restoring authorship annotation for Sergey Polovko <sergey@polovko.me>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/monlib/counters')
-rw-r--r-- | library/cpp/monlib/counters/counters.cpp | 6 | ||||
-rw-r--r-- | library/cpp/monlib/counters/counters.h | 556 | ||||
-rw-r--r-- | library/cpp/monlib/counters/counters_ut.cpp | 88 | ||||
-rw-r--r-- | library/cpp/monlib/counters/histogram.cpp | 74 | ||||
-rw-r--r-- | library/cpp/monlib/counters/histogram.h | 374 | ||||
-rw-r--r-- | library/cpp/monlib/counters/histogram_ut.cpp | 84 | ||||
-rw-r--r-- | library/cpp/monlib/counters/meter.cpp | 8 | ||||
-rw-r--r-- | library/cpp/monlib/counters/meter.h | 570 | ||||
-rw-r--r-- | library/cpp/monlib/counters/meter_ut.cpp | 74 | ||||
-rw-r--r-- | library/cpp/monlib/counters/timer.h | 342 | ||||
-rw-r--r-- | library/cpp/monlib/counters/timer_ut.cpp | 102 | ||||
-rw-r--r-- | library/cpp/monlib/counters/ut/ya.make | 24 | ||||
-rw-r--r-- | library/cpp/monlib/counters/ya.make | 28 |
13 files changed, 1165 insertions, 1165 deletions
diff --git a/library/cpp/monlib/counters/counters.cpp b/library/cpp/monlib/counters/counters.cpp index f49589fac2..50dca4c577 100644 --- a/library/cpp/monlib/counters/counters.cpp +++ b/library/cpp/monlib/counters/counters.cpp @@ -2,7 +2,7 @@ #include "counters.h" namespace NMonitoring { - char* PrettyNumShort(i64 val, char* buf, size_t size) { + char* PrettyNumShort(i64 val, char* buf, size_t size) { static const char shorts[] = {' ', 'K', 'M', 'G', 'T', 'P', 'E'}; unsigned i = 0; i64 major = val; @@ -26,7 +26,7 @@ namespace NMonitoring { return buf; } - char* PrettyNum(i64 val, char* buf, size_t size) { + char* PrettyNum(i64 val, char* buf, size_t size) { Y_ASSERT(buf); if (size < 4) { buf[0] = 0; @@ -46,4 +46,4 @@ namespace NMonitoring { return buf; } -} +} diff --git a/library/cpp/monlib/counters/counters.h b/library/cpp/monlib/counters/counters.h index 71ee2b4527..038b55f0c8 100644 --- a/library/cpp/monlib/counters/counters.h +++ b/library/cpp/monlib/counters/counters.h @@ -19,330 +19,330 @@ #include <array> namespace NMonitoring { -#define BEGIN_OUTPUT_COUNTERS \ - void OutputImpl(IOutputStream& out) { \ +#define BEGIN_OUTPUT_COUNTERS \ + void OutputImpl(IOutputStream& out) { \ char prettyBuf[32]; -#define END_OUTPUT_COUNTERS \ - out.Flush(); \ - } +#define END_OUTPUT_COUNTERS \ + out.Flush(); \ + } #define OUTPUT_NAMED_COUNTER(var, name) out << name << ": \t" << var << NMonitoring::PrettyNum(var, prettyBuf, 32) << '\n' #define OUTPUT_COUNTER(var) OUTPUT_NAMED_COUNTER(var, #var); - char* PrettyNumShort(i64 val, char* buf, size_t size); - char* PrettyNum(i64 val, char* buf, size_t size); - - // This class is deprecated. Please consider to use - // library/cpp/monlib/metrics instead. See more info at - // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/ - class TDeprecatedCounter { - public: - using TValue = TAtomic; - using TValueBase = TAtomicBase; - - TDeprecatedCounter() - : Value() - , Derivative(false) - { - } - - TDeprecatedCounter(TValue value, bool derivative = false) - : Value(value) - , Derivative(derivative) - { - } - - bool ForDerivative() const { - return Derivative; - } - - operator TValueBase() const { - return AtomicGet(Value); - } - TValueBase Val() const { - return AtomicGet(Value); - } - - void Set(TValue val) { - AtomicSet(Value, val); - } - - TValueBase Inc() { - return AtomicIncrement(Value); - } - TValueBase Dec() { - return AtomicDecrement(Value); - } - - TValueBase Add(const TValue val) { - return AtomicAdd(Value, val); - } - TValueBase Sub(const TValue val) { - return AtomicAdd(Value, -val); - } - - // operator overloads convinient - void operator++() { - Inc(); - } - void operator++(int) { - Inc(); - } - - void operator--() { - Dec(); - } - void operator--(int) { - Dec(); - } - - void operator+=(TValue rhs) { - Add(rhs); - } - void operator-=(TValue rhs) { - Sub(rhs); - } - - TValueBase operator=(TValue rhs) { - AtomicSwap(&Value, rhs); - return rhs; - } - - bool operator!() const { - return AtomicGet(Value) == 0; - } + char* PrettyNumShort(i64 val, char* buf, size_t size); + char* PrettyNum(i64 val, char* buf, size_t size); + + // This class is deprecated. Please consider to use + // library/cpp/monlib/metrics instead. See more info at + // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/ + class TDeprecatedCounter { + public: + using TValue = TAtomic; + using TValueBase = TAtomicBase; + + TDeprecatedCounter() + : Value() + , Derivative(false) + { + } + + TDeprecatedCounter(TValue value, bool derivative = false) + : Value(value) + , Derivative(derivative) + { + } + + bool ForDerivative() const { + return Derivative; + } + + operator TValueBase() const { + return AtomicGet(Value); + } + TValueBase Val() const { + return AtomicGet(Value); + } + + void Set(TValue val) { + AtomicSet(Value, val); + } + + TValueBase Inc() { + return AtomicIncrement(Value); + } + TValueBase Dec() { + return AtomicDecrement(Value); + } + + TValueBase Add(const TValue val) { + return AtomicAdd(Value, val); + } + TValueBase Sub(const TValue val) { + return AtomicAdd(Value, -val); + } + + // operator overloads convinient + void operator++() { + Inc(); + } + void operator++(int) { + Inc(); + } + + void operator--() { + Dec(); + } + void operator--(int) { + Dec(); + } + + void operator+=(TValue rhs) { + Add(rhs); + } + void operator-=(TValue rhs) { + Sub(rhs); + } + + TValueBase operator=(TValue rhs) { + AtomicSwap(&Value, rhs); + return rhs; + } + + bool operator!() const { + return AtomicGet(Value) == 0; + } TAtomic& GetAtomic() { return Value; } - private: - TAtomic Value; - bool Derivative; - }; - - template <typename T> - struct TDeprecatedCountersBase { - virtual ~TDeprecatedCountersBase() { - } - - virtual void OutputImpl(IOutputStream&) = 0; - - static T& Instance() { - return *Singleton<T>(); - } - - static void Output(IOutputStream& out) { - Instance().OutputImpl(out); - } - }; - - // This class is deprecated. Please consider to use - // library/cpp/monlib/metrics instead. See more info at - // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/ - // - // Groups of G counters, defined by T type. - // Less(a,b) returns true, if a < b. - // It's threadsafe. - template <typename T, typename G, typename TL = TLess<T>> - class TDeprecatedCounterGroups { - public: - typedef TMap<T, G*> TGroups; - typedef TVector<T> TGroupsNames; - typedef THolder<TGroupsNames> TGroupsNamesPtr; - - private: - class TCollection { - struct TElement { - T* Name; - G* Counters; - - public: - static bool Compare(const TElement& a, const TElement& b) { - return Less(*(a.Name), *(b.Name)); - } - }; // TElement - private: - TArrayHolder<TElement> Elements; - size_t Size; - + private: + TAtomic Value; + bool Derivative; + }; + + template <typename T> + struct TDeprecatedCountersBase { + virtual ~TDeprecatedCountersBase() { + } + + virtual void OutputImpl(IOutputStream&) = 0; + + static T& Instance() { + return *Singleton<T>(); + } + + static void Output(IOutputStream& out) { + Instance().OutputImpl(out); + } + }; + + // This class is deprecated. Please consider to use + // library/cpp/monlib/metrics instead. See more info at + // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/ + // + // Groups of G counters, defined by T type. + // Less(a,b) returns true, if a < b. + // It's threadsafe. + template <typename T, typename G, typename TL = TLess<T>> + class TDeprecatedCounterGroups { + public: + typedef TMap<T, G*> TGroups; + typedef TVector<T> TGroupsNames; + typedef THolder<TGroupsNames> TGroupsNamesPtr; + + private: + class TCollection { + struct TElement { + T* Name; + G* Counters; + + public: + static bool Compare(const TElement& a, const TElement& b) { + return Less(*(a.Name), *(b.Name)); + } + }; // TElement + private: + TArrayHolder<TElement> Elements; + size_t Size; + public: - TCollection() - : Size(0) - { + TCollection() + : Size(0) + { } - TCollection(const TCollection& collection) + TCollection(const TCollection& collection) : Elements(new TElement[collection.Size]) - , Size(collection.Size) - { - for (int i = 0; i < Size; ++i) { - Elements[i] = collection.Elements[i]; - } + , Size(collection.Size) + { + for (int i = 0; i < Size; ++i) { + Elements[i] = collection.Elements[i]; + } } - TCollection(const TCollection& collection, T* name, G* counters) + TCollection(const TCollection& collection, T* name, G* counters) : Elements(new TElement[collection.Size + 1]) - , Size(collection.Size + 1) - { - for (size_t i = 0; i < Size - 1; ++i) { - Elements[i] = collection.Elements[i]; - } - Elements[Size - 1].Name = name; - Elements[Size - 1].Counters = counters; - for (size_t i = 1; i < Size; ++i) { - size_t j = i; - while (j > 0 && - TElement::Compare(Elements[j], Elements[j - 1])) { - std::swap(Elements[j], Elements[j - 1]); - --j; - } - } + , Size(collection.Size + 1) + { + for (size_t i = 0; i < Size - 1; ++i) { + Elements[i] = collection.Elements[i]; + } + Elements[Size - 1].Name = name; + Elements[Size - 1].Counters = counters; + for (size_t i = 1; i < Size; ++i) { + size_t j = i; + while (j > 0 && + TElement::Compare(Elements[j], Elements[j - 1])) { + std::swap(Elements[j], Elements[j - 1]); + --j; + } + } } - - G* Find(const T& name) const { - G* result = nullptr; - if (Size == 0) { - return nullptr; + + G* Find(const T& name) const { + G* result = nullptr; + if (Size == 0) { + return nullptr; } - size_t l = 0; - size_t r = Size - 1; - while (l < r) { - size_t m = (l + r) / 2; - if (Less(*(Elements[m].Name), name)) { - l = m + 1; - } else { - r = m; - } - } - if (!Less(*(Elements[l].Name), name) && !Less(name, *(Elements[l].Name))) { - result = Elements[l].Counters; - } - return result; + size_t l = 0; + size_t r = Size - 1; + while (l < r) { + size_t m = (l + r) / 2; + if (Less(*(Elements[m].Name), name)) { + l = m + 1; + } else { + r = m; + } + } + if (!Less(*(Elements[l].Name), name) && !Less(name, *(Elements[l].Name))) { + result = Elements[l].Counters; + } + return result; } - void Free() { - for (size_t i = 0; i < Size; ++i) { - T* name = Elements[i].Name; - G* counters = Elements[i].Counters; - Elements[i].Name = nullptr; - Elements[i].Counters = nullptr; - delete name; - delete counters; - } - Size = 0; + void Free() { + for (size_t i = 0; i < Size; ++i) { + T* name = Elements[i].Name; + G* counters = Elements[i].Counters; + Elements[i].Name = nullptr; + Elements[i].Counters = nullptr; + delete name; + delete counters; + } + Size = 0; } - - TGroupsNamesPtr GetNames() const { - TGroupsNamesPtr result(new TGroupsNames()); - for (size_t i = 0; i < Size; ++i) { - result->push_back(*(Elements[i].Name)); + + TGroupsNamesPtr GetNames() const { + TGroupsNamesPtr result(new TGroupsNames()); + for (size_t i = 0; i < Size; ++i) { + result->push_back(*(Elements[i].Name)); } - return result; + return result; } - }; // TCollection - struct TOldGroup { - TCollection* Collection; - ui64 Time; - }; - - private: - TCollection* Groups; - TList<TOldGroup> OldGroups; - TSpinLock AddMutex; - - ui64 Timeout; - - static TL Less; - - private: - G* Add(const T& name) { - TGuard<TSpinLock> guard(AddMutex); - G* result = Groups->Find(name); - if (result == nullptr) { - T* newName = new T(name); - G* newCounters = new G(); - TCollection* newGroups = - new TCollection(*Groups, newName, newCounters); - ui64 now = ::Now().MicroSeconds(); - TOldGroup group; - group.Collection = Groups; - group.Time = now; - OldGroups.push_back(group); - for (ui32 i = 0; i < 5; ++i) { - if (OldGroups.front().Time + Timeout < now) { - delete OldGroups.front().Collection; - OldGroups.front().Collection = nullptr; - OldGroups.pop_front(); - } else { - break; - } - } - Groups = newGroups; - result = Groups->Find(name); + }; // TCollection + struct TOldGroup { + TCollection* Collection; + ui64 Time; + }; + + private: + TCollection* Groups; + TList<TOldGroup> OldGroups; + TSpinLock AddMutex; + + ui64 Timeout; + + static TL Less; + + private: + G* Add(const T& name) { + TGuard<TSpinLock> guard(AddMutex); + G* result = Groups->Find(name); + if (result == nullptr) { + T* newName = new T(name); + G* newCounters = new G(); + TCollection* newGroups = + new TCollection(*Groups, newName, newCounters); + ui64 now = ::Now().MicroSeconds(); + TOldGroup group; + group.Collection = Groups; + group.Time = now; + OldGroups.push_back(group); + for (ui32 i = 0; i < 5; ++i) { + if (OldGroups.front().Time + Timeout < now) { + delete OldGroups.front().Collection; + OldGroups.front().Collection = nullptr; + OldGroups.pop_front(); + } else { + break; + } + } + Groups = newGroups; + result = Groups->Find(name); } return result; } - public: - TDeprecatedCounterGroups(ui64 timeout = 5 * 1000000L) { - Groups = new TCollection(); - Timeout = timeout; + public: + TDeprecatedCounterGroups(ui64 timeout = 5 * 1000000L) { + Groups = new TCollection(); + Timeout = timeout; } - virtual ~TDeprecatedCounterGroups() { - TGuard<TSpinLock> guard(AddMutex); - Groups->Free(); - delete Groups; - Groups = nullptr; - typename TList<TOldGroup>::iterator i; - for (i = OldGroups.begin(); i != OldGroups.end(); ++i) { - delete i->Collection; - i->Collection = nullptr; + virtual ~TDeprecatedCounterGroups() { + TGuard<TSpinLock> guard(AddMutex); + Groups->Free(); + delete Groups; + Groups = nullptr; + typename TList<TOldGroup>::iterator i; + for (i = OldGroups.begin(); i != OldGroups.end(); ++i) { + delete i->Collection; + i->Collection = nullptr; } - OldGroups.clear(); + OldGroups.clear(); } - bool Has(const T& name) const { - TCollection* groups = Groups; - return groups->Find(name) != nullptr; - } + bool Has(const T& name) const { + TCollection* groups = Groups; + return groups->Find(name) != nullptr; + } G* Find(const T& name) const { - TCollection* groups = Groups; - return groups->Find(name); + TCollection* groups = Groups; + return groups->Find(name); } - // Get group with the name, if it exists. - // If there is no group with the name, add new group. - G& Get(const T& name) { - G* result = Find(name); - if (result == nullptr) { - result = Add(name); - Y_ASSERT(result != nullptr); - } - return *result; + // Get group with the name, if it exists. + // If there is no group with the name, add new group. + G& Get(const T& name) { + G* result = Find(name); + if (result == nullptr) { + result = Add(name); + Y_ASSERT(result != nullptr); + } + return *result; } - // Get copy of groups names array. - TGroupsNamesPtr GetGroupsNames() const { - TCollection* groups = Groups; - TGroupsNamesPtr result = groups->GetNames(); - return result; + // Get copy of groups names array. + TGroupsNamesPtr GetGroupsNames() const { + TCollection* groups = Groups; + TGroupsNamesPtr result = groups->GetNames(); + return result; } - }; // TDeprecatedCounterGroups + }; // TDeprecatedCounterGroups - template <typename T, typename G, typename TL> - TL TDeprecatedCounterGroups<T, G, TL>::Less; -} + template <typename T, typename G, typename TL> + TL TDeprecatedCounterGroups<T, G, TL>::Less; +} -static inline IOutputStream& operator<<(IOutputStream& o, const NMonitoring::TDeprecatedCounter& rhs) { +static inline IOutputStream& operator<<(IOutputStream& o, const NMonitoring::TDeprecatedCounter& rhs) { return o << rhs.Val(); } template <size_t N> -static inline IOutputStream& operator<<(IOutputStream& o, const std::array<NMonitoring::TDeprecatedCounter, N>& rhs) { - for (typename std::array<NMonitoring::TDeprecatedCounter, N>::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { +static inline IOutputStream& operator<<(IOutputStream& o, const std::array<NMonitoring::TDeprecatedCounter, N>& rhs) { + for (typename std::array<NMonitoring::TDeprecatedCounter, N>::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { if (!!*it) o << *it << Endl; } diff --git a/library/cpp/monlib/counters/counters_ut.cpp b/library/cpp/monlib/counters/counters_ut.cpp index cd006fab2f..2845efb97b 100644 --- a/library/cpp/monlib/counters/counters_ut.cpp +++ b/library/cpp/monlib/counters/counters_ut.cpp @@ -1,49 +1,49 @@ -#include "counters.h" - +#include "counters.h" + #include <library/cpp/testing/unittest/registar.h> - -#include <util/generic/set.h> + +#include <util/generic/set.h> #include <util/thread/pool.h> - -using namespace NMonitoring; - -Y_UNIT_TEST_SUITE(TDeprecatedCountersTest) { + +using namespace NMonitoring; + +Y_UNIT_TEST_SUITE(TDeprecatedCountersTest) { Y_UNIT_TEST(CounterGroupsAreThreadSafe) { - const static ui32 GROUPS_COUNT = 1000; - const static ui32 THREADS_COUNT = 10; - - TDeprecatedCounterGroups<ui32, ui32> groups; - - auto adder = [&groups]() { - for (ui32 id = 0; id < GROUPS_COUNT; id++) { - groups.Get(id); - - // adds contention - ::NanoSleep(42); - } - }; - + const static ui32 GROUPS_COUNT = 1000; + const static ui32 THREADS_COUNT = 10; + + TDeprecatedCounterGroups<ui32, ui32> groups; + + auto adder = [&groups]() { + for (ui32 id = 0; id < GROUPS_COUNT; id++) { + groups.Get(id); + + // adds contention + ::NanoSleep(42); + } + }; + TThreadPool q; - q.Start(THREADS_COUNT); - for (ui32 i = 0; i < THREADS_COUNT; i++) { - q.SafeAddFunc(adder); - } - q.Stop(); - - // each group id is present - for (ui32 id = 0; id < GROUPS_COUNT; id++) { - UNIT_ASSERT(groups.Has(id)); - } - - // group names contains only appropriate ids - auto ids = groups.GetGroupsNames(); - for (ui32 id : *ids) { - UNIT_ASSERT(id < GROUPS_COUNT); - } - - // no duplication in group names + q.Start(THREADS_COUNT); + for (ui32 i = 0; i < THREADS_COUNT; i++) { + q.SafeAddFunc(adder); + } + q.Stop(); + + // each group id is present + for (ui32 id = 0; id < GROUPS_COUNT; id++) { + UNIT_ASSERT(groups.Has(id)); + } + + // group names contains only appropriate ids + auto ids = groups.GetGroupsNames(); + for (ui32 id : *ids) { + UNIT_ASSERT(id < GROUPS_COUNT); + } + + // no duplication in group names TSet<ui32> uniqueIds(ids->begin(), ids->end()); - UNIT_ASSERT_EQUAL(ids->size(), uniqueIds.size()); - UNIT_ASSERT_EQUAL(ids->size(), GROUPS_COUNT); - } -} + UNIT_ASSERT_EQUAL(ids->size(), uniqueIds.size()); + UNIT_ASSERT_EQUAL(ids->size(), GROUPS_COUNT); + } +} diff --git a/library/cpp/monlib/counters/histogram.cpp b/library/cpp/monlib/counters/histogram.cpp index 6a9d7a1f0b..46cf4e6ec8 100644 --- a/library/cpp/monlib/counters/histogram.cpp +++ b/library/cpp/monlib/counters/histogram.cpp @@ -1,40 +1,40 @@ -#include "histogram.h" - -namespace NMonitoring { - void THistogramSnapshot::Print(IOutputStream* out) const { - (*out) << "mean: " << Mean - << ", stddev: " << StdDeviation - << ", min: " << Min - << ", max: " << Max - << ", 50%: " << Percentile50 - << ", 75%: " << Percentile75 - << ", 90%: " << Percentile90 - << ", 95%: " << Percentile95 - << ", 98%: " << Percentile98 - << ", 99%: " << Percentile99 +#include "histogram.h" + +namespace NMonitoring { + void THistogramSnapshot::Print(IOutputStream* out) const { + (*out) << "mean: " << Mean + << ", stddev: " << StdDeviation + << ", min: " << Min + << ", max: " << Max + << ", 50%: " << Percentile50 + << ", 75%: " << Percentile75 + << ", 90%: " << Percentile90 + << ", 95%: " << Percentile95 + << ", 98%: " << Percentile98 + << ", 99%: " << Percentile99 << ", 99.9%: " << Percentile999 << ", count: " << TotalCount; - } - - void THdrHistogram::TakeSnaphot(THistogramSnapshot* snapshot) { - with_lock (Lock_) { - // TODO: get data with single traverse - snapshot->Mean = Data_.GetMean(); - snapshot->StdDeviation = Data_.GetStdDeviation(); - snapshot->Min = Data_.GetMin(); - snapshot->Max = Data_.GetMax(); - snapshot->Percentile50 = Data_.GetValueAtPercentile(50.0); - snapshot->Percentile75 = Data_.GetValueAtPercentile(75.0); - snapshot->Percentile90 = Data_.GetValueAtPercentile(90.0); - snapshot->Percentile95 = Data_.GetValueAtPercentile(95.0); - snapshot->Percentile98 = Data_.GetValueAtPercentile(98.0); - snapshot->Percentile99 = Data_.GetValueAtPercentile(99.0); - snapshot->Percentile999 = Data_.GetValueAtPercentile(99.9); + } + + void THdrHistogram::TakeSnaphot(THistogramSnapshot* snapshot) { + with_lock (Lock_) { + // TODO: get data with single traverse + snapshot->Mean = Data_.GetMean(); + snapshot->StdDeviation = Data_.GetStdDeviation(); + snapshot->Min = Data_.GetMin(); + snapshot->Max = Data_.GetMax(); + snapshot->Percentile50 = Data_.GetValueAtPercentile(50.0); + snapshot->Percentile75 = Data_.GetValueAtPercentile(75.0); + snapshot->Percentile90 = Data_.GetValueAtPercentile(90.0); + snapshot->Percentile95 = Data_.GetValueAtPercentile(95.0); + snapshot->Percentile98 = Data_.GetValueAtPercentile(98.0); + snapshot->Percentile99 = Data_.GetValueAtPercentile(99.0); + snapshot->Percentile999 = Data_.GetValueAtPercentile(99.9); snapshot->TotalCount = Data_.GetTotalCount(); - - // cleanup histogram data - Data_.Reset(); - } - } - -} + + // cleanup histogram data + Data_.Reset(); + } + } + +} diff --git a/library/cpp/monlib/counters/histogram.h b/library/cpp/monlib/counters/histogram.h index e6bc625daf..96361b0023 100644 --- a/library/cpp/monlib/counters/histogram.h +++ b/library/cpp/monlib/counters/histogram.h @@ -1,189 +1,189 @@ -#pragma once - +#pragma once + #include <library/cpp/histogram/hdr/histogram.h> - -#include <util/system/spinlock.h> -#include <util/stream/output.h> - -namespace NMonitoring { - /** - * A statistical snapshot of values recorded in histogram. - */ - struct THistogramSnapshot { - double Mean; - double StdDeviation; - i64 Min; - i64 Max; - i64 Percentile50; - i64 Percentile75; - i64 Percentile90; - i64 Percentile95; - i64 Percentile98; - i64 Percentile99; - i64 Percentile999; + +#include <util/system/spinlock.h> +#include <util/stream/output.h> + +namespace NMonitoring { + /** + * A statistical snapshot of values recorded in histogram. + */ + struct THistogramSnapshot { + double Mean; + double StdDeviation; + i64 Min; + i64 Max; + i64 Percentile50; + i64 Percentile75; + i64 Percentile90; + i64 Percentile95; + i64 Percentile98; + i64 Percentile99; + i64 Percentile999; i64 TotalCount; - - void Print(IOutputStream* out) const; - }; - - /** - * Special counter which calculates the distribution of a value. - */ - class THdrHistogram { - public: - /** - * Construct a histogram given the Lowest and Highest values to be tracked - * and a number of significant decimal digits. Providing a - * lowestDiscernibleValue is useful in situations where the units used for - * the histogram's values are much smaller that the minimal accuracy - * required. E.g. when tracking time values stated in nanosecond units, - * where the minimal accuracy required is a microsecond, the proper value - * for lowestDiscernibleValue would be 1000. - * - * @param lowestDiscernibleValue The lowest value that can be discerned - * (distinguished from 0) by the histogram. Must be a positive - * integer that is >= 1. May be internally rounded down to nearest - * power of 2. - * - * @param highestTrackableValue The highest value to be tracked by the - * histogram. Must be a positive integer that is - * >= (2 * lowestDiscernibleValue). - * - * @param numberOfSignificantValueDigits Specifies the precision to use. - * This is the number of significant decimal digits to which the - * histogram will maintain value resolution and separation. Must be - * a non-negative integer between 0 and 5. - */ - THdrHistogram(i64 lowestDiscernibleValue, i64 highestTrackableValue, - i32 numberOfSignificantValueDigits) - : Data_(lowestDiscernibleValue, highestTrackableValue, - numberOfSignificantValueDigits) { - } - - /** - * Records a value in the histogram, will round this value of to a - * precision at or better than the NumberOfSignificantValueDigits specified - * at construction time. - * - * @param value Value to add to the histogram - * @return false if the value is larger than the HighestTrackableValue - * and can't be recorded, true otherwise. - */ - bool RecordValue(i64 value) { - with_lock (Lock_) { - return Data_.RecordValue(value); - } - } - - /** - * Records count values in the histogram, will round this value of to a - * precision at or better than the NumberOfSignificantValueDigits specified - * at construction time. - * - * @param value Value to add to the histogram - * @param count Number of values to add to the histogram - * @return false if the value is larger than the HighestTrackableValue - * and can't be recorded, true otherwise. - */ - bool RecordValues(i64 value, i64 count) { - with_lock (Lock_) { - return Data_.RecordValues(value, count); - } - } - - /** - * Records a value in the histogram and backfill based on an expected - * interval. Value will be rounded this to a precision at or better - * than the NumberOfSignificantValueDigits specified at contruction time. - * This is specifically used for recording latency. If the value is larger - * than the expectedInterval then the latency recording system has - * experienced co-ordinated omission. This method fills in the values that - * would have occured had the client providing the load not been blocked. - * - * @param value Value to add to the histogram - * @param expectedInterval The delay between recording values - * @return false if the value is larger than the HighestTrackableValue - * and can't be recorded, true otherwise. - */ - bool RecordValueWithExpectedInterval(i64 value, i64 expectedInterval) { - with_lock (Lock_) { - return Data_.RecordValueWithExpectedInterval(value, expectedInterval); - } - } - - /** - * Record a value in the histogram count times. Applies the same correcting - * logic as {@link THdrHistogram::RecordValueWithExpectedInterval}. - * - * @param value Value to add to the histogram - * @param count Number of values to add to the histogram - * @param expectedInterval The delay between recording values. - * @return false if the value is larger than the HighestTrackableValue - * and can't be recorded, true otherwise. - */ - bool RecordValuesWithExpectedInterval( - i64 value, i64 count, i64 expectedInterval) { - with_lock (Lock_) { - return Data_.RecordValuesWithExpectedInterval( - value, count, expectedInterval); - } - } - - /** - * @return The configured lowestDiscernibleValue - */ - i64 GetLowestDiscernibleValue() const { - with_lock (Lock_) { - return Data_.GetLowestDiscernibleValue(); - } - } - - /** - * @return The configured highestTrackableValue - */ - i64 GetHighestTrackableValue() const { - with_lock (Lock_) { - return Data_.GetHighestTrackableValue(); - } - } - - /** - * @return The configured numberOfSignificantValueDigits - */ - i32 GetNumberOfSignificantValueDigits() const { - with_lock (Lock_) { - return Data_.GetNumberOfSignificantValueDigits(); - } - } - - /** - * @return The total count of all recorded values in the histogram - */ - i64 GetTotalCount() const { - with_lock (Lock_) { - return Data_.GetTotalCount(); - } - } - - /** - * Place a copy of the value counts accumulated since the last snapshot - * was taken into {@code snapshot}. Calling this member-function will - * reset the value counts, and start accumulating value counts for the - * next interval. - * - * @param snapshot the structure into which the values should be copied. - */ - void TakeSnaphot(THistogramSnapshot* snapshot); - - private: - mutable TSpinLock Lock_; - NHdr::THistogram Data_; - }; - -} - -template <> -inline void Out<NMonitoring::THistogramSnapshot>( - IOutputStream& out, const NMonitoring::THistogramSnapshot& snapshot) { - snapshot.Print(&out); -} + + void Print(IOutputStream* out) const; + }; + + /** + * Special counter which calculates the distribution of a value. + */ + class THdrHistogram { + public: + /** + * Construct a histogram given the Lowest and Highest values to be tracked + * and a number of significant decimal digits. Providing a + * lowestDiscernibleValue is useful in situations where the units used for + * the histogram's values are much smaller that the minimal accuracy + * required. E.g. when tracking time values stated in nanosecond units, + * where the minimal accuracy required is a microsecond, the proper value + * for lowestDiscernibleValue would be 1000. + * + * @param lowestDiscernibleValue The lowest value that can be discerned + * (distinguished from 0) by the histogram. Must be a positive + * integer that is >= 1. May be internally rounded down to nearest + * power of 2. + * + * @param highestTrackableValue The highest value to be tracked by the + * histogram. Must be a positive integer that is + * >= (2 * lowestDiscernibleValue). + * + * @param numberOfSignificantValueDigits Specifies the precision to use. + * This is the number of significant decimal digits to which the + * histogram will maintain value resolution and separation. Must be + * a non-negative integer between 0 and 5. + */ + THdrHistogram(i64 lowestDiscernibleValue, i64 highestTrackableValue, + i32 numberOfSignificantValueDigits) + : Data_(lowestDiscernibleValue, highestTrackableValue, + numberOfSignificantValueDigits) { + } + + /** + * Records a value in the histogram, will round this value of to a + * precision at or better than the NumberOfSignificantValueDigits specified + * at construction time. + * + * @param value Value to add to the histogram + * @return false if the value is larger than the HighestTrackableValue + * and can't be recorded, true otherwise. + */ + bool RecordValue(i64 value) { + with_lock (Lock_) { + return Data_.RecordValue(value); + } + } + + /** + * Records count values in the histogram, will round this value of to a + * precision at or better than the NumberOfSignificantValueDigits specified + * at construction time. + * + * @param value Value to add to the histogram + * @param count Number of values to add to the histogram + * @return false if the value is larger than the HighestTrackableValue + * and can't be recorded, true otherwise. + */ + bool RecordValues(i64 value, i64 count) { + with_lock (Lock_) { + return Data_.RecordValues(value, count); + } + } + + /** + * Records a value in the histogram and backfill based on an expected + * interval. Value will be rounded this to a precision at or better + * than the NumberOfSignificantValueDigits specified at contruction time. + * This is specifically used for recording latency. If the value is larger + * than the expectedInterval then the latency recording system has + * experienced co-ordinated omission. This method fills in the values that + * would have occured had the client providing the load not been blocked. + * + * @param value Value to add to the histogram + * @param expectedInterval The delay between recording values + * @return false if the value is larger than the HighestTrackableValue + * and can't be recorded, true otherwise. + */ + bool RecordValueWithExpectedInterval(i64 value, i64 expectedInterval) { + with_lock (Lock_) { + return Data_.RecordValueWithExpectedInterval(value, expectedInterval); + } + } + + /** + * Record a value in the histogram count times. Applies the same correcting + * logic as {@link THdrHistogram::RecordValueWithExpectedInterval}. + * + * @param value Value to add to the histogram + * @param count Number of values to add to the histogram + * @param expectedInterval The delay between recording values. + * @return false if the value is larger than the HighestTrackableValue + * and can't be recorded, true otherwise. + */ + bool RecordValuesWithExpectedInterval( + i64 value, i64 count, i64 expectedInterval) { + with_lock (Lock_) { + return Data_.RecordValuesWithExpectedInterval( + value, count, expectedInterval); + } + } + + /** + * @return The configured lowestDiscernibleValue + */ + i64 GetLowestDiscernibleValue() const { + with_lock (Lock_) { + return Data_.GetLowestDiscernibleValue(); + } + } + + /** + * @return The configured highestTrackableValue + */ + i64 GetHighestTrackableValue() const { + with_lock (Lock_) { + return Data_.GetHighestTrackableValue(); + } + } + + /** + * @return The configured numberOfSignificantValueDigits + */ + i32 GetNumberOfSignificantValueDigits() const { + with_lock (Lock_) { + return Data_.GetNumberOfSignificantValueDigits(); + } + } + + /** + * @return The total count of all recorded values in the histogram + */ + i64 GetTotalCount() const { + with_lock (Lock_) { + return Data_.GetTotalCount(); + } + } + + /** + * Place a copy of the value counts accumulated since the last snapshot + * was taken into {@code snapshot}. Calling this member-function will + * reset the value counts, and start accumulating value counts for the + * next interval. + * + * @param snapshot the structure into which the values should be copied. + */ + void TakeSnaphot(THistogramSnapshot* snapshot); + + private: + mutable TSpinLock Lock_; + NHdr::THistogram Data_; + }; + +} + +template <> +inline void Out<NMonitoring::THistogramSnapshot>( + IOutputStream& out, const NMonitoring::THistogramSnapshot& snapshot) { + snapshot.Print(&out); +} diff --git a/library/cpp/monlib/counters/histogram_ut.cpp b/library/cpp/monlib/counters/histogram_ut.cpp index 654994d12f..5a0800505a 100644 --- a/library/cpp/monlib/counters/histogram_ut.cpp +++ b/library/cpp/monlib/counters/histogram_ut.cpp @@ -1,47 +1,47 @@ -#include "histogram.h" - +#include "histogram.h" + #include <library/cpp/testing/unittest/registar.h> - -using namespace NMonitoring; - + +using namespace NMonitoring; + Y_UNIT_TEST_SUITE(THistorgamTest) { Y_UNIT_TEST(TakeSnapshot) { - THdrHistogram h(1, 10, 3); - UNIT_ASSERT(h.RecordValue(1)); - UNIT_ASSERT(h.RecordValue(2)); - UNIT_ASSERT(h.RecordValues(3, 10)); - UNIT_ASSERT(h.RecordValue(4)); - UNIT_ASSERT(h.RecordValue(5)); - - UNIT_ASSERT_EQUAL(h.GetTotalCount(), 14); - - THistogramSnapshot snapshot; - h.TakeSnaphot(&snapshot); - - UNIT_ASSERT_EQUAL(h.GetTotalCount(), 0); - - UNIT_ASSERT_EQUAL(snapshot.Min, 1); - UNIT_ASSERT_EQUAL(snapshot.Max, 5); - - // >>> a = [1, 2] + [3 for i in range(10)] + [4, 5] - // >>> numpy.mean(a) - // 3.0 - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.Mean, 3.0, 1e-6); - - // >>> numpy.std(a) - // 0.84515425472851657 - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.84515425472851657, 1e-6); - - // >>> [(p, round(numpy.percentile(a, p))) for p in [50, 75, 90, 95, 98, 99, 99.9, 100]] - // [(50, 3.0), (75, 3.0), (90, 4.0), (95, 4.0), (98, 5.0), (99, 5.0), (99.9, 5.0), (100, 5.0)] - UNIT_ASSERT_EQUAL(snapshot.Percentile50, 3); - UNIT_ASSERT_EQUAL(snapshot.Percentile75, 3); - UNIT_ASSERT_EQUAL(snapshot.Percentile90, 4); - UNIT_ASSERT_EQUAL(snapshot.Percentile95, 4); - UNIT_ASSERT_EQUAL(snapshot.Percentile98, 5); - UNIT_ASSERT_EQUAL(snapshot.Percentile99, 5); - UNIT_ASSERT_EQUAL(snapshot.Percentile999, 5); + THdrHistogram h(1, 10, 3); + UNIT_ASSERT(h.RecordValue(1)); + UNIT_ASSERT(h.RecordValue(2)); + UNIT_ASSERT(h.RecordValues(3, 10)); + UNIT_ASSERT(h.RecordValue(4)); + UNIT_ASSERT(h.RecordValue(5)); + + UNIT_ASSERT_EQUAL(h.GetTotalCount(), 14); + + THistogramSnapshot snapshot; + h.TakeSnaphot(&snapshot); + + UNIT_ASSERT_EQUAL(h.GetTotalCount(), 0); + + UNIT_ASSERT_EQUAL(snapshot.Min, 1); + UNIT_ASSERT_EQUAL(snapshot.Max, 5); + + // >>> a = [1, 2] + [3 for i in range(10)] + [4, 5] + // >>> numpy.mean(a) + // 3.0 + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.Mean, 3.0, 1e-6); + + // >>> numpy.std(a) + // 0.84515425472851657 + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.84515425472851657, 1e-6); + + // >>> [(p, round(numpy.percentile(a, p))) for p in [50, 75, 90, 95, 98, 99, 99.9, 100]] + // [(50, 3.0), (75, 3.0), (90, 4.0), (95, 4.0), (98, 5.0), (99, 5.0), (99.9, 5.0), (100, 5.0)] + UNIT_ASSERT_EQUAL(snapshot.Percentile50, 3); + UNIT_ASSERT_EQUAL(snapshot.Percentile75, 3); + UNIT_ASSERT_EQUAL(snapshot.Percentile90, 4); + UNIT_ASSERT_EQUAL(snapshot.Percentile95, 4); + UNIT_ASSERT_EQUAL(snapshot.Percentile98, 5); + UNIT_ASSERT_EQUAL(snapshot.Percentile99, 5); + UNIT_ASSERT_EQUAL(snapshot.Percentile999, 5); UNIT_ASSERT_EQUAL(snapshot.TotalCount, 14); - } -} + } +} diff --git a/library/cpp/monlib/counters/meter.cpp b/library/cpp/monlib/counters/meter.cpp index 2ecdb97666..6f15f173d1 100644 --- a/library/cpp/monlib/counters/meter.cpp +++ b/library/cpp/monlib/counters/meter.cpp @@ -1,4 +1,4 @@ -#include "meter.h" - -namespace NMonitoring { -} +#include "meter.h" + +namespace NMonitoring { +} diff --git a/library/cpp/monlib/counters/meter.h b/library/cpp/monlib/counters/meter.h index ea0bdad11f..1219f95c4d 100644 --- a/library/cpp/monlib/counters/meter.h +++ b/library/cpp/monlib/counters/meter.h @@ -1,285 +1,285 @@ -#pragma once - -#include <util/system/types.h> -#include <util/generic/noncopyable.h> -#include <util/system/atomic.h> - -#include <chrono> -#include <cstdlib> -#include <cmath> - -namespace NMonitoring { - /** - * An exponentially-weighted moving average. - * - * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf"> - * UNIX Load Average Part 1: How It Works</a> - * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf"> - * UNIX Load Average Part 2: Not Your Average Average</a> - * @see <a href="http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average">EMA</a> - */ - class TMovingAverage { - public: - enum { - INTERVAL = 5 // in seconds - }; - - public: - /** - * Creates a new EWMA which is equivalent to the UNIX one minute load - * average and which expects to be ticked every 5 seconds. - * - * @return a one-minute EWMA - */ - static TMovingAverage OneMinute() { - static const double M1_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 1); - return {M1_ALPHA, std::chrono::seconds(INTERVAL)}; - } - - /** - * Creates a new EWMA which is equivalent to the UNIX five minute load - * average and which expects to be ticked every 5 seconds. - * - * @return a five-minute EWMA - */ - static TMovingAverage FiveMinutes() { - static const double M5_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 5); - return {M5_ALPHA, std::chrono::seconds(INTERVAL)}; - } - - /** - * Creates a new EWMA which is equivalent to the UNIX fifteen minute load - * average and which expects to be ticked every 5 seconds. - * - * @return a fifteen-minute EWMA - */ - static TMovingAverage FifteenMinutes() { - static const double M15_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 15); - return {M15_ALPHA, std::chrono::seconds(INTERVAL)}; - } - - /** - * Create a new EWMA with a specific smoothing constant. - * - * @param alpha the smoothing constant - * @param interval the expected tick interval - */ - TMovingAverage(double alpha, std::chrono::seconds interval) - : Initialized_(0) - , Rate_(0) - , Uncounted_(0) - , Alpha_(alpha) - , Interval_(std::chrono::nanoseconds(interval).count()) - { - } - - TMovingAverage(const TMovingAverage& rhs) - : Initialized_(AtomicGet(rhs.Initialized_)) - , Rate_(AtomicGet(rhs.Rate_)) - , Uncounted_(AtomicGet(rhs.Uncounted_)) - , Alpha_(rhs.Alpha_) - , Interval_(rhs.Interval_) - { - } - - TMovingAverage& operator=(const TMovingAverage& rhs) { - AtomicSet(Initialized_, AtomicGet(Initialized_)); - AtomicSet(Rate_, AtomicGet(rhs.Rate_)); - AtomicSet(Uncounted_, AtomicGet(rhs.Uncounted_)); - Alpha_ = rhs.Alpha_; - Interval_ = rhs.Interval_; - return *this; - } - - /** - * Update the moving average with a new value. - * - * @param n the new value - */ - void Update(ui64 n = 1) { - AtomicAdd(Uncounted_, n); - } - - /** - * Mark the passage of time and decay the current rate accordingly. - */ - void Tick() { - double instantRate = AtomicSwap(&Uncounted_, 0) / Interval_; - if (AtomicGet(Initialized_)) { - double rate = AsDouble(AtomicGet(Rate_)); - rate += (Alpha_ * (instantRate - rate)); - AtomicSet(Rate_, AsAtomic(rate)); - } else { - AtomicSet(Rate_, AsAtomic(instantRate)); - AtomicSet(Initialized_, 1); - } - } - - /** - * @return the rate in the seconds - */ - double GetRate() const { - double rate = AsDouble(AtomicGet(Rate_)); - return rate * std::nano::den; - } - - private: - static double AsDouble(TAtomicBase val) { - union { - double D; - TAtomicBase A; - } doubleAtomic; - doubleAtomic.A = val; - return doubleAtomic.D; - } - - static TAtomicBase AsAtomic(double val) { - union { - double D; - TAtomicBase A; - } doubleAtomic; - doubleAtomic.D = val; - return doubleAtomic.A; - } - - private: - TAtomic Initialized_; - TAtomic Rate_; - TAtomic Uncounted_; - double Alpha_; - double Interval_; - }; - - /** - * A meter metric which measures mean throughput and one-, five-, and - * fifteen-minute exponentially-weighted moving average throughputs. - */ - template <typename TClock> - class TMeterImpl: private TNonCopyable { - public: - TMeterImpl() - : StartTime_(TClock::now()) - , LastTick_(StartTime_.time_since_epoch().count()) - , Count_(0) - , OneMinuteRate_(TMovingAverage::OneMinute()) - , FiveMinutesRate_(TMovingAverage::FiveMinutes()) - , FifteenMinutesRate_(TMovingAverage::FifteenMinutes()) - { - } - - /** - * Mark the occurrence of events. - * - * @param n the number of events - */ - void Mark(ui64 n = 1) { - TickIfNecessary(); - AtomicAdd(Count_, n); - OneMinuteRate_.Update(n); - FiveMinutesRate_.Update(n); - FifteenMinutesRate_.Update(n); - } - - /** - * Returns the one-minute exponentially-weighted moving average rate at - * which events have occurred since the meter was created. - * - * This rate has the same exponential decay factor as the one-minute load - * average in the top Unix command. - * - * @return the one-minute exponentially-weighted moving average rate at - * which events have occurred since the meter was created - */ - double GetOneMinuteRate() const { - return OneMinuteRate_.GetRate(); - } - - /** - * Returns the five-minute exponentially-weighted moving average rate at - * which events have occurred since the meter was created. - * - * This rate has the same exponential decay factor as the five-minute load - * average in the top Unix command. - * - * @return the five-minute exponentially-weighted moving average rate at - * which events have occurred since the meter was created - */ - double GetFiveMinutesRate() const { - return FiveMinutesRate_.GetRate(); - } - - /** - * Returns the fifteen-minute exponentially-weighted moving average rate - * at which events have occurred since the meter was created. - * - * This rate has the same exponential decay factor as the fifteen-minute - * load average in the top Unix command. - * - * @return the fifteen-minute exponentially-weighted moving average rate - * at which events have occurred since the meter was created - */ - double GetFifteenMinutesRate() const { - return FifteenMinutesRate_.GetRate(); - } - - /** - * @return the mean rate at which events have occurred since the meter - * was created - */ - double GetMeanRate() const { - if (GetCount() == 0) { - return 0.0; - } - - auto now = TClock::now(); - std::chrono::duration<double> elapsedSeconds = now - StartTime_; - return GetCount() / elapsedSeconds.count(); - } - - /** - * @return the number of events which have been marked - */ - ui64 GetCount() const { - return AtomicGet(Count_); - } - - private: - void TickIfNecessary() { - static ui64 TICK_INTERVAL_NS = - std::chrono::nanoseconds( - std::chrono::seconds(TMovingAverage::INTERVAL)) - .count(); - - auto oldTickNs = AtomicGet(LastTick_); - auto newTickNs = TClock::now().time_since_epoch().count(); - ui64 elapsedNs = std::abs(newTickNs - oldTickNs); - - if (elapsedNs > TICK_INTERVAL_NS) { - // adjust to interval begining - newTickNs -= elapsedNs % TICK_INTERVAL_NS; - if (AtomicCas(&LastTick_, newTickNs, oldTickNs)) { - ui64 requiredTicks = elapsedNs / TICK_INTERVAL_NS; - for (ui64 i = 0; i < requiredTicks; ++i) { - OneMinuteRate_.Tick(); - FiveMinutesRate_.Tick(); - FifteenMinutesRate_.Tick(); - } - } - } - } - - private: - const typename TClock::time_point StartTime_; - TAtomic LastTick_; - TAtomic Count_; - TMovingAverage OneMinuteRate_; - TMovingAverage FiveMinutesRate_; - TMovingAverage FifteenMinutesRate_; - }; - - using TSystemMeter = TMeterImpl<std::chrono::system_clock>; - using TSteadyMeter = TMeterImpl<std::chrono::steady_clock>; - using THighResMeter = TMeterImpl<std::chrono::high_resolution_clock>; - using TMeter = THighResMeter; - -} +#pragma once + +#include <util/system/types.h> +#include <util/generic/noncopyable.h> +#include <util/system/atomic.h> + +#include <chrono> +#include <cstdlib> +#include <cmath> + +namespace NMonitoring { + /** + * An exponentially-weighted moving average. + * + * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf"> + * UNIX Load Average Part 1: How It Works</a> + * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf"> + * UNIX Load Average Part 2: Not Your Average Average</a> + * @see <a href="http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average">EMA</a> + */ + class TMovingAverage { + public: + enum { + INTERVAL = 5 // in seconds + }; + + public: + /** + * Creates a new EWMA which is equivalent to the UNIX one minute load + * average and which expects to be ticked every 5 seconds. + * + * @return a one-minute EWMA + */ + static TMovingAverage OneMinute() { + static const double M1_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 1); + return {M1_ALPHA, std::chrono::seconds(INTERVAL)}; + } + + /** + * Creates a new EWMA which is equivalent to the UNIX five minute load + * average and which expects to be ticked every 5 seconds. + * + * @return a five-minute EWMA + */ + static TMovingAverage FiveMinutes() { + static const double M5_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 5); + return {M5_ALPHA, std::chrono::seconds(INTERVAL)}; + } + + /** + * Creates a new EWMA which is equivalent to the UNIX fifteen minute load + * average and which expects to be ticked every 5 seconds. + * + * @return a fifteen-minute EWMA + */ + static TMovingAverage FifteenMinutes() { + static const double M15_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 15); + return {M15_ALPHA, std::chrono::seconds(INTERVAL)}; + } + + /** + * Create a new EWMA with a specific smoothing constant. + * + * @param alpha the smoothing constant + * @param interval the expected tick interval + */ + TMovingAverage(double alpha, std::chrono::seconds interval) + : Initialized_(0) + , Rate_(0) + , Uncounted_(0) + , Alpha_(alpha) + , Interval_(std::chrono::nanoseconds(interval).count()) + { + } + + TMovingAverage(const TMovingAverage& rhs) + : Initialized_(AtomicGet(rhs.Initialized_)) + , Rate_(AtomicGet(rhs.Rate_)) + , Uncounted_(AtomicGet(rhs.Uncounted_)) + , Alpha_(rhs.Alpha_) + , Interval_(rhs.Interval_) + { + } + + TMovingAverage& operator=(const TMovingAverage& rhs) { + AtomicSet(Initialized_, AtomicGet(Initialized_)); + AtomicSet(Rate_, AtomicGet(rhs.Rate_)); + AtomicSet(Uncounted_, AtomicGet(rhs.Uncounted_)); + Alpha_ = rhs.Alpha_; + Interval_ = rhs.Interval_; + return *this; + } + + /** + * Update the moving average with a new value. + * + * @param n the new value + */ + void Update(ui64 n = 1) { + AtomicAdd(Uncounted_, n); + } + + /** + * Mark the passage of time and decay the current rate accordingly. + */ + void Tick() { + double instantRate = AtomicSwap(&Uncounted_, 0) / Interval_; + if (AtomicGet(Initialized_)) { + double rate = AsDouble(AtomicGet(Rate_)); + rate += (Alpha_ * (instantRate - rate)); + AtomicSet(Rate_, AsAtomic(rate)); + } else { + AtomicSet(Rate_, AsAtomic(instantRate)); + AtomicSet(Initialized_, 1); + } + } + + /** + * @return the rate in the seconds + */ + double GetRate() const { + double rate = AsDouble(AtomicGet(Rate_)); + return rate * std::nano::den; + } + + private: + static double AsDouble(TAtomicBase val) { + union { + double D; + TAtomicBase A; + } doubleAtomic; + doubleAtomic.A = val; + return doubleAtomic.D; + } + + static TAtomicBase AsAtomic(double val) { + union { + double D; + TAtomicBase A; + } doubleAtomic; + doubleAtomic.D = val; + return doubleAtomic.A; + } + + private: + TAtomic Initialized_; + TAtomic Rate_; + TAtomic Uncounted_; + double Alpha_; + double Interval_; + }; + + /** + * A meter metric which measures mean throughput and one-, five-, and + * fifteen-minute exponentially-weighted moving average throughputs. + */ + template <typename TClock> + class TMeterImpl: private TNonCopyable { + public: + TMeterImpl() + : StartTime_(TClock::now()) + , LastTick_(StartTime_.time_since_epoch().count()) + , Count_(0) + , OneMinuteRate_(TMovingAverage::OneMinute()) + , FiveMinutesRate_(TMovingAverage::FiveMinutes()) + , FifteenMinutesRate_(TMovingAverage::FifteenMinutes()) + { + } + + /** + * Mark the occurrence of events. + * + * @param n the number of events + */ + void Mark(ui64 n = 1) { + TickIfNecessary(); + AtomicAdd(Count_, n); + OneMinuteRate_.Update(n); + FiveMinutesRate_.Update(n); + FifteenMinutesRate_.Update(n); + } + + /** + * Returns the one-minute exponentially-weighted moving average rate at + * which events have occurred since the meter was created. + * + * This rate has the same exponential decay factor as the one-minute load + * average in the top Unix command. + * + * @return the one-minute exponentially-weighted moving average rate at + * which events have occurred since the meter was created + */ + double GetOneMinuteRate() const { + return OneMinuteRate_.GetRate(); + } + + /** + * Returns the five-minute exponentially-weighted moving average rate at + * which events have occurred since the meter was created. + * + * This rate has the same exponential decay factor as the five-minute load + * average in the top Unix command. + * + * @return the five-minute exponentially-weighted moving average rate at + * which events have occurred since the meter was created + */ + double GetFiveMinutesRate() const { + return FiveMinutesRate_.GetRate(); + } + + /** + * Returns the fifteen-minute exponentially-weighted moving average rate + * at which events have occurred since the meter was created. + * + * This rate has the same exponential decay factor as the fifteen-minute + * load average in the top Unix command. + * + * @return the fifteen-minute exponentially-weighted moving average rate + * at which events have occurred since the meter was created + */ + double GetFifteenMinutesRate() const { + return FifteenMinutesRate_.GetRate(); + } + + /** + * @return the mean rate at which events have occurred since the meter + * was created + */ + double GetMeanRate() const { + if (GetCount() == 0) { + return 0.0; + } + + auto now = TClock::now(); + std::chrono::duration<double> elapsedSeconds = now - StartTime_; + return GetCount() / elapsedSeconds.count(); + } + + /** + * @return the number of events which have been marked + */ + ui64 GetCount() const { + return AtomicGet(Count_); + } + + private: + void TickIfNecessary() { + static ui64 TICK_INTERVAL_NS = + std::chrono::nanoseconds( + std::chrono::seconds(TMovingAverage::INTERVAL)) + .count(); + + auto oldTickNs = AtomicGet(LastTick_); + auto newTickNs = TClock::now().time_since_epoch().count(); + ui64 elapsedNs = std::abs(newTickNs - oldTickNs); + + if (elapsedNs > TICK_INTERVAL_NS) { + // adjust to interval begining + newTickNs -= elapsedNs % TICK_INTERVAL_NS; + if (AtomicCas(&LastTick_, newTickNs, oldTickNs)) { + ui64 requiredTicks = elapsedNs / TICK_INTERVAL_NS; + for (ui64 i = 0; i < requiredTicks; ++i) { + OneMinuteRate_.Tick(); + FiveMinutesRate_.Tick(); + FifteenMinutesRate_.Tick(); + } + } + } + } + + private: + const typename TClock::time_point StartTime_; + TAtomic LastTick_; + TAtomic Count_; + TMovingAverage OneMinuteRate_; + TMovingAverage FiveMinutesRate_; + TMovingAverage FifteenMinutesRate_; + }; + + using TSystemMeter = TMeterImpl<std::chrono::system_clock>; + using TSteadyMeter = TMeterImpl<std::chrono::steady_clock>; + using THighResMeter = TMeterImpl<std::chrono::high_resolution_clock>; + using TMeter = THighResMeter; + +} diff --git a/library/cpp/monlib/counters/meter_ut.cpp b/library/cpp/monlib/counters/meter_ut.cpp index 39b1f0440a..b507d16fbd 100644 --- a/library/cpp/monlib/counters/meter_ut.cpp +++ b/library/cpp/monlib/counters/meter_ut.cpp @@ -1,41 +1,41 @@ -#include "meter.h" - +#include "meter.h" + #include <library/cpp/testing/unittest/registar.h> - -using namespace NMonitoring; - -struct TMockClock { - using duration = std::chrono::nanoseconds; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point<TMockClock, duration>; - - static time_point now() noexcept { - static int index = 0; - return index++ < 2 ? time_point() : time_point(std::chrono::seconds(10)); - } -}; - -using TMockMeter = TMeterImpl<TMockClock>; - + +using namespace NMonitoring; + +struct TMockClock { + using duration = std::chrono::nanoseconds; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point<TMockClock, duration>; + + static time_point now() noexcept { + static int index = 0; + return index++ < 2 ? time_point() : time_point(std::chrono::seconds(10)); + } +}; + +using TMockMeter = TMeterImpl<TMockClock>; + Y_UNIT_TEST_SUITE(TMeterTest) { Y_UNIT_TEST(StartsOutWithNoRatesOrCount) { - TMeter meter; - UNIT_ASSERT_EQUAL(meter.GetCount(), 0L); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.0, 0.0001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.0, 0.0001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.0, 0.0001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.0, 0.0001); - } - + TMeter meter; + UNIT_ASSERT_EQUAL(meter.GetCount(), 0L); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.0, 0.0001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.0, 0.0001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.0, 0.0001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.0, 0.0001); + } + Y_UNIT_TEST(MarksEventsAndUpdatesRatesAndCount) { - TMockMeter meter; - meter.Mark(); - meter.Mark(2); - UNIT_ASSERT_EQUAL(meter.GetCount(), 3L); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.3, 0.001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.1840, 0.0001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.1966, 0.0001); - UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.1988, 0.0001); - } -} + TMockMeter meter; + meter.Mark(); + meter.Mark(2); + UNIT_ASSERT_EQUAL(meter.GetCount(), 3L); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.3, 0.001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.1840, 0.0001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.1966, 0.0001); + UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.1988, 0.0001); + } +} diff --git a/library/cpp/monlib/counters/timer.h b/library/cpp/monlib/counters/timer.h index 5b234e0907..03dfb35337 100644 --- a/library/cpp/monlib/counters/timer.h +++ b/library/cpp/monlib/counters/timer.h @@ -1,176 +1,176 @@ -#pragma once - -#include "histogram.h" - +#pragma once + +#include "histogram.h" + #include <util/generic/scope.h> -#include <chrono> - -namespace NMonitoring { - /** - * A timer counter which aggregates timing durations and provides duration - * statistics in selected time resolution. - */ - template <typename TResolution> - class TTimerImpl { - public: - /** - * Construct a timer given the Lowest and Highest values to be tracked - * and a number of significant decimal digits. Providing a - * lowestDiscernibleValue is useful in situations where the units used for - * the timer's values are much smaller that the minimal accuracy - * required. E.g. when tracking time values stated in nanosecond units, - * where the minimal accuracy required is a microsecond, the proper value - * for lowestDiscernibleValue would be 1000. - * - * @param min The lowest value that can be discerned (distinguished from - * 0) by the timer. Must be a positive integer that is >= 1. - * May be internally rounded down to nearest power of 2. - * - * @param max The highest value to be tracked by the timer. Must be a - * positive integer that is >= (2 * min). - * - * @param numberOfSignificantValueDigits Specifies the precision to use. - * This is the number of significant decimal digits to which the - * timer will maintain value resolution and separation. Must be - * a non-negative integer between 0 and 5. - */ - TTimerImpl(ui64 min, ui64 max, i32 numberOfSignificantValueDigits = 3) - : TTimerImpl(TResolution(min), TResolution(max), - numberOfSignificantValueDigits) { - } - - /** - * Construct a timer given the Lowest and Highest values to be tracked - * and a number of significant decimal digits. - * - * @param min The lowest value that can be discerned (distinguished from - * 0) by the timer. - * - * @param max The highest value to be tracked by the histogram. Must be a - * positive integer that is >= (2 * min). - * - * @param numberOfSignificantValueDigits Specifies the precision to use. - */ - template <typename TDurationMin, typename TDurationMax> - TTimerImpl(TDurationMin min, TDurationMax max, - i32 numberOfSignificantValueDigits = 3) - : Histogram_(std::chrono::duration_cast<TResolution>(min).count(), - std::chrono::duration_cast<TResolution>(max).count(), - numberOfSignificantValueDigits) { - } - - /** - * Records a value in the timer with timer resulution. Recorded value will - * be rounded to a precision at or better than the - * NumberOfSignificantValueDigits specified at construction time. - * - * @param duration duration to add to the timer - * @return false if the value is larger than the max and can't be recorded, - * true otherwise. - */ - bool RecordValue(ui64 duration) { - return Histogram_.RecordValue(duration); - } - - /** - * Records a duration in the timer. Recorded value will be converted to - * the timer resulution and rounded to a precision at or better than the - * NumberOfSignificantValueDigits specified at construction time. - * - * @param duration duration to add to the timer - * @return false if the value is larger than the max and can't be recorded, - * true otherwise. - */ - template <typename TDuration> - bool RecordValue(TDuration duration) { - auto count = static_cast<ui64>( - std::chrono::duration_cast<TResolution>(duration).count()); - return RecordValue(count); - } - - /** - * Records count values in the timer with timer resulution. Recorded value will - * be rounded to a precision at or better than the - * NumberOfSignificantValueDigits specified at construction time. - * - * @param duration duration to add to the timer - * @param count number of values to add to the histogram - * @return false if the value is larger than the max and can't be recorded, - * true otherwise. - */ - bool RecordValues(ui64 duration, ui64 count) { - return Histogram_.RecordValues(duration, count); - } - - /** - * Measures a time of functor execution. - * - * @param fn functor whose duration should be timed - */ - template <typename TFunc> - void Measure(TFunc&& fn) { - using TClock = std::chrono::high_resolution_clock; - - auto start = TClock::now(); +#include <chrono> + +namespace NMonitoring { + /** + * A timer counter which aggregates timing durations and provides duration + * statistics in selected time resolution. + */ + template <typename TResolution> + class TTimerImpl { + public: + /** + * Construct a timer given the Lowest and Highest values to be tracked + * and a number of significant decimal digits. Providing a + * lowestDiscernibleValue is useful in situations where the units used for + * the timer's values are much smaller that the minimal accuracy + * required. E.g. when tracking time values stated in nanosecond units, + * where the minimal accuracy required is a microsecond, the proper value + * for lowestDiscernibleValue would be 1000. + * + * @param min The lowest value that can be discerned (distinguished from + * 0) by the timer. Must be a positive integer that is >= 1. + * May be internally rounded down to nearest power of 2. + * + * @param max The highest value to be tracked by the timer. Must be a + * positive integer that is >= (2 * min). + * + * @param numberOfSignificantValueDigits Specifies the precision to use. + * This is the number of significant decimal digits to which the + * timer will maintain value resolution and separation. Must be + * a non-negative integer between 0 and 5. + */ + TTimerImpl(ui64 min, ui64 max, i32 numberOfSignificantValueDigits = 3) + : TTimerImpl(TResolution(min), TResolution(max), + numberOfSignificantValueDigits) { + } + + /** + * Construct a timer given the Lowest and Highest values to be tracked + * and a number of significant decimal digits. + * + * @param min The lowest value that can be discerned (distinguished from + * 0) by the timer. + * + * @param max The highest value to be tracked by the histogram. Must be a + * positive integer that is >= (2 * min). + * + * @param numberOfSignificantValueDigits Specifies the precision to use. + */ + template <typename TDurationMin, typename TDurationMax> + TTimerImpl(TDurationMin min, TDurationMax max, + i32 numberOfSignificantValueDigits = 3) + : Histogram_(std::chrono::duration_cast<TResolution>(min).count(), + std::chrono::duration_cast<TResolution>(max).count(), + numberOfSignificantValueDigits) { + } + + /** + * Records a value in the timer with timer resulution. Recorded value will + * be rounded to a precision at or better than the + * NumberOfSignificantValueDigits specified at construction time. + * + * @param duration duration to add to the timer + * @return false if the value is larger than the max and can't be recorded, + * true otherwise. + */ + bool RecordValue(ui64 duration) { + return Histogram_.RecordValue(duration); + } + + /** + * Records a duration in the timer. Recorded value will be converted to + * the timer resulution and rounded to a precision at or better than the + * NumberOfSignificantValueDigits specified at construction time. + * + * @param duration duration to add to the timer + * @return false if the value is larger than the max and can't be recorded, + * true otherwise. + */ + template <typename TDuration> + bool RecordValue(TDuration duration) { + auto count = static_cast<ui64>( + std::chrono::duration_cast<TResolution>(duration).count()); + return RecordValue(count); + } + + /** + * Records count values in the timer with timer resulution. Recorded value will + * be rounded to a precision at or better than the + * NumberOfSignificantValueDigits specified at construction time. + * + * @param duration duration to add to the timer + * @param count number of values to add to the histogram + * @return false if the value is larger than the max and can't be recorded, + * true otherwise. + */ + bool RecordValues(ui64 duration, ui64 count) { + return Histogram_.RecordValues(duration, count); + } + + /** + * Measures a time of functor execution. + * + * @param fn functor whose duration should be timed + */ + template <typename TFunc> + void Measure(TFunc&& fn) { + using TClock = std::chrono::high_resolution_clock; + + auto start = TClock::now(); Y_SCOPE_EXIT(this, start) { - RecordValue(TClock::now() - start); - }; - - fn(); - } - - /** - * Place a copy of the value counts accumulated since the last snapshot - * was taken into {@code snapshot}. Calling this member-function will - * reset the value counts, and start accumulating value counts for the - * next interval. - * - * @param snapshot the structure into which the values should be copied. - */ - void TakeSnapshot(THistogramSnapshot* snapshot) { - Histogram_.TakeSnaphot(snapshot); - } - - private: - THdrHistogram Histogram_; - }; - - /** - * Timer template instantiations for certain time resolutions. - */ - using TTimerNs = TTimerImpl<std::chrono::nanoseconds>; - using TTimerUs = TTimerImpl<std::chrono::microseconds>; - using TTimerMs = TTimerImpl<std::chrono::milliseconds>; - using TTimerS = TTimerImpl<std::chrono::seconds>; - - /** - * A timing scope to record elapsed time since creation. - */ - template <typename TTimer, typename TFunc = std::function<void(std::chrono::high_resolution_clock::duration)>> - class TTimerScope { - using TClock = std::chrono::high_resolution_clock; - - public: - explicit TTimerScope(TTimer* timer, TFunc* callback = nullptr) - : Timer_(timer) - , StartTime_(TClock::now()) - , Callback_(callback) - { - } - - ~TTimerScope() { - TClock::duration duration = TClock::now() - StartTime_; - if (Callback_) { - (*Callback_)(duration); - } - Timer_->RecordValue(duration); + RecordValue(TClock::now() - start); + }; + + fn(); + } + + /** + * Place a copy of the value counts accumulated since the last snapshot + * was taken into {@code snapshot}. Calling this member-function will + * reset the value counts, and start accumulating value counts for the + * next interval. + * + * @param snapshot the structure into which the values should be copied. + */ + void TakeSnapshot(THistogramSnapshot* snapshot) { + Histogram_.TakeSnaphot(snapshot); + } + + private: + THdrHistogram Histogram_; + }; + + /** + * Timer template instantiations for certain time resolutions. + */ + using TTimerNs = TTimerImpl<std::chrono::nanoseconds>; + using TTimerUs = TTimerImpl<std::chrono::microseconds>; + using TTimerMs = TTimerImpl<std::chrono::milliseconds>; + using TTimerS = TTimerImpl<std::chrono::seconds>; + + /** + * A timing scope to record elapsed time since creation. + */ + template <typename TTimer, typename TFunc = std::function<void(std::chrono::high_resolution_clock::duration)>> + class TTimerScope { + using TClock = std::chrono::high_resolution_clock; + + public: + explicit TTimerScope(TTimer* timer, TFunc* callback = nullptr) + : Timer_(timer) + , StartTime_(TClock::now()) + , Callback_(callback) + { } - - private: - TTimer* Timer_; - TClock::time_point StartTime_; - TFunc* Callback_; - }; -} + + ~TTimerScope() { + TClock::duration duration = TClock::now() - StartTime_; + if (Callback_) { + (*Callback_)(duration); + } + Timer_->RecordValue(duration); + } + + private: + TTimer* Timer_; + TClock::time_point StartTime_; + TFunc* Callback_; + }; +} diff --git a/library/cpp/monlib/counters/timer_ut.cpp b/library/cpp/monlib/counters/timer_ut.cpp index f92d38a445..c5cd07e89d 100644 --- a/library/cpp/monlib/counters/timer_ut.cpp +++ b/library/cpp/monlib/counters/timer_ut.cpp @@ -1,14 +1,14 @@ -#include "timer.h" - +#include "timer.h" + #include <library/cpp/testing/unittest/registar.h> - -using namespace NMonitoring; -using namespace std::literals::chrono_literals; - + +using namespace NMonitoring; +using namespace std::literals::chrono_literals; + class TCallback { public: - explicit TCallback(int value) - : Value_(value){}; + explicit TCallback(int value) + : Value_(value){}; void operator()(std::chrono::high_resolution_clock::duration duration) { Value_ = duration.count(); }; @@ -18,50 +18,50 @@ public: Y_UNIT_TEST_SUITE(TTimerTest) { Y_UNIT_TEST(RecordValue) { - TTimerNs timerNs(1ns, 1s); - UNIT_ASSERT(timerNs.RecordValue(10us)); - - TTimerUs timerUs(1us, 1s); - UNIT_ASSERT(timerUs.RecordValue(10us)); - - THistogramSnapshot snapshot; - timerNs.TakeSnapshot(&snapshot); - UNIT_ASSERT_EQUAL(snapshot.Min, 10000); - UNIT_ASSERT_EQUAL(snapshot.Max, 10007); - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); - - timerUs.TakeSnapshot(&snapshot); - UNIT_ASSERT_EQUAL(snapshot.Min, 10); - UNIT_ASSERT_EQUAL(snapshot.Max, 10); - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); - } - + TTimerNs timerNs(1ns, 1s); + UNIT_ASSERT(timerNs.RecordValue(10us)); + + TTimerUs timerUs(1us, 1s); + UNIT_ASSERT(timerUs.RecordValue(10us)); + + THistogramSnapshot snapshot; + timerNs.TakeSnapshot(&snapshot); + UNIT_ASSERT_EQUAL(snapshot.Min, 10000); + UNIT_ASSERT_EQUAL(snapshot.Max, 10007); + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); + + timerUs.TakeSnapshot(&snapshot); + UNIT_ASSERT_EQUAL(snapshot.Min, 10); + UNIT_ASSERT_EQUAL(snapshot.Max, 10); + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); + } + Y_UNIT_TEST(Measure) { - TTimerNs timer(1ns, 1s); - timer.Measure([]() { - Sleep(TDuration::MilliSeconds(1)); - }); - THistogramSnapshot snapshot; - timer.TakeSnapshot(&snapshot); - - UNIT_ASSERT(snapshot.Min > std::chrono::nanoseconds(1ms).count()); - UNIT_ASSERT(snapshot.Max > std::chrono::nanoseconds(1ms).count()); - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); - } - + TTimerNs timer(1ns, 1s); + timer.Measure([]() { + Sleep(TDuration::MilliSeconds(1)); + }); + THistogramSnapshot snapshot; + timer.TakeSnapshot(&snapshot); + + UNIT_ASSERT(snapshot.Min > std::chrono::nanoseconds(1ms).count()); + UNIT_ASSERT(snapshot.Max > std::chrono::nanoseconds(1ms).count()); + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); + } + Y_UNIT_TEST(TimerScope) { - TTimerUs timer(1us, 1000s); - { - TTimerScope<TTimerUs> scope(&timer); - Sleep(TDuration::MilliSeconds(10)); - } - THistogramSnapshot snapshot; - timer.TakeSnapshot(&snapshot); - - UNIT_ASSERT(snapshot.Min > std::chrono::microseconds(10ms).count()); - UNIT_ASSERT(snapshot.Max > std::chrono::microseconds(10ms).count()); - UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); - } + TTimerUs timer(1us, 1000s); + { + TTimerScope<TTimerUs> scope(&timer); + Sleep(TDuration::MilliSeconds(10)); + } + THistogramSnapshot snapshot; + timer.TakeSnapshot(&snapshot); + + UNIT_ASSERT(snapshot.Min > std::chrono::microseconds(10ms).count()); + UNIT_ASSERT(snapshot.Max > std::chrono::microseconds(10ms).count()); + UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); + } Y_UNIT_TEST(TimerScopeWithCallback) { TCallback callback(0); @@ -78,4 +78,4 @@ Y_UNIT_TEST_SUITE(TTimerTest) { UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6); UNIT_ASSERT(callback.Value_ > std::chrono::microseconds(10ms).count()); } -} +} diff --git a/library/cpp/monlib/counters/ut/ya.make b/library/cpp/monlib/counters/ut/ya.make index 3c8540c67d..999dadb199 100644 --- a/library/cpp/monlib/counters/ut/ya.make +++ b/library/cpp/monlib/counters/ut/ya.make @@ -1,12 +1,12 @@ -UNITTEST_FOR(library/cpp/monlib/counters) - -OWNER(jamel) - -SRCS( - counters_ut.cpp - histogram_ut.cpp - meter_ut.cpp - timer_ut.cpp -) - -END() +UNITTEST_FOR(library/cpp/monlib/counters) + +OWNER(jamel) + +SRCS( + counters_ut.cpp + histogram_ut.cpp + meter_ut.cpp + timer_ut.cpp +) + +END() diff --git a/library/cpp/monlib/counters/ya.make b/library/cpp/monlib/counters/ya.make index d569608035..aa1a671bf8 100644 --- a/library/cpp/monlib/counters/ya.make +++ b/library/cpp/monlib/counters/ya.make @@ -1,15 +1,15 @@ -LIBRARY() - -OWNER(jamel) - -SRCS( - counters.cpp - histogram.cpp - meter.cpp -) - -PEERDIR( +LIBRARY() + +OWNER(jamel) + +SRCS( + counters.cpp + histogram.cpp + meter.cpp +) + +PEERDIR( library/cpp/histogram/hdr -) - -END() +) + +END() |