blob: b630554a80725282b9c9340e174710326bcc69ff [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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 09:11:00 -080011#ifndef RTC_BASE_ROLLING_ACCUMULATOR_H_
12#define RTC_BASE_ROLLING_ACCUMULATOR_H_
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013
Yves Gerey3e707812018-11-28 16:47:49 +010014#include <stddef.h>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020015#include <algorithm>
16#include <vector>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/constructor_magic.h"
Yves Gerey3dfb6802019-05-13 17:01:32 +020020#include "rtc_base/numerics/running_statistics.h"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020021
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 15:03:05 +020028template <typename T>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020029class RollingAccumulator {
30 public:
Yves Gerey665174f2018-06-19 15:03:05 +020031 explicit RollingAccumulator(size_t max_count) : samples_(max_count) {
Yves Gerey3dfb6802019-05-13 17:01:32 +020032 RTC_DCHECK(max_count > 0);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020033 Reset();
34 }
Yves Gerey665174f2018-06-19 15:03:05 +020035 ~RollingAccumulator() {}
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020036
Yves Gerey665174f2018-06-19 15:03:05 +020037 size_t max_count() const { return samples_.size(); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020038
Yves Gerey3dfb6802019-05-13 17:01:32 +020039 size_t count() const { return static_cast<size_t>(stats_.Size()); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020040
41 void Reset() {
Yves Gerey3dfb6802019-05-13 17:01:32 +020042 stats_ = webrtc::RunningStatistics<T>();
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020043 next_index_ = 0U;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020044 max_ = T();
45 max_stale_ = false;
46 min_ = T();
47 min_stale_ = false;
48 }
49
50 void AddSample(T sample) {
Yves Gerey3dfb6802019-05-13 17:01:32 +020051 if (count() == max_count()) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020052 // Remove oldest sample.
53 T sample_to_remove = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 17:01:32 +020054 stats_.RemoveSample(sample_to_remove);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020055 if (sample_to_remove >= max_) {
56 max_stale_ = true;
57 }
58 if (sample_to_remove <= min_) {
59 min_stale_ = true;
60 }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020061 }
62 // Add new sample.
63 samples_[next_index_] = sample;
Yves Gerey3dfb6802019-05-13 17:01:32 +020064 if (count() == 0 || sample >= max_) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020065 max_ = sample;
66 max_stale_ = false;
67 }
Yves Gerey3dfb6802019-05-13 17:01:32 +020068 if (count() == 0 || sample <= min_) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020069 min_ = sample;
70 min_stale_ = false;
71 }
Yves Gerey3dfb6802019-05-13 17:01:32 +020072 stats_.AddSample(sample);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020073 // Update next_index_.
74 next_index_ = (next_index_ + 1) % max_count();
75 }
76
Yves Gerey3dfb6802019-05-13 17:01:32 +020077 double ComputeMean() const { return stats_.GetMean().value_or(0); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020078
79 T ComputeMax() const {
80 if (max_stale_) {
Yves Gerey3dfb6802019-05-13 17:01:32 +020081 RTC_DCHECK(count() > 0)
82 << "It shouldn't be possible for max_stale_ && count() == 0";
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020083 max_ = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 17:01:32 +020084 for (size_t i = 1u; i < count(); i++) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020085 max_ = std::max(max_, samples_[(next_index_ + i) % max_count()]);
86 }
87 max_stale_ = false;
88 }
89 return max_;
90 }
91
92 T ComputeMin() const {
93 if (min_stale_) {
Yves Gerey3dfb6802019-05-13 17:01:32 +020094 RTC_DCHECK(count() > 0)
95 << "It shouldn't be possible for min_stale_ && count() == 0";
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020096 min_ = samples_[next_index_];
Yves Gerey3dfb6802019-05-13 17:01:32 +020097 for (size_t i = 1u; i < count(); i++) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020098 min_ = std::min(min_, samples_[(next_index_ + i) % max_count()]);
99 }
100 min_stale_ = false;
101 }
102 return min_;
103 }
104
105 // O(n) time complexity.
106 // Weights nth sample with weight (learning_rate)^n. Learning_rate should be
107 // between (0.0, 1.0], otherwise the non-weighted mean is returned.
108 double ComputeWeightedMean(double learning_rate) const {
Yves Gerey3dfb6802019-05-13 17:01:32 +0200109 if (count() < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200110 return ComputeMean();
111 }
112 double weighted_mean = 0.0;
113 double current_weight = 1.0;
114 double weight_sum = 0.0;
115 const size_t max_size = max_count();
Yves Gerey3dfb6802019-05-13 17:01:32 +0200116 for (size_t i = 0; i < count(); ++i) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200117 current_weight *= learning_rate;
118 weight_sum += current_weight;
119 // Add max_size to prevent underflow.
120 size_t index = (next_index_ + max_size - i - 1) % max_size;
121 weighted_mean += current_weight * samples_[index];
122 }
123 return weighted_mean / weight_sum;
124 }
125
126 // Compute estimated variance. Estimation is more accurate
127 // as the number of samples grows.
Yves Gerey3dfb6802019-05-13 17:01:32 +0200128 double ComputeVariance() const { return stats_.GetVariance().value_or(0); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200129
130 private:
Yves Gerey3dfb6802019-05-13 17:01:32 +0200131 webrtc::RunningStatistics<T> stats_;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200132 size_t next_index_;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200133 mutable T max_;
134 mutable bool max_stale_;
135 mutable T min_;
136 mutable bool min_stale_;
137 std::vector<T> samples_;
138
139 RTC_DISALLOW_COPY_AND_ASSIGN(RollingAccumulator);
140};
141
142} // namespace rtc
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143
Steve Anton10542f22019-01-11 09:11:00 -0800144#endif // RTC_BASE_ROLLING_ACCUMULATOR_H_