1 /* 2 * Copyright (c) 2016 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 11 #ifndef VIDEO_STATS_COUNTER_H_ 12 #define VIDEO_STATS_COUNTER_H_ 13 14 #include <memory> 15 #include <string> 16 17 namespace webrtc { 18 19 class AggregatedCounter; 20 class Clock; 21 class Samples; 22 23 // `StatsCounterObserver` is called periodically when a metric is updated. 24 class StatsCounterObserver { 25 public: 26 virtual void OnMetricUpdated(int sample) = 0; 27 ~StatsCounterObserver()28 virtual ~StatsCounterObserver() {} 29 }; 30 31 struct AggregatedStats { 32 std::string ToString() const; 33 std::string ToStringWithMultiplier(int multiplier) const; 34 35 int64_t num_samples = 0; 36 int min = -1; 37 int max = -1; 38 int average = -1; 39 // TODO(asapersson): Consider adding median/percentiles. 40 }; 41 42 // Classes which periodically computes a metric. 43 // 44 // During a period, `kProcessIntervalMs`, different metrics can be computed e.g: 45 // - `AvgCounter`: average of samples 46 // - `PercentCounter`: percentage of samples 47 // - `PermilleCounter`: permille of samples 48 // 49 // Each periodic metric can be either: 50 // - reported to an `observer` each period 51 // - aggregated during the call (e.g. min, max, average) 52 // 53 // periodically computed 54 // GetMetric() GetMetric() => AggregatedStats 55 // ^ ^ (e.g. min/max/avg) 56 // | | 57 // | * * * * | ** * * * * | ... 58 // |<- process interval ->| 59 // 60 // (*) - samples 61 // 62 // 63 // Example usage: 64 // 65 // AvgCounter counter(&clock, nullptr); 66 // counter.Add(5); 67 // counter.Add(1); 68 // counter.Add(6); // process interval passed -> GetMetric() avg:4 69 // counter.Add(7); 70 // counter.Add(3); // process interval passed -> GetMetric() avg:5 71 // counter.Add(10); 72 // counter.Add(20); // process interval passed -> GetMetric() avg:15 73 // AggregatedStats stats = counter.GetStats(); 74 // stats: {min:4, max:15, avg:8} 75 // 76 77 // Note: StatsCounter takes ownership of `observer`. 78 79 class StatsCounter { 80 public: 81 virtual ~StatsCounter(); 82 83 // Gets metric within an interval. Returns true on success false otherwise. 84 virtual bool GetMetric(int* metric) const = 0; 85 86 // Gets the value to use for an interval without samples. 87 virtual int GetValueForEmptyInterval() const = 0; 88 89 // Gets aggregated stats (i.e. aggregate of periodically computed metrics). 90 AggregatedStats GetStats(); 91 92 // Reports metrics for elapsed intervals to AggregatedCounter and GetStats. 93 AggregatedStats ProcessAndGetStats(); 94 95 // Reports metrics for elapsed intervals to AggregatedCounter and pauses stats 96 // (i.e. empty intervals will be discarded until next sample is added). 97 void ProcessAndPause(); 98 99 // As above with a minimum pause time. Added samples within this interval will 100 // not resume the stats (i.e. stop the pause). 101 void ProcessAndPauseForDuration(int64_t min_pause_time_ms); 102 103 // Reports metrics for elapsed intervals to AggregatedCounter and stops pause. 104 void ProcessAndStopPause(); 105 106 // Checks if a sample has been added (i.e. Add or Set called). 107 bool HasSample() const; 108 109 protected: 110 StatsCounter(Clock* clock, 111 int64_t process_intervals_ms, 112 bool include_empty_intervals, 113 StatsCounterObserver* observer); 114 115 void Add(int sample); 116 void Set(int64_t sample, uint32_t stream_id); 117 void SetLast(int64_t sample, uint32_t stream_id); 118 119 const bool include_empty_intervals_; 120 const int64_t process_intervals_ms_; 121 const std::unique_ptr<AggregatedCounter> aggregated_counter_; 122 const std::unique_ptr<Samples> samples_; 123 124 private: 125 bool TimeToProcess(int* num_elapsed_intervals); 126 void TryProcess(); 127 void ReportMetricToAggregatedCounter(int value, int num_values_to_add) const; 128 bool IncludeEmptyIntervals() const; 129 void Resume(); 130 void ResumeIfMinTimePassed(); 131 132 Clock* const clock_; 133 const std::unique_ptr<StatsCounterObserver> observer_; 134 int64_t last_process_time_ms_; 135 bool paused_; 136 int64_t pause_time_ms_; 137 int64_t min_pause_time_ms_; 138 }; 139 140 // AvgCounter: average of samples 141 // 142 // | * * * | * * | ... 143 // | Add(5) Add(1) Add(6) | Add(5) Add(5) | 144 // GetMetric | (5 + 1 + 6) / 3 | (5 + 5) / 2 | 145 // 146 // `include_empty_intervals`: If set, intervals without samples will be included 147 // in the stats. The value for an interval is 148 // determined by GetValueForEmptyInterval(). 149 // 150 class AvgCounter : public StatsCounter { 151 public: 152 AvgCounter(Clock* clock, 153 StatsCounterObserver* observer, 154 bool include_empty_intervals); ~AvgCounter()155 ~AvgCounter() override {} 156 157 AvgCounter(const AvgCounter&) = delete; 158 AvgCounter& operator=(const AvgCounter&) = delete; 159 160 void Add(int sample); 161 162 private: 163 bool GetMetric(int* metric) const override; 164 165 // Returns the last computed metric (i.e. from GetMetric). 166 int GetValueForEmptyInterval() const override; 167 }; 168 169 // MaxCounter: maximum of samples 170 // 171 // | * * * | * * | ... 172 // | Add(5) Add(1) Add(6) | Add(5) Add(5) | 173 // GetMetric | max: (5, 1, 6) | max: (5, 5) | 174 // 175 class MaxCounter : public StatsCounter { 176 public: 177 MaxCounter(Clock* clock, 178 StatsCounterObserver* observer, 179 int64_t process_intervals_ms); ~MaxCounter()180 ~MaxCounter() override {} 181 182 MaxCounter(const MaxCounter&) = delete; 183 MaxCounter& operator=(const MaxCounter&) = delete; 184 185 void Add(int sample); 186 187 private: 188 bool GetMetric(int* metric) const override; 189 int GetValueForEmptyInterval() const override; 190 }; 191 192 // PercentCounter: percentage of samples 193 // 194 // | * * * | * * | ... 195 // | Add(T) Add(F) Add(T) | Add(F) Add(T) | 196 // GetMetric | 100 * 2 / 3 | 100 * 1 / 2 | 197 // 198 class PercentCounter : public StatsCounter { 199 public: 200 PercentCounter(Clock* clock, StatsCounterObserver* observer); ~PercentCounter()201 ~PercentCounter() override {} 202 203 PercentCounter(const PercentCounter&) = delete; 204 PercentCounter& operator=(const PercentCounter&) = delete; 205 206 void Add(bool sample); 207 208 private: 209 bool GetMetric(int* metric) const override; 210 int GetValueForEmptyInterval() const override; 211 }; 212 213 // PermilleCounter: permille of samples 214 // 215 // | * * * | * * | ... 216 // | Add(T) Add(F) Add(T) | Add(F) Add(T) | 217 // GetMetric | 1000 * 2 / 3 | 1000 * 1 / 2 | 218 // 219 class PermilleCounter : public StatsCounter { 220 public: 221 PermilleCounter(Clock* clock, StatsCounterObserver* observer); ~PermilleCounter()222 ~PermilleCounter() override {} 223 224 PermilleCounter(const PermilleCounter&) = delete; 225 PermilleCounter& operator=(const PermilleCounter&) = delete; 226 227 void Add(bool sample); 228 229 private: 230 bool GetMetric(int* metric) const override; 231 int GetValueForEmptyInterval() const override; 232 }; 233 234 // RateCounter: units per second 235 // 236 // | * * * | * * | ... 237 // | Add(5) Add(1) Add(6) | Add(5) Add(5) | 238 // |<------ 2 sec ------->| | 239 // GetMetric | (5 + 1 + 6) / 2 | (5 + 5) / 2 | 240 // 241 // `include_empty_intervals`: If set, intervals without samples will be included 242 // in the stats. The value for an interval is 243 // determined by GetValueForEmptyInterval(). 244 // 245 class RateCounter : public StatsCounter { 246 public: 247 RateCounter(Clock* clock, 248 StatsCounterObserver* observer, 249 bool include_empty_intervals); ~RateCounter()250 ~RateCounter() override {} 251 252 RateCounter(const RateCounter&) = delete; 253 RateCounter& operator=(const RateCounter&) = delete; 254 255 void Add(int sample); 256 257 private: 258 bool GetMetric(int* metric) const override; 259 int GetValueForEmptyInterval() const override; // Returns zero. 260 }; 261 262 // RateAccCounter: units per second (used for counters) 263 // 264 // | * * * | * * | ... 265 // | Set(5) Set(6) Set(8) | Set(11) Set(13) | 266 // |<------ 2 sec ------->| | 267 // GetMetric | (8 - 0) / 2 | (13 - 8) / 2 | 268 // 269 // `include_empty_intervals`: If set, intervals without samples will be included 270 // in the stats. The value for an interval is 271 // determined by GetValueForEmptyInterval(). 272 // 273 class RateAccCounter : public StatsCounter { 274 public: 275 RateAccCounter(Clock* clock, 276 StatsCounterObserver* observer, 277 bool include_empty_intervals); ~RateAccCounter()278 ~RateAccCounter() override {} 279 280 RateAccCounter(const RateAccCounter&) = delete; 281 RateAccCounter& operator=(const RateAccCounter&) = delete; 282 283 void Set(int64_t sample, uint32_t stream_id); 284 285 // Sets the value for previous interval. 286 // To be used if a value other than zero is initially required. 287 void SetLast(int64_t sample, uint32_t stream_id); 288 289 private: 290 bool GetMetric(int* metric) const override; 291 int GetValueForEmptyInterval() const override; // Returns zero. 292 }; 293 294 } // namespace webrtc 295 296 #endif // VIDEO_STATS_COUNTER_H_ 297