diff options
author | Vasily Gerasimov <UgnineSirdis@gmail.com> | 2022-02-10 16:49:09 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:09 +0300 |
commit | 6cdc8f140213c595e4ad38bc3d97fcef1146b8c3 (patch) | |
tree | f69637041e6fed76ebae0c74ae1fa0c4be6ab5b4 /library/cpp/sliding_window | |
parent | e5d4696304c6689379ac7ce334512404d4b7836c (diff) | |
download | ydb-6cdc8f140213c595e4ad38bc3d97fcef1146b8c3.tar.gz |
Restoring authorship annotation for Vasily Gerasimov <UgnineSirdis@gmail.com>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/sliding_window')
-rw-r--r-- | library/cpp/sliding_window/README.md | 58 | ||||
-rw-r--r-- | library/cpp/sliding_window/sliding_window.h | 64 | ||||
-rw-r--r-- | library/cpp/sliding_window/sliding_window_ut.cpp | 106 | ||||
-rw-r--r-- | library/cpp/sliding_window/ut/ya.make | 16 | ||||
-rw-r--r-- | library/cpp/sliding_window/ya.make | 20 |
5 files changed, 132 insertions, 132 deletions
diff --git a/library/cpp/sliding_window/README.md b/library/cpp/sliding_window/README.md index 47692da7d5..b9c952ba8e 100644 --- a/library/cpp/sliding_window/README.md +++ b/library/cpp/sliding_window/README.md @@ -1,30 +1,30 @@ -# TSlidingWindow - скользящее окно - +# TSlidingWindow - скользящее окно + [TSlidingWindow](/arc/trunk/arcadia/library/cpp/sliding_window/sliding_window.h) - класс скользящего окна, позволяющий поддерживать и обновлять определённое значение (максимум, сумму) в промежутке времени определённой длины. Разбивает общий временной промежуток на маленькие бакеты (число задаётся в конструкторе) и ротирует их, поддерживая значение за окно. Есть возможность также указать мьютекс или спинлок для синхронизации (по умолчанию TFakeMutex). Использование: - -``` -// Создаём окно, вычисляющее максимум за последние пять минут, поддерживая 50 бакетов со значениями. -TSlidingWindow<TMaxOperation<int>> window(TDuration::Minutes(5), 50); - -// Загружаем значения в различные моменты времени -window.Update(42, TInstant::Now()); - -... // делаем какую-то работу -int currentMaximum = window.Update(50, TInstant::Now()); - -... // делаем ещё что-то -int currentMaximum = window.Update(25, TInstant::Now()); - -... -// Просто получаем значение максимума за последние 5 минут -int currentMaximum = window.Update(TInstant::Now()); - -... -int currentMaximum = window.GetValue(); // получение значения без обновления времени -``` - -# Поддерживаемые функции - -* `TMaxOperation` - максимум -* `TMinOperation` - минимум -* `TSumOperation` - сумма + +``` +// Создаём окно, вычисляющее максимум за последние пять минут, поддерживая 50 бакетов со значениями. +TSlidingWindow<TMaxOperation<int>> window(TDuration::Minutes(5), 50); + +// Загружаем значения в различные моменты времени +window.Update(42, TInstant::Now()); + +... // делаем какую-то работу +int currentMaximum = window.Update(50, TInstant::Now()); + +... // делаем ещё что-то +int currentMaximum = window.Update(25, TInstant::Now()); + +... +// Просто получаем значение максимума за последние 5 минут +int currentMaximum = window.Update(TInstant::Now()); + +... +int currentMaximum = window.GetValue(); // получение значения без обновления времени +``` + +# Поддерживаемые функции + +* `TMaxOperation` - максимум +* `TMinOperation` - минимум +* `TSumOperation` - сумма diff --git a/library/cpp/sliding_window/sliding_window.h b/library/cpp/sliding_window/sliding_window.h index 180bdf93d0..d140ec7f9c 100644 --- a/library/cpp/sliding_window/sliding_window.h +++ b/library/cpp/sliding_window/sliding_window.h @@ -1,16 +1,16 @@ #pragma once -#include <util/datetime/base.h> -#include <util/generic/vector.h> -#include <util/system/guard.h> -#include <util/system/mutex.h> -#include <util/system/types.h> -#include <util/system/yassert.h> +#include <util/datetime/base.h> +#include <util/generic/vector.h> +#include <util/system/guard.h> +#include <util/system/mutex.h> +#include <util/system/types.h> +#include <util/system/yassert.h> -#include <functional> -#include <limits> +#include <functional> +#include <limits> -namespace NSlidingWindow { +namespace NSlidingWindow { namespace NPrivate { template <class TValueType_, class TCmp, TValueType_ initialValue> // std::less for max, std::greater for min struct TMinMaxOperationImpl { @@ -33,14 +33,14 @@ namespace NSlidingWindow { } } return windowValue; - } + } static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, const size_t firstElemIndex, const size_t bucketsToClear) { Y_ASSERT(!buckets.empty()); Y_ASSERT(firstElemIndex < buckets.size()); Y_ASSERT(bucketsToClear <= buckets.size()); TCmp cmp; - + bool needRecalc = false; size_t current = firstElemIndex; const size_t arraySize = buckets.size(); @@ -51,7 +51,7 @@ namespace NSlidingWindow { } curVal = InitialValue(); current = (current + 1) % arraySize; - } + } if (needRecalc) { windowValue = InitialValue(); for (size_t i = 0; i < firstElemIndex; ++i) { @@ -66,28 +66,28 @@ namespace NSlidingWindow { windowValue = val; } } - } + } return windowValue; - } + } }; - } + } template <class TValueType> using TMaxOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::less<TValueType>, std::numeric_limits<TValueType>::min()>; - + template <class TValueType> using TMinOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::greater<TValueType>, std::numeric_limits<TValueType>::max()>; - + template <class TValueType_> struct TSumOperation { using TValueType = TValueType_; using TValueVector = TVector<TValueType>; - + static constexpr TValueType InitialValue() { return TValueType(); // zero } - + // Updates value in current bucket and returns window value static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { Y_ASSERT(index < buckets.size()); @@ -95,12 +95,12 @@ namespace NSlidingWindow { windowValue += newVal; return windowValue; } - + static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) { Y_ASSERT(!buckets.empty()); Y_ASSERT(firstElemIndex < buckets.size()); Y_ASSERT(bucketsToClear <= buckets.size()); - + const size_t arraySize = buckets.size(); for (size_t i = 0; i < bucketsToClear; ++i) { TValueType& curVal = buckets[firstElemIndex]; @@ -145,17 +145,17 @@ namespace NSlidingWindow { Length = w.Length; MicroSecondsPerBucket = w.MicroSecondsPerBucket; } - + TSlidingWindow(TSlidingWindow&&) = default; - + TSlidingWindow& operator=(TSlidingWindow&&) = default; TSlidingWindow& operator=(const TSlidingWindow&) = delete; - + // Period of time const TDuration& GetDuration() const { return Length; } - + // Update window with new value and time TValueType Update(TValueType val, TInstant t) { TGuard<TMutexImpl> guard(&Mutex); @@ -163,14 +163,14 @@ namespace NSlidingWindow { UpdateCurrentBucket(val); return WindowValue; } - + // Update just time, without new values TValueType Update(TInstant t) { TGuard<TMutexImpl> guard(&Mutex); AdvanceTime(t); return WindowValue; } - + // Get current window value (without updating current time) TValueType GetValue() const { TGuard<TMutexImpl> guard(&Mutex); @@ -182,7 +182,7 @@ namespace NSlidingWindow { const TSizeType arraySize = Buckets.size(); const TSizeType pos = (FirstElem + arraySize - 1) % arraySize; WindowValue = TOperation::UpdateBucket(WindowValue, Buckets, pos, val); - } + } void AdvanceTime(const TInstant& time) { if (time < PeriodStart + Length) { @@ -193,24 +193,24 @@ namespace NSlidingWindow { PeriodStart = time - Length; return; } - + const TInstant& newPeriodStart = time - Length; const ui64 tmDiff = (newPeriodStart - PeriodStart).MicroSeconds(); const TSizeType bucketsDiff = tmDiff / MicroSecondsPerBucket; const TSizeType arraySize = Buckets.size(); const TSizeType buckets = Min(bucketsDiff, arraySize); - + WindowValue = TOperation::ClearBuckets(WindowValue, Buckets, FirstElem, buckets); FirstElem = (FirstElem + buckets) % arraySize; PeriodStart += TDuration::MicroSeconds(bucketsDiff * MicroSecondsPerBucket); - + // Check that PeriodStart lags behind newPeriodStart // (which is actual, uptodate, precise and equal to time - Length) not more // then MicroSecondsPerBucket Y_ASSERT(newPeriodStart >= PeriodStart); Y_ASSERT((newPeriodStart - PeriodStart).MicroSeconds() <= MicroSecondsPerBucket); } - + mutable TMutexImpl Mutex; TValueVector Buckets; diff --git a/library/cpp/sliding_window/sliding_window_ut.cpp b/library/cpp/sliding_window/sliding_window_ut.cpp index 1e7343a8d3..22814fadeb 100644 --- a/library/cpp/sliding_window/sliding_window_ut.cpp +++ b/library/cpp/sliding_window/sliding_window_ut.cpp @@ -2,131 +2,131 @@ #include <library/cpp/testing/unittest/registar.h> -using namespace NSlidingWindow; +using namespace NSlidingWindow; Y_UNIT_TEST_SUITE(TSlidingWindowTest) { Y_UNIT_TEST(TestSlidingWindowMax) { - TSlidingWindow<TMaxOperation<unsigned>> w(TDuration::Minutes(5), 5); + TSlidingWindow<TMaxOperation<unsigned>> w(TDuration::Minutes(5), 5); TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); - TInstant now = start; + TInstant now = start; w.Update(5, start); // ~ ~ ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1) + TDuration::Seconds(1); + now += TDuration::Minutes(1) + TDuration::Seconds(1); w.Update(5, now); // 5 ~ ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(3, now); // 5 3 ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(3); + now += TDuration::Minutes(3); w.Update(2, now); // 5 3 ~ ~ 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(2, now); // 2 3 ~ ~ 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(2, now); // 2 2 ~ ~ 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - now += TDuration::Minutes(5); + now += TDuration::Minutes(5); w.Update(1, now); // ~ 1 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ - // update current bucket + // update current bucket w.Update(2, now); // ~ 2 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - + w.Update(1, now + TDuration::Seconds(30)); // ~ 2 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - - // test idle - now += TDuration::Minutes(1); + + // test idle + now += TDuration::Minutes(1); w.Update(now); // ~ 2 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - + now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); + UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); } Y_UNIT_TEST(TestSlidingWindowMin) { - TSlidingWindow<TMinOperation<unsigned>> w(TDuration::Minutes(5), 5); + TSlidingWindow<TMinOperation<unsigned>> w(TDuration::Minutes(5), 5); TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); - TInstant now = start; + TInstant now = start; w.Update(5, start); // ~ ~ ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1) + TDuration::Seconds(1); + now += TDuration::Minutes(1) + TDuration::Seconds(1); w.Update(5, now); // 5 ~ ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(7, now); // 5 7 ~ ~ 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(3); + now += TDuration::Minutes(3); w.Update(8, now); // 5 7 ~ ~ 8 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(8, now); // 8 7 ~ ~ 8 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(8, now); // 8 8 ~ ~ 8 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 8); // ^ - now += TDuration::Minutes(5); + now += TDuration::Minutes(5); w.Update(6, now); // ~ 6 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ - // update current bucket + // update current bucket w.Update(5, now); // ~ 5 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - + w.Update(6, now + TDuration::Seconds(30)); // ~ 5 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - - // test idle - now += TDuration::Minutes(1); + + // test idle + now += TDuration::Minutes(1); w.Update(now); // ~ 5 ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - + now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.Update(now), std::numeric_limits<unsigned>::max()); - } - + UNIT_ASSERT_VALUES_EQUAL(w.Update(now), std::numeric_limits<unsigned>::max()); + } + Y_UNIT_TEST(TestSlidingWindowSum) { - TSlidingWindow<TSumOperation<unsigned>> w(TDuration::Minutes(5), 5); - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 0); // current sum - + TSlidingWindow<TSumOperation<unsigned>> w(TDuration::Minutes(5), 5); + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 0); // current sum + TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); - TInstant now = start; + TInstant now = start; w.Update(5, start); // 0 0 0 0 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(1) + TDuration::Seconds(1); + now += TDuration::Minutes(1) + TDuration::Seconds(1); w.Update(5, now); // 5 0 0 0 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(3, now); // 5 3 0 0 5 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 13); // ^ - now += TDuration::Minutes(3); + now += TDuration::Minutes(3); w.Update(2, now); // 5 3 0 0 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(2, now); // 2 3 0 0 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ - now += TDuration::Minutes(1); + now += TDuration::Minutes(1); w.Update(2, now); // 2 2 0 0 2 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ - now += TDuration::Minutes(5); + now += TDuration::Minutes(5); w.Update(1, now); // 0 1 0 0 0 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ - - // update current bucket + + // update current bucket w.Update(2, now); // 0 3 0 0 0 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ - + w.Update(1, now + TDuration::Seconds(30)); // 0 4 0 0 0 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ - - // test idle - now += TDuration::Minutes(1); + + // test idle + now += TDuration::Minutes(1); w.Update(now); // 0 4 0 0 0 UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ - + now += TDuration::Minutes(5); // 0 0 0 0 0 - UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); - } -} + UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); + } +} diff --git a/library/cpp/sliding_window/ut/ya.make b/library/cpp/sliding_window/ut/ya.make index 3839a8dadc..a82a24e5b7 100644 --- a/library/cpp/sliding_window/ut/ya.make +++ b/library/cpp/sliding_window/ut/ya.make @@ -1,9 +1,9 @@ UNITTEST_FOR(library/cpp/sliding_window) - -OWNER(g:kikimr) - -SRCS( - sliding_window_ut.cpp -) - -END() + +OWNER(g:kikimr) + +SRCS( + sliding_window_ut.cpp +) + +END() diff --git a/library/cpp/sliding_window/ya.make b/library/cpp/sliding_window/ya.make index 79aeaa06bb..948ffdcb26 100644 --- a/library/cpp/sliding_window/ya.make +++ b/library/cpp/sliding_window/ya.make @@ -1,10 +1,10 @@ -LIBRARY() - -OWNER(g:kikimr) - -SRCS( - sliding_window.cpp - sliding_window.h -) - -END() +LIBRARY() + +OWNER(g:kikimr) + +SRCS( + sliding_window.cpp + sliding_window.h +) + +END() |