diff options
author | imsemenov00 <imsemenov00@yandex-team.ru> | 2022-02-10 16:50:34 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:50:34 +0300 |
commit | bfa8c3e83c12beb065db3c294bcad58628069502 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /library/cpp | |
parent | d8e4b5a95238ab8f48a54f35418a97403bf8070a (diff) | |
download | ydb-bfa8c3e83c12beb065db3c294bcad58628069502.tar.gz |
Restoring authorship annotation for <imsemenov00@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/bucket_quoter/ut/README.md | 40 | ||||
-rw-r--r-- | library/cpp/bucket_quoter/ut/main.cpp | 88 | ||||
-rw-r--r-- | library/cpp/bucket_quoter/ut/test_namespace.cpp | 26 | ||||
-rw-r--r-- | library/cpp/bucket_quoter/ut/test_namespace.h | 166 | ||||
-rw-r--r-- | library/cpp/bucket_quoter/ut/ya.make | 36 | ||||
-rw-r--r-- | library/cpp/bucket_quoter/ya.make | 4 |
6 files changed, 180 insertions, 180 deletions
diff --git a/library/cpp/bucket_quoter/ut/README.md b/library/cpp/bucket_quoter/ut/README.md index e844b0f526..a0db9f6239 100644 --- a/library/cpp/bucket_quoter/ut/README.md +++ b/library/cpp/bucket_quoter/ut/README.md @@ -1,20 +1,20 @@ -# Unit test для bucket_quoter - -Этот тест предназначен не для проверки корректности bucket_quoter, а для того, -чтобы показать некоторые его недостатки - -Первый недостаток: При вызове метода FillBucket, вычисляется количество токенов, -которое можно добавить в Bucket за время, прошедшее с последнего добавления. -Если это количество нецелое, то оно округляется вниз. Это может иметь значение для малых RPS. - -Второй недостаток: -При попытке получить время через GetWaitTime, возвращается не ближайшее время, когда станут доступны новые токены. -Возвращаемое время кратно (1 / RPS), выраженному в микросекундах. -Кроме того, из-за округления, метод может вернуть время, в котором новые токены все еще не смогут быть начислены. - -Написанный тест демонстрирует, что данные недостатки могут приводить значительному снижению -количества пропускаемых лимитером запросов(вплоть до двух раз в специальных условиях с искусственным таймером). - -Так же демонстрируется, что при использовании лимитера со стандартным таймером(TInstantTimerMs), RPS тоже может -достаточно далек от заданного. - +# Unit test для bucket_quoter + +Этот тест предназначен не для проверки корректности bucket_quoter, а для того, +чтобы показать некоторые его недостатки + +Первый недостаток: При вызове метода FillBucket, вычисляется количество токенов, +которое можно добавить в Bucket за время, прошедшее с последнего добавления. +Если это количество нецелое, то оно округляется вниз. Это может иметь значение для малых RPS. + +Второй недостаток: +При попытке получить время через GetWaitTime, возвращается не ближайшее время, когда станут доступны новые токены. +Возвращаемое время кратно (1 / RPS), выраженному в микросекундах. +Кроме того, из-за округления, метод может вернуть время, в котором новые токены все еще не смогут быть начислены. + +Написанный тест демонстрирует, что данные недостатки могут приводить значительному снижению +количества пропускаемых лимитером запросов(вплоть до двух раз в специальных условиях с искусственным таймером). + +Так же демонстрируется, что при использовании лимитера со стандартным таймером(TInstantTimerMs), RPS тоже может +достаточно далек от заданного. + diff --git a/library/cpp/bucket_quoter/ut/main.cpp b/library/cpp/bucket_quoter/ut/main.cpp index 85296b1072..9c86bace4e 100644 --- a/library/cpp/bucket_quoter/ut/main.cpp +++ b/library/cpp/bucket_quoter/ut/main.cpp @@ -1,44 +1,44 @@ -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/bucket_quoter/bucket_quoter.h> - -#include "test_namespace.h" - - -using NBucketQuoterTest::TMockTimer; - -#define TEST_RPS_EXACT(THREADS, RPS, EXPECTED_RESULT, TIMER) \ -Y_UNIT_TEST(Test##TIMER##RPS##Rps##THREADS##Threads) { \ - ui32 seconds = 10; \ - ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\ - (THREADS, RPS, seconds);\ - ui32 total_rps = summary_requests / seconds; \ - UNIT_ASSERT_EQUAL(total_rps, EXPECTED_RESULT);\ -} - -#define TEST_RPS_LESS(THREADS, RPS, UPPER_BOUND, TIMER) \ -Y_UNIT_TEST(Test##TIMER##RPS##rps##THREADS##threads) { \ - ui32 seconds = 10; \ - ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\ - (THREADS, RPS, seconds); \ - ui32 total_rps = summary_requests / seconds; \ - UNIT_ASSERT_LE(total_rps, UPPER_BOUND); \ -} - -Y_UNIT_TEST_SUITE(TMockTimerTest) { - TEST_RPS_EXACT(1, 100, 100, TMockTimer) - TEST_RPS_EXACT(1, 120, 60, TMockTimer) - TEST_RPS_EXACT(1, 200, 200, TMockTimer) - TEST_RPS_EXACT(1, 220, 110, TMockTimer) - TEST_RPS_EXACT(1, 240, 120, TMockTimer) - TEST_RPS_EXACT(1, 300, 150, TMockTimer) - TEST_RPS_EXACT(1, 320, 320, TMockTimer) - TEST_RPS_EXACT(1, 480, 240, TMockTimer) - -} - -Y_UNIT_TEST_SUITE(TInstantTimerTest) { - TEST_RPS_LESS(1, 360, 300, TInstantTimerMs) - TEST_RPS_LESS(1, 480, 400, TInstantTimerMs) - TEST_RPS_LESS(5, 420, 350, TInstantTimerMs) - TEST_RPS_LESS(5, 220, 185, TInstantTimerMs) -} +#include <library/cpp/testing/unittest/registar.h> +#include <library/cpp/bucket_quoter/bucket_quoter.h> + +#include "test_namespace.h" + + +using NBucketQuoterTest::TMockTimer; + +#define TEST_RPS_EXACT(THREADS, RPS, EXPECTED_RESULT, TIMER) \ +Y_UNIT_TEST(Test##TIMER##RPS##Rps##THREADS##Threads) { \ + ui32 seconds = 10; \ + ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\ + (THREADS, RPS, seconds);\ + ui32 total_rps = summary_requests / seconds; \ + UNIT_ASSERT_EQUAL(total_rps, EXPECTED_RESULT);\ +} + +#define TEST_RPS_LESS(THREADS, RPS, UPPER_BOUND, TIMER) \ +Y_UNIT_TEST(Test##TIMER##RPS##rps##THREADS##threads) { \ + ui32 seconds = 10; \ + ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\ + (THREADS, RPS, seconds); \ + ui32 total_rps = summary_requests / seconds; \ + UNIT_ASSERT_LE(total_rps, UPPER_BOUND); \ +} + +Y_UNIT_TEST_SUITE(TMockTimerTest) { + TEST_RPS_EXACT(1, 100, 100, TMockTimer) + TEST_RPS_EXACT(1, 120, 60, TMockTimer) + TEST_RPS_EXACT(1, 200, 200, TMockTimer) + TEST_RPS_EXACT(1, 220, 110, TMockTimer) + TEST_RPS_EXACT(1, 240, 120, TMockTimer) + TEST_RPS_EXACT(1, 300, 150, TMockTimer) + TEST_RPS_EXACT(1, 320, 320, TMockTimer) + TEST_RPS_EXACT(1, 480, 240, TMockTimer) + +} + +Y_UNIT_TEST_SUITE(TInstantTimerTest) { + TEST_RPS_LESS(1, 360, 300, TInstantTimerMs) + TEST_RPS_LESS(1, 480, 400, TInstantTimerMs) + TEST_RPS_LESS(5, 420, 350, TInstantTimerMs) + TEST_RPS_LESS(5, 220, 185, TInstantTimerMs) +} diff --git a/library/cpp/bucket_quoter/ut/test_namespace.cpp b/library/cpp/bucket_quoter/ut/test_namespace.cpp index 8b306c4568..ee6c84796c 100644 --- a/library/cpp/bucket_quoter/ut/test_namespace.cpp +++ b/library/cpp/bucket_quoter/ut/test_namespace.cpp @@ -1,13 +1,13 @@ -#include "test_namespace.h" - -namespace NBucketQuoterTest { - - TMockTimer::TTime TMockTimer::CurrentTime = 0; - - template <> - void Sleep<TMockTimer>(TDuration duration) { - TMockTimer::Sleep(duration); - } - -} - +#include "test_namespace.h" + +namespace NBucketQuoterTest { + + TMockTimer::TTime TMockTimer::CurrentTime = 0; + + template <> + void Sleep<TMockTimer>(TDuration duration) { + TMockTimer::Sleep(duration); + } + +} + diff --git a/library/cpp/bucket_quoter/ut/test_namespace.h b/library/cpp/bucket_quoter/ut/test_namespace.h index ae5f85ab9d..8d8dc1f2b3 100644 --- a/library/cpp/bucket_quoter/ut/test_namespace.h +++ b/library/cpp/bucket_quoter/ut/test_namespace.h @@ -1,83 +1,83 @@ -#pragma once - -#include <library/cpp/bucket_quoter/bucket_quoter.h> -#include <library/cpp/getopt/last_getopt.h> - -#include <util/thread/pool.h> -#include <util/string/printf.h> -#include <util/system/types.h> -#include <util/stream/output.h> -#include <util/datetime/base.h> -#include <util/digest/fnv.h> -#include <vector> -#include <thread> -#include <numeric> - -namespace NBucketQuoterTest { - - // thread unsafe - struct TMockTimer { - using TTime = i64; - static constexpr ui64 Resolution = 1'000'000ull; // microseconds - static TTime CurrentTime; - - static TMockTimer::TTime Now() { - return CurrentTime; - } - - static ui64 Duration(TMockTimer::TTime from, TMockTimer::TTime to) { - return to - from; - } - - static void Sleep(TDuration duration) { - CurrentTime += duration.MicroSeconds(); - } - }; - - template <typename Timer> - void Sleep(TDuration duration) { - ::Sleep(duration); - } - - template <> - void Sleep<TMockTimer>(TDuration duration); - - template <class Timer> - using QuoterTemplate = TBucketQuoter<i64, TMutex, Timer>; - - template<class Timer> - struct TTestScenario { - void operator () (TBucketQuoter<i64, TMutex, Timer>& quoter, ui64 work_time, i64 wait_time, ui64& store_result) const { - typename Timer::TTime start = Timer::Now(); - work_time *= Timer::Resolution; - while (Timer::Duration(start, Timer::Now()) < work_time) { - while(!quoter.IsAvail()) { - NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(quoter.GetWaitTime())); - } - quoter.Use(1); - ++store_result; - if (wait_time != 0) { - NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(wait_time)); - } - } - } - }; - - template <class Timer, template <class TT> class Scenario> - ui32 Run(ui64 thread_count, ui64 rps, ui64 seconds, i64 wait_time = 0) { - TBucketQuoter<i64, TMutex, Timer> quoter(rps, rps); - std::vector<std::thread> threads; - std::vector<ui64> results; - threads.reserve(thread_count); - results.reserve(thread_count); - for (ui32 i = 0; i < thread_count; ++i) { - results.emplace_back(0); - threads.emplace_back(Scenario<Timer>{}, std::ref(quoter), seconds, wait_time, std::ref(results.back())); - } - for (ui32 i = 0; i < thread_count; ++i) { - threads[i].join(); - } - return std::reduce(results.begin(), results.end(), 0, std::plus<>()); - } - -}
\ No newline at end of file +#pragma once + +#include <library/cpp/bucket_quoter/bucket_quoter.h> +#include <library/cpp/getopt/last_getopt.h> + +#include <util/thread/pool.h> +#include <util/string/printf.h> +#include <util/system/types.h> +#include <util/stream/output.h> +#include <util/datetime/base.h> +#include <util/digest/fnv.h> +#include <vector> +#include <thread> +#include <numeric> + +namespace NBucketQuoterTest { + + // thread unsafe + struct TMockTimer { + using TTime = i64; + static constexpr ui64 Resolution = 1'000'000ull; // microseconds + static TTime CurrentTime; + + static TMockTimer::TTime Now() { + return CurrentTime; + } + + static ui64 Duration(TMockTimer::TTime from, TMockTimer::TTime to) { + return to - from; + } + + static void Sleep(TDuration duration) { + CurrentTime += duration.MicroSeconds(); + } + }; + + template <typename Timer> + void Sleep(TDuration duration) { + ::Sleep(duration); + } + + template <> + void Sleep<TMockTimer>(TDuration duration); + + template <class Timer> + using QuoterTemplate = TBucketQuoter<i64, TMutex, Timer>; + + template<class Timer> + struct TTestScenario { + void operator () (TBucketQuoter<i64, TMutex, Timer>& quoter, ui64 work_time, i64 wait_time, ui64& store_result) const { + typename Timer::TTime start = Timer::Now(); + work_time *= Timer::Resolution; + while (Timer::Duration(start, Timer::Now()) < work_time) { + while(!quoter.IsAvail()) { + NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(quoter.GetWaitTime())); + } + quoter.Use(1); + ++store_result; + if (wait_time != 0) { + NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(wait_time)); + } + } + } + }; + + template <class Timer, template <class TT> class Scenario> + ui32 Run(ui64 thread_count, ui64 rps, ui64 seconds, i64 wait_time = 0) { + TBucketQuoter<i64, TMutex, Timer> quoter(rps, rps); + std::vector<std::thread> threads; + std::vector<ui64> results; + threads.reserve(thread_count); + results.reserve(thread_count); + for (ui32 i = 0; i < thread_count; ++i) { + results.emplace_back(0); + threads.emplace_back(Scenario<Timer>{}, std::ref(quoter), seconds, wait_time, std::ref(results.back())); + } + for (ui32 i = 0; i < thread_count; ++i) { + threads[i].join(); + } + return std::reduce(results.begin(), results.end(), 0, std::plus<>()); + } + +}
\ No newline at end of file diff --git a/library/cpp/bucket_quoter/ut/ya.make b/library/cpp/bucket_quoter/ut/ya.make index 83b49cdcef..774b85e623 100644 --- a/library/cpp/bucket_quoter/ut/ya.make +++ b/library/cpp/bucket_quoter/ut/ya.make @@ -1,18 +1,18 @@ -UNITTEST() - -OWNER( - g:kikimr - svc -) - -FORK_SUBTESTS() -SRCS( - main.cpp - test_namespace.cpp -) -PEERDIR( - library/cpp/bucket_quoter - library/cpp/getopt -) - -END() +UNITTEST() + +OWNER( + g:kikimr + svc +) + +FORK_SUBTESTS() +SRCS( + main.cpp + test_namespace.cpp +) +PEERDIR( + library/cpp/bucket_quoter + library/cpp/getopt +) + +END() diff --git a/library/cpp/bucket_quoter/ya.make b/library/cpp/bucket_quoter/ya.make index 4833527e27..49c407b502 100644 --- a/library/cpp/bucket_quoter/ya.make +++ b/library/cpp/bucket_quoter/ya.make @@ -7,5 +7,5 @@ SRCS( ) END() - -RECURSE_FOR_TESTS(ut) + +RECURSE_FOR_TESTS(ut) |