From bcc2d3284a0f8d91879197741228f21282584a0f Mon Sep 17 00:00:00 2001 From: Mihai Brodschi Date: Tue, 27 Aug 2024 14:33:59 +0300 Subject: [PATCH] Convert TokenBucket to measure time in microseconds --- elements/standard/bwratedunqueue.cc | 2 +- elements/standard/ratedsource.cc | 6 +- elements/standard/ratedunqueue.cc | 2 +- elements/test/tokenbuckettest.cc | 2 +- include/click/tokenbucket.hh | 88 +++++++++++++++++++++++++---- 5 files changed, 82 insertions(+), 18 deletions(-) diff --git a/elements/standard/bwratedunqueue.cc b/elements/standard/bwratedunqueue.cc index 86fedf094d..32f6dd9dcf 100644 --- a/elements/standard/bwratedunqueue.cc +++ b/elements/standard/bwratedunqueue.cc @@ -85,7 +85,7 @@ BandwidthRatedUnqueue::run_task(Task *) } } } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(tb_bandwidth_thresh))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(tb_bandwidth_thresh))); _empty_runs++; return false; } diff --git a/elements/standard/ratedsource.cc b/elements/standard/ratedsource.cc index c780b2765c..fb32eb708e 100644 --- a/elements/standard/ratedsource.cc +++ b/elements/standard/ratedsource.cc @@ -179,7 +179,7 @@ RatedSource::run_task(Task *) count++; } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(_batch_size))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(_batch_size))); return false; } } @@ -194,7 +194,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); return false; } @@ -209,7 +209,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); return false; } diff --git a/elements/standard/ratedunqueue.cc b/elements/standard/ratedunqueue.cc index da8b7a3102..cbe95ae4fa 100644 --- a/elements/standard/ratedunqueue.cc +++ b/elements/standard/ratedunqueue.cc @@ -133,7 +133,7 @@ RatedUnqueue::run_task(Task *) } #endif } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); _empty_runs++; return false; } diff --git a/elements/test/tokenbuckettest.cc b/elements/test/tokenbuckettest.cc index 58c5f5faab..0bd516ac55 100644 --- a/elements/test/tokenbuckettest.cc +++ b/elements/test/tokenbuckettest.cc @@ -30,7 +30,7 @@ TokenBucketTest::TokenBucketTest() int TokenBucketTest::initialize(ErrorHandler *errh) { - TokenBucket tb; + TokenBucketX > tb; tb.assign(1024, 2048); CHECK(tb.rate() >= 1022 && tb.rate() <= 1026); CHECK(tb.capacity() >= 2046 && tb.capacity() <= 2050); diff --git a/include/click/tokenbucket.hh b/include/click/tokenbucket.hh index 8336fee247..e5318c9e86 100644 --- a/include/click/tokenbucket.hh +++ b/include/click/tokenbucket.hh @@ -32,6 +32,8 @@ CLICK_DECLS TokenRateX template parameter P defines the time tick unit and frequency. The provided TokenBucketJiffyParameters class is designed to be used as TokenRateX's parameter; it measures ticks in units of jiffies. + TokenBucketUsecParameters is also included, which measures ticks in + units of microseconds. @sa GapRate */ @@ -48,7 +50,7 @@ CLICK_DECLS token_max. An idle TokenRateX never refills. Most users will be satisfied with the TokenRate type, which is equal to - TokenRateX >. + TokenRateX >. @sa TokenCounterX, TokenBucketX */ @@ -318,7 +320,7 @@ template struct TokenRateConverter { remove(), and similar functions act as normal for idle and unlimited rates. Most users will be satisfied with the TokenCounter type, which is equal to - TokenCounterX > >. + TokenCounterX > >. @sa TokenRateX, TokenBucketX */ @@ -693,6 +695,68 @@ class TokenBucketJiffyParameters { public: }; +/** @class TokenBucketUsecParameters include/click/tokenbucket.hh + @brief Helper class for token bucket rate limiter. + + Pass this class as the parameter to TokenRateX. TokenBucketUsecParameters + measures ticks in units of microseconds. The template parameter is the type of + tokens. */ + +template +class TokenBucketUsecParameters { public: + + /** @brief The type of tokens. Always unsigned. */ + typedef T token_type; + + /** @brief The type of a time point. Always unsigned. */ + typedef click_uintmax_t time_point_type; + + /** @brief The type of a difference between time points. Always signed. */ + typedef click_intmax_t duration_type; + + /** @brief Return the current time point. + * @note TokenBucketUsecParameters measures time points in microseconds. */ + static time_point_type now() { + return Timestamp::now_steady().usecval(); + } + + static time_point_type time_point(time_point_type t) { + return t; + } + + /** @brief Return @a b - @a a, assuming that @a b was measured after @a a. + * + * Some time measurements can, in rare cases, appear to jump backwards, + * as timestamps do when the user changes the current time. If this + * happens, and @a b < @a a (even though @a b happened after @a a), + * time_monotonic_difference must return 0. */ + static duration_type time_monotonic_difference(time_point_type a, time_point_type b) { + return (likely(a <= b) ? b - a : 0); + } + + /** @brief Return true if @a a happened before @a b. */ + static bool time_less(time_point_type a, time_point_type b) { + return (duration_type) (a - b) < 0; + } + + /** @brief Return the number of time points per period. + * + * Here, this is the number of microseconds per second. */ + static unsigned frequency() { + return 1000000; + } + + /** @brief Return the Timestamp representing a given time point. */ + static Timestamp timestamp(time_point_type x) { + return Timestamp::make_usec(x); + } + + /** @brief Return the Timestamp representing a given tick count. */ + static Timestamp timestamp(duration_type x) { + return Timestamp::make_usec(x); + } + +}; /** @class TokenBucketX include/click/tokenbucket.hh @brief Token bucket rate limiter. @@ -701,7 +765,7 @@ class TokenBucketJiffyParameters { public: implemented as a pair of TokenRateX and TokenCounterX. Most users will be satisfied with the TokenBucket type, which is equal to - TokenBucketX >. + TokenBucketX >. @sa GapRate */ @@ -1006,15 +1070,15 @@ inline typename TokenBucketX

::ticks_type TokenBucketX

::epochs_until_contai /** @class TokenRate include/click/tokenbucket.hh - * @brief Jiffy-based token bucket rate + * @brief Microsecond-based token bucket rate * * Equivalent to - * @link TokenRateX TokenRateX >@endlink. - * @sa TokenRateX, TokenBucketJiffyParameters */ -typedef TokenRateX > TokenRate; + * @link TokenRateX TokenRateX >@endlink. + * @sa TokenRateX, TokenBucketUsecParameters */ +typedef TokenRateX > TokenRate; /** @class TokenCounter include/click/tokenbucket.hh - * @brief Jiffy-based token counter + * @brief Microsecond-based token counter * * Equivalent to * @link TokenCounterX TokenCounterX@endlink. @@ -1022,12 +1086,12 @@ typedef TokenRateX > TokenRate; typedef TokenCounterX TokenCounter; /** @class TokenBucket include/click/tokenbucket.hh - * @brief Jiffy-based token bucket rate limiter + * @brief Microsecond-based token bucket rate limiter * * Equivalent to - * @link TokenBucketX TokenBucketX >@endlink. - * @sa TokenBucketX, TokenBucketJiffyParameters */ -typedef TokenBucketX > TokenBucket; + * @link TokenBucketX TokenBucketX >@endlink. + * @sa TokenBucketX, TokenBucketUsecParameters */ +typedef TokenBucketX > TokenBucket; CLICK_ENDDECLS #endif