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