summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/rate_statistics.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/rate_statistics.cc
parentInitial commit. (diff)
downloadfirefox-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.cc157
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