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