diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/rate_statistics.cc | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/rate_statistics.cc')
-rw-r--r-- | third_party/libwebrtc/rtc_base/rate_statistics.cc | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/rate_statistics.cc b/third_party/libwebrtc/rtc_base/rate_statistics.cc new file mode 100644 index 0000000000..5c83796471 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_statistics.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/rate_statistics.h" + +#include <algorithm> +#include <limits> +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +RateStatistics::Bucket::Bucket(int64_t timestamp) + : sum(0), num_samples(0), timestamp(timestamp) {} + +RateStatistics::RateStatistics(int64_t window_size_ms, float scale) + : accumulated_count_(0), + first_timestamp_(-1), + num_samples_(0), + scale_(scale), + max_window_size_ms_(window_size_ms), + current_window_size_ms_(max_window_size_ms_) {} + +RateStatistics::RateStatistics(const RateStatistics& other) + : buckets_(other.buckets_), + accumulated_count_(other.accumulated_count_), + first_timestamp_(other.first_timestamp_), + overflow_(other.overflow_), + num_samples_(other.num_samples_), + scale_(other.scale_), + max_window_size_ms_(other.max_window_size_ms_), + current_window_size_ms_(other.current_window_size_ms_) {} + +RateStatistics::RateStatistics(RateStatistics&& other) = default; + +RateStatistics::~RateStatistics() {} + +void RateStatistics::Reset() { + accumulated_count_ = 0; + overflow_ = false; + num_samples_ = 0; + first_timestamp_ = -1; + current_window_size_ms_ = max_window_size_ms_; + buckets_.clear(); +} + +void RateStatistics::Update(int64_t count, int64_t now_ms) { + RTC_DCHECK_GE(count, 0); + + EraseOld(now_ms); + if (first_timestamp_ == -1 || num_samples_ == 0) { + first_timestamp_ = now_ms; + } + + if (buckets_.empty() || now_ms != buckets_.back().timestamp) { + if (!buckets_.empty() && now_ms < buckets_.back().timestamp) { + RTC_LOG(LS_WARNING) << "Timestamp " << now_ms + << " is before the last added " + "timestamp in the rate window: " + << buckets_.back().timestamp << ", aligning to that."; + now_ms = buckets_.back().timestamp; + } + buckets_.emplace_back(now_ms); + } + Bucket& last_bucket = buckets_.back(); + last_bucket.sum += count; + ++last_bucket.num_samples; + + if (std::numeric_limits<int64_t>::max() - accumulated_count_ > count) { + accumulated_count_ += count; + } else { + overflow_ = true; + } + ++num_samples_; +} + +absl::optional<int64_t> RateStatistics::Rate(int64_t now_ms) const { + // Yeah, this const_cast ain't pretty, but the alternative is to declare most + // of the members as mutable... + const_cast<RateStatistics*>(this)->EraseOld(now_ms); + + int active_window_size = 0; + if (first_timestamp_ != -1) { + if (first_timestamp_ <= now_ms - current_window_size_ms_) { + // Count window as full even if no data points currently in view, if the + // data stream started before the window. + active_window_size = current_window_size_ms_; + } else { + // Size of a single bucket is 1ms, so even if now_ms == first_timestmap_ + // the window size should be 1. + active_window_size = now_ms - first_timestamp_ + 1; + } + } + + // If window is a single bucket or there is only one sample in a data set that + // has not grown to the full window size, or if the accumulator has + // overflowed, treat this as rate unavailable. + if (num_samples_ == 0 || active_window_size <= 1 || + (num_samples_ <= 1 && + rtc::SafeLt(active_window_size, current_window_size_ms_)) || + overflow_) { + return absl::nullopt; + } + + float scale = static_cast<float>(scale_) / active_window_size; + float result = accumulated_count_ * scale + 0.5f; + + // Better return unavailable rate than garbage value (undefined behavior). + if (result > static_cast<float>(std::numeric_limits<int64_t>::max())) { + return absl::nullopt; + } + return rtc::dchecked_cast<int64_t>(result); +} + +void RateStatistics::EraseOld(int64_t now_ms) { + // New oldest time that is included in data set. + const int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1; + + // Loop over buckets and remove too old data points. + while (!buckets_.empty() && buckets_.front().timestamp < new_oldest_time) { + const Bucket& oldest_bucket = buckets_.front(); + RTC_DCHECK_GE(accumulated_count_, oldest_bucket.sum); + RTC_DCHECK_GE(num_samples_, oldest_bucket.num_samples); + accumulated_count_ -= oldest_bucket.sum; + num_samples_ -= oldest_bucket.num_samples; + buckets_.pop_front(); + // This does not clear overflow_ even when counter is empty. + // TODO(https://bugs.webrtc.org/11247): Consider if overflow_ can be reset. + } +} + +bool RateStatistics::SetWindowSize(int64_t window_size_ms, int64_t now_ms) { + if (window_size_ms <= 0 || window_size_ms > max_window_size_ms_) + return false; + if (first_timestamp_ != -1) { + // If the window changes (e.g. decreases - removing data point, then + // increases again) we need to update the first timestamp mark as + // otherwise it indicates the window coveres a region of zeros, suddenly + // under-estimating the rate. + first_timestamp_ = std::max(first_timestamp_, now_ms - window_size_ms + 1); + } + current_window_size_ms_ = window_size_ms; + EraseOld(now_ms); + return true; +} + +} // namespace webrtc |