blob: 84d791edd13ab13b1a7622751f148d8f3e9dd559 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
2 * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 17:11:0011#ifndef RTC_BASE_ROLLING_ACCUMULATOR_H_
12#define RTC_BASE_ROLLING_ACCUMULATOR_H_
henrike@webrtc.orgf0488722014-05-13 18:00:2613
Yves Gerey3e707812018-11-28 15:47:4914#include <stddef.h>
Jonas Olssona4d87372019-07-05 17:08:3315
Henrik Kjellanderec78f1c2017-06-29 05:52:5016#include <algorithm>
17#include <vector>
henrike@webrtc.orgf0488722014-05-13 18:00:2618
Mirko Bonadei92ea95e2017-09-15 04:47:3119#include "rtc_base/checks.h"
Yves Gerey3dfb6802019-05-13 15:01:3220#include "rtc_base/numerics/running_statistics.h"
Henrik Kjellanderec78f1c2017-06-29 05:52:5021
22namespace rtc {
23
24// RollingAccumulator stores and reports statistics
25// over N most recent samples.
26//
27// T is assumed to be an int, long, double or float.
Yves Gerey665174f2018-06-19 13:03:0528template <typename T>
Henrik Kjellanderec78f1c2017-06-29 05:52:5029class RollingAccumulator {
30 public:
Yves Gerey665174f2018-06-19 13:03:0531 explicit RollingAccumulator(size_t max_count) : samples_(max_count) {
Yves Gerey3dfb6802019-05-13 15:01:3232 RTC_DCHECK(max_count > 0);
Henrik Kjellanderec78f1c2017-06-29 05:52:5033 Reset();
34 }
Yves Gerey665174f2018-06-19 13:03:0535 ~RollingAccumulator() {}
Henrik Kjellanderec78f1c2017-06-29 05:52:5036
Byoungchan Lee14af7622022-01-11 20:24:5837 RollingAccumulator(const RollingAccumulator&) = delete;
38 RollingAccumulator& operator=(const RollingAccumulator&) = delete;
39
Yves Gerey665174f2018-06-19 13:03:0540 size_t max_count() const { return samples_.size(); }
Henrik Kjellanderec78f1c2017-06-29 05:52:5041
Yves Gerey3dfb6802019-05-13 15:01:3242 size_t count() const { return static_cast<size_t>(stats_.Size()); }
Henrik Kjellanderec78f1c2017-06-29 05:52:5043
44 void Reset() {
Artem Titov9d777622020-09-18 16:23:0845 stats_ = webrtc::webrtc_impl::RunningStatistics<T>();
Henrik Kjellanderec78f1c2017-06-29 05:52:5046 next_index_ = 0U;
Henrik Kjellanderec78f1c2017-06-29 05:52:5047 max_ = T();
48 max_stale_ = false;
49 min_ = T();
50 min_stale_ = false;
51 }
52
53 void AddSample(T sample) {
Yves Gerey3dfb6802019-05-13 15:01:3254 if (count() == max_count()) {
Henrik Kjellanderec78f1c2017-06-29 05:52:5055 // Remove oldest sample.
56 T sample_to_remove = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 15:01:3257 stats_.RemoveSample(sample_to_remove);
Henrik Kjellanderec78f1c2017-06-29 05:52:5058 if (sample_to_remove >= max_) {
59 max_stale_ = true;
60 }
61 if (sample_to_remove <= min_) {
62 min_stale_ = true;
63 }
Henrik Kjellanderec78f1c2017-06-29 05:52:5064 }
65 // Add new sample.
66 samples_[next_index_] = sample;
Yves Gerey3dfb6802019-05-13 15:01:3267 if (count() == 0 || sample >= max_) {
Henrik Kjellanderec78f1c2017-06-29 05:52:5068 max_ = sample;
69 max_stale_ = false;
70 }
Yves Gerey3dfb6802019-05-13 15:01:3271 if (count() == 0 || sample <= min_) {
Henrik Kjellanderec78f1c2017-06-29 05:52:5072 min_ = sample;
73 min_stale_ = false;
74 }
Yves Gerey3dfb6802019-05-13 15:01:3275 stats_.AddSample(sample);
Henrik Kjellanderec78f1c2017-06-29 05:52:5076 // Update next_index_.
77 next_index_ = (next_index_ + 1) % max_count();
78 }
79
Yves Gerey3dfb6802019-05-13 15:01:3280 double ComputeMean() const { return stats_.GetMean().value_or(0); }
Henrik Kjellanderec78f1c2017-06-29 05:52:5081
82 T ComputeMax() const {
83 if (max_stale_) {
Yves Gerey3dfb6802019-05-13 15:01:3284 RTC_DCHECK(count() > 0)
85 << "It shouldn't be possible for max_stale_ && count() == 0";
Henrik Kjellanderec78f1c2017-06-29 05:52:5086 max_ = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 15:01:3287 for (size_t i = 1u; i < count(); i++) {
Henrik Kjellanderec78f1c2017-06-29 05:52:5088 max_ = std::max(max_, samples_[(next_index_ + i) % max_count()]);
89 }
90 max_stale_ = false;
91 }
92 return max_;
93 }
94
95 T ComputeMin() const {
96 if (min_stale_) {
Yves Gerey3dfb6802019-05-13 15:01:3297 RTC_DCHECK(count() > 0)
98 << "It shouldn't be possible for min_stale_ && count() == 0";
Henrik Kjellanderec78f1c2017-06-29 05:52:5099 min_ = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 15:01:32100 for (size_t i = 1u; i < count(); i++) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50101 min_ = std::min(min_, samples_[(next_index_ + i) % max_count()]);
102 }
103 min_stale_ = false;
104 }
105 return min_;
106 }
107
108 // O(n) time complexity.
109 // Weights nth sample with weight (learning_rate)^n. Learning_rate should be
110 // between (0.0, 1.0], otherwise the non-weighted mean is returned.
111 double ComputeWeightedMean(double learning_rate) const {
Yves Gerey3dfb6802019-05-13 15:01:32112 if (count() < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50113 return ComputeMean();
114 }
115 double weighted_mean = 0.0;
116 double current_weight = 1.0;
117 double weight_sum = 0.0;
118 const size_t max_size = max_count();
Yves Gerey3dfb6802019-05-13 15:01:32119 for (size_t i = 0; i < count(); ++i) {
Henrik Kjellanderec78f1c2017-06-29 05:52:50120 current_weight *= learning_rate;
121 weight_sum += current_weight;
122 // Add max_size to prevent underflow.
123 size_t index = (next_index_ + max_size - i - 1) % max_size;
124 weighted_mean += current_weight * samples_[index];
125 }
126 return weighted_mean / weight_sum;
127 }
128
129 // Compute estimated variance. Estimation is more accurate
130 // as the number of samples grows.
Yves Gerey3dfb6802019-05-13 15:01:32131 double ComputeVariance() const { return stats_.GetVariance().value_or(0); }
Henrik Kjellanderec78f1c2017-06-29 05:52:50132
133 private:
Artem Titov9d777622020-09-18 16:23:08134 webrtc::webrtc_impl::RunningStatistics<T> stats_;
Henrik Kjellanderec78f1c2017-06-29 05:52:50135 size_t next_index_;
Henrik Kjellanderec78f1c2017-06-29 05:52:50136 mutable T max_;
137 mutable bool max_stale_;
138 mutable T min_;
139 mutable bool min_stale_;
140 std::vector<T> samples_;
Henrik Kjellanderec78f1c2017-06-29 05:52:50141};
142
143} // namespace rtc
henrike@webrtc.orgf0488722014-05-13 18:00:26144
Steve Anton10542f22019-01-11 17:11:00145#endif // RTC_BASE_ROLLING_ACCUMULATOR_H_