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