xref: /aosp_15_r20/external/webrtc/video/stats_counter.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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