12 std::chrono::seconds window_size,
13 std::size_t buckets_per_second)
14 : window_size_(window_size),
15 bucket_duration_(
std::chrono::milliseconds{1000 / buckets_per_second}),
16 buckets_(static_cast<
std::size_t>(window_size.count()) * buckets_per_second) {
19 bucket.count.store(0, std::memory_order_relaxed);
20 bucket.timestamp_ms.store(0, std::memory_order_relaxed);
25 : window_size_(other.window_size_),
26 bucket_duration_(other.bucket_duration_),
27 buckets_(other.buckets_.size()) {
28 for (std::size_t i = 0; i <
buckets_.size(); ++i) {
30 other.
buckets_[i].count.load(std::memory_order_relaxed),
31 std::memory_order_relaxed);
33 other.
buckets_[i].timestamp_ms.load(std::memory_order_relaxed),
34 std::memory_order_relaxed);
38 std::memory_order_relaxed);
42 : window_size_(other.window_size_),
43 bucket_duration_(other.bucket_duration_),
44 buckets_(std::move(other.buckets_)) {
45 all_time_total_.store(
46 other.all_time_total_.exchange(0, std::memory_order_relaxed),
47 std::memory_order_relaxed);
61 for (std::size_t i = 0; i <
buckets_.size(); ++i) {
63 other.
buckets_[i].count.load(std::memory_order_relaxed),
64 std::memory_order_relaxed);
66 other.
buckets_[i].timestamp_ms.load(std::memory_order_relaxed),
67 std::memory_order_relaxed);
71 std::memory_order_relaxed);
79 window_size_ = other.window_size_;
80 bucket_duration_ = other.bucket_duration_;
81 buckets_ = std::move(other.buckets_);
82 all_time_total_.store(
83 other.all_time_total_.exchange(0, std::memory_order_relaxed),
84 std::memory_order_relaxed);
97 buckets_[bucket_index].count.fetch_add(
98 static_cast<std::uint64_t
>(count), std::memory_order_relaxed);
100 static_cast<std::uint64_t
>(count), std::memory_order_relaxed);
105 const auto window_seconds =
static_cast<double>(
window_size_.count());
106 return static_cast<double>(total) / window_seconds;
111 std::uint64_t total = 0;
113 for (
const auto& bucket :
buckets_) {
114 const auto timestamp = bucket.timestamp_ms.load(std::memory_order_relaxed);
116 total += bucket.count.load(std::memory_order_relaxed);
129 bucket.count.store(0, std::memory_order_relaxed);
130 bucket.timestamp_ms.store(0, std::memory_order_relaxed);
148 std::uint64_t timestamp_ms)
const {
149 const auto bucket_duration_ms =
151 return static_cast<std::size_t
>(
152 (timestamp_ms / bucket_duration_ms) %
buckets_.size());
156 return static_cast<std::uint64_t
>(
157 std::chrono::duration_cast<std::chrono::milliseconds>(
158 std::chrono::steady_clock::now().time_since_epoch())
163 std::uint64_t bucket_timestamp_ms,
164 std::uint64_t current_ms)
const {
165 if (bucket_timestamp_ms == 0) {
169 const auto window_ms =
170 static_cast<std::uint64_t
>(
window_size_.count()) * 1000;
171 return (current_ms - bucket_timestamp_ms) < window_ms;
175 std::size_t bucket_index,
176 std::uint64_t current_ms) {
177 auto& bucket =
buckets_[bucket_index];
178 const auto bucket_duration_ms =
182 const auto expected_timestamp =
183 (current_ms / bucket_duration_ms) * bucket_duration_ms;
185 auto old_timestamp = bucket.timestamp_ms.load(std::memory_order_relaxed);
188 if (old_timestamp < expected_timestamp) {
190 if (bucket.timestamp_ms.compare_exchange_strong(
191 old_timestamp, expected_timestamp,
192 std::memory_order_relaxed, std::memory_order_relaxed)) {
195 bucket.count.store(0, std::memory_order_relaxed);
Sliding window counter for throughput measurement.
SlidingWindowCounter & operator=(const SlidingWindowCounter &other)
Copy assignment operator.
bool is_bucket_valid(std::uint64_t bucket_timestamp_ms, std::uint64_t current_ms) const
Check if a bucket is within the current window.
std::size_t bucket_count() const
Get the number of buckets.
void reset()
Reset the counter.
std::chrono::seconds window_size_
The sliding window duration.
std::size_t current_bucket_index() const
Get the current bucket index based on current time.
std::chrono::seconds window_size() const
Get the window size.
void increment(std::size_t count=1)
Increment the counter.
SlidingWindowCounter(std::chrono::seconds window_size, std::size_t buckets_per_second=DEFAULT_BUCKETS_PER_SECOND)
Constructs a sliding window counter.
std::uint64_t all_time_total() const
Get the all-time total count.
std::uint64_t total_in_window() const
Get the total count within the current window.
std::vector< Bucket > buckets_
Circular buffer of time buckets.
std::size_t bucket_index_for_time(std::uint64_t timestamp_ms) const
Get the bucket index for a specific timestamp.
double rate_per_second() const
Get the current rate per second.
std::atomic< std::uint64_t > all_time_total_
All-time total count.
std::chrono::milliseconds bucket_duration_
Duration of each bucket.
void advance_bucket(std::size_t bucket_index, std::uint64_t current_ms)
Advance bucket to current time period if needed.
static std::uint64_t current_time_ms()
Get current time in milliseconds since epoch.
Sliding window counter for throughput measurement.