aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/sliding_window
diff options
context:
space:
mode:
authorVasily Gerasimov <UgnineSirdis@gmail.com>2022-02-10 16:49:09 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:49:09 +0300
commit6cdc8f140213c595e4ad38bc3d97fcef1146b8c3 (patch)
treef69637041e6fed76ebae0c74ae1fa0c4be6ab5b4 /library/cpp/sliding_window
parente5d4696304c6689379ac7ce334512404d4b7836c (diff)
downloadydb-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.md58
-rw-r--r--library/cpp/sliding_window/sliding_window.h64
-rw-r--r--library/cpp/sliding_window/sliding_window_ut.cpp106
-rw-r--r--library/cpp/sliding_window/ut/ya.make16
-rw-r--r--library/cpp/sliding_window/ya.make20
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()