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