xref: /aosp_15_r20/external/webrtc/system_wrappers/include/metrics.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 //
2 // Copyright (c) 2014 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 SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
12 #define SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
13 
14 #include <stddef.h>
15 
16 #include <atomic>
17 #include <map>
18 #include <memory>
19 #include <string>
20 
21 #include "absl/strings/string_view.h"
22 #include "rtc_base/checks.h"
23 #include "rtc_base/string_utils.h"
24 
25 #if defined(RTC_DISABLE_METRICS)
26 #define RTC_METRICS_ENABLED 0
27 #else
28 #define RTC_METRICS_ENABLED 1
29 #endif
30 
31 namespace webrtc {
32 namespace metrics_impl {
33 template <typename... Ts>
NoOp(const Ts &...)34 void NoOp(const Ts&...) {}
35 }
36 }
37 
38 #if RTC_METRICS_ENABLED
39 #define EXPECT_METRIC_EQ(val1, val2) EXPECT_EQ(val1, val2)
40 #define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) \
41   EXPECT_EQ_WAIT(val1, val2, timeout)
42 #define EXPECT_METRIC_GT(val1, val2) EXPECT_GT(val1, val2)
43 #define EXPECT_METRIC_LE(val1, val2) EXPECT_LE(val1, val2)
44 #define EXPECT_METRIC_TRUE(conditon) EXPECT_TRUE(conditon)
45 #define EXPECT_METRIC_FALSE(conditon) EXPECT_FALSE(conditon)
46 #define EXPECT_METRIC_THAT(value, matcher) EXPECT_THAT(value, matcher)
47 #else
48 #define EXPECT_METRIC_EQ(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
49 #define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) webrtc::metrics_impl::NoOp(val1, val2, timeout)
50 #define EXPECT_METRIC_GT(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
51 #define EXPECT_METRIC_LE(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
52 #define EXPECT_METRIC_TRUE(condition) webrtc::metrics_impl::NoOp(condition || true)
53 #define EXPECT_METRIC_FALSE(condition) webrtc::metrics_impl::NoOp(condition && false)
54 #define EXPECT_METRIC_THAT(value, matcher) webrtc::metrics_impl::NoOp(value, testing::_)
55 #endif
56 
57 #if RTC_METRICS_ENABLED
58 // Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
59 // statistics.
60 //
61 // Histogram for counters.
62 // RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count);
63 //
64 // Histogram for enumerators.
65 // The boundary should be above the max enumerator sample.
66 // RTC_HISTOGRAM_ENUMERATION(name, sample, boundary);
67 //
68 //
69 // The macros use the methods HistogramFactoryGetCounts,
70 // HistogramFactoryGetEnumeration and HistogramAdd.
71 //
72 // By default WebRTC provides implementations of the aforementioned methods
73 // that can be found in system_wrappers/source/metrics.cc. If clients want to
74 // provide a custom version, they will have to:
75 //
76 // 1. Compile WebRTC defining the preprocessor macro
77 //    WEBRTC_EXCLUDE_METRICS_DEFAULT (if GN is used this can be achieved
78 //    by setting the GN arg rtc_exclude_metrics_default to true).
79 // 2. Provide implementations of:
80 //    Histogram* webrtc::metrics::HistogramFactoryGetCounts(
81 //        absl::string_view name, int sample, int min, int max,
82 //        int bucket_count);
83 //    Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
84 //        absl::string_view name, int sample, int boundary);
85 //    void webrtc::metrics::HistogramAdd(
86 //        Histogram* histogram_pointer, absl::string_view name, int sample);
87 //
88 // Example usage:
89 //
90 // RTC_HISTOGRAM_COUNTS("WebRTC.Video.NacksSent", nacks_sent, 1, 100000, 100);
91 //
92 // enum Types {
93 //   kTypeX,
94 //   kTypeY,
95 //   kBoundary,
96 // };
97 //
98 // RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary);
99 //
100 // NOTE: It is recommended to do the Chromium review for modifications to
101 // histograms.xml before new metrics are committed to WebRTC.
102 
103 // Macros for adding samples to a named histogram.
104 
105 // Histogram for counters (exponentially spaced buckets).
106 #define RTC_HISTOGRAM_COUNTS_100(name, sample) \
107   RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)
108 
109 #define RTC_HISTOGRAM_COUNTS_200(name, sample) \
110   RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)
111 
112 #define RTC_HISTOGRAM_COUNTS_500(name, sample) \
113   RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)
114 
115 #define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
116   RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)
117 
118 #define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
119   RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)
120 
121 #define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
122   RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
123 
124 #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count)       \
125   RTC_HISTOGRAM_COMMON_BLOCK(name, sample,                               \
126                              webrtc::metrics::HistogramFactoryGetCounts( \
127                                  name, min, max, bucket_count))
128 
129 #define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count)      \
130   RTC_HISTOGRAM_COMMON_BLOCK(name, sample,                                     \
131                              webrtc::metrics::HistogramFactoryGetCountsLinear( \
132                                  name, min, max, bucket_count))
133 
134 // Slow metrics: pointer to metric is acquired at each call and is not cached.
135 //
136 #define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
137   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
138 
139 #define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \
140   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 200, 50)
141 
142 #define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \
143   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 500, 50)
144 
145 #define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \
146   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 1000, 50)
147 
148 #define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \
149   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 10000, 50)
150 
151 #define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \
152   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100000, 50)
153 
154 #define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count)     \
155   RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample,                               \
156                                   webrtc::metrics::HistogramFactoryGetCounts( \
157                                       name, min, max, bucket_count))
158 
159 // Histogram for percentage (evenly spaced buckets).
160 #define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
161   RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
162 
163 // Histogram for booleans.
164 #define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \
165   RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 2)
166 
167 // Histogram for enumerators (evenly spaced buckets).
168 // `boundary` should be above the max enumerator sample.
169 //
170 // TODO(qingsi): Refactor the default implementation given by RtcHistogram,
171 // which is already sparse, and remove the boundary argument from the macro.
172 #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
173   RTC_HISTOGRAM_COMMON_BLOCK_SLOW(                               \
174       name, sample,                                              \
175       webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary))
176 
177 // Histogram for percentage (evenly spaced buckets).
178 #define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
179   RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
180 
181 // Histogram for booleans.
182 #define RTC_HISTOGRAM_BOOLEAN(name, sample) \
183   RTC_HISTOGRAM_ENUMERATION(name, sample, 2)
184 
185 // Histogram for enumerators (evenly spaced buckets).
186 // `boundary` should be above the max enumerator sample.
187 #define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
188   RTC_HISTOGRAM_COMMON_BLOCK_SLOW(                        \
189       name, sample,                                       \
190       webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
191 
192 // The name of the histogram should not vary.
193 #define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample,                     \
194                                    factory_get_invocation)                    \
195   do {                                                                        \
196     static std::atomic<webrtc::metrics::Histogram*> atomic_histogram_pointer( \
197         nullptr);                                                             \
198     webrtc::metrics::Histogram* histogram_pointer =                           \
199         atomic_histogram_pointer.load(std::memory_order_acquire);             \
200     if (!histogram_pointer) {                                                 \
201       histogram_pointer = factory_get_invocation;                             \
202       webrtc::metrics::Histogram* null_histogram = nullptr;                   \
203       atomic_histogram_pointer.compare_exchange_strong(null_histogram,        \
204                                                        histogram_pointer);    \
205     }                                                                         \
206     if (histogram_pointer) {                                                  \
207       webrtc::metrics::HistogramAdd(histogram_pointer, sample);               \
208     }                                                                         \
209   } while (0)
210 
211 // The histogram is constructed/found for each call.
212 // May be used for histograms with infrequent updates.`
213 #define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
214   do {                                                                        \
215     webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation;   \
216     if (histogram_pointer) {                                                  \
217       webrtc::metrics::HistogramAdd(histogram_pointer, sample);               \
218     }                                                                         \
219   } while (0)
220 
221 // Helper macros.
222 // Macros for calling a histogram with varying name (e.g. when using a metric
223 // in different modes such as real-time vs screenshare). Fast, because pointer
224 // is cached. `index` should be different for different names. Allowed `index`
225 // values are 0, 1, and 2.
226 #define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \
227   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
228                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50))
229 
230 #define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \
231   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
232                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50))
233 
234 #define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \
235   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
236                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50))
237 
238 #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
239   RTC_HISTOGRAMS_COMMON(index, name, sample,            \
240                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50))
241 
242 #define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
243   RTC_HISTOGRAMS_COMMON(index, name, sample,             \
244                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50))
245 
246 #define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
247   RTC_HISTOGRAMS_COMMON(index, name, sample,              \
248                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50))
249 
250 #define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
251   RTC_HISTOGRAMS_COMMON(index, name, sample,                      \
252                         RTC_HISTOGRAM_ENUMERATION(name, sample, boundary))
253 
254 #define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \
255   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
256                         RTC_HISTOGRAM_PERCENTAGE(name, sample))
257 
258 #define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
259   do {                                                               \
260     switch (index) {                                                 \
261       case 0:                                                        \
262         macro_invocation;                                            \
263         break;                                                       \
264       case 1:                                                        \
265         macro_invocation;                                            \
266         break;                                                       \
267       case 2:                                                        \
268         macro_invocation;                                            \
269         break;                                                       \
270       default:                                                       \
271         RTC_DCHECK_NOTREACHED();                                     \
272     }                                                                \
273   } while (0)
274 
275 #else
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 // This section defines no-op alternatives to the metrics macros when
279 // RTC_METRICS_ENABLED is defined.
280 
281 #define RTC_HISTOGRAM_COUNTS_100(name, sample) webrtc::metrics_impl::NoOp(name, sample)
282 
283 #define RTC_HISTOGRAM_COUNTS_200(name, sample) webrtc::metrics_impl::NoOp(name, sample)
284 
285 #define RTC_HISTOGRAM_COUNTS_500(name, sample) webrtc::metrics_impl::NoOp(name, sample)
286 
287 #define RTC_HISTOGRAM_COUNTS_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
288 
289 #define RTC_HISTOGRAM_COUNTS_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
290 
291 #define RTC_HISTOGRAM_COUNTS_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
292 
293 #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
294   webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
295 
296 #define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \
297   webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
298 
299 #define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) webrtc::metrics_impl::NoOp(name, sample)
300 
301 #define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) webrtc::metrics_impl::NoOp(name, sample)
302 
303 #define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) webrtc::metrics_impl::NoOp(name, sample)
304 
305 #define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
306 
307 #define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
308 
309 #define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
310 
311 #define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
312   webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
313 
314 #define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
315 
316 #define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
317 
318 #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
319   webrtc::metrics_impl::NoOp(name, sample, boundary)
320 
321 #define RTC_HISTOGRAM_PERCENTAGE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
322 
323 #define RTC_HISTOGRAM_BOOLEAN(name, sample) webrtc::metrics_impl::NoOp(name, sample)
324 
325 #define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
326   webrtc::metrics_impl::NoOp(name, sample, boundary)
327 
328 #define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample,  \
329                                    factory_get_invocation) \
330   webrtc::metrics_impl::NoOp(constant_name, sample, factory_get_invocation)
331 
332 #define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
333   webrtc::metrics_impl::NoOp(name, sample, factory_get_invocation)
334 
335 #define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
336 
337 #define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
338 
339 #define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
340 
341 #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
342   webrtc::metrics_impl::NoOp(index, name, sample)
343 
344 #define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
345   webrtc::metrics_impl::NoOp(index, name, sample)
346 
347 #define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
348   webrtc::metrics_impl::NoOp(index, name, sample)
349 
350 #define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
351   webrtc::metrics_impl::NoOp(index, name, sample, boundary)
352 
353 #define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
354 
355 #define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
356   webrtc::metrics_impl::NoOp(index, name, sample, macro_invocation)
357 
358 #endif  // RTC_METRICS_ENABLED
359 
360 namespace webrtc {
361 namespace metrics {
362 
363 // Time that should have elapsed for stats that are gathered once per call.
364 constexpr int kMinRunTimeInSeconds = 10;
365 
366 class Histogram;
367 
368 // Functions for getting pointer to histogram (constructs or finds the named
369 // histogram).
370 
371 // Get histogram for counters.
372 Histogram* HistogramFactoryGetCounts(absl::string_view name,
373                                      int min,
374                                      int max,
375                                      int bucket_count);
376 
377 // Get histogram for counters with linear bucket spacing.
378 Histogram* HistogramFactoryGetCountsLinear(absl::string_view name,
379                                            int min,
380                                            int max,
381                                            int bucket_count);
382 
383 // Get histogram for enumerators.
384 // `boundary` should be above the max enumerator sample.
385 Histogram* HistogramFactoryGetEnumeration(absl::string_view name, int boundary);
386 
387 // Get sparse histogram for enumerators.
388 // `boundary` should be above the max enumerator sample.
389 Histogram* SparseHistogramFactoryGetEnumeration(absl::string_view name,
390                                                 int boundary);
391 
392 // Function for adding a `sample` to a histogram.
393 void HistogramAdd(Histogram* histogram_pointer, int sample);
394 
395 struct SampleInfo {
396   SampleInfo(absl::string_view name, int min, int max, size_t bucket_count);
397   ~SampleInfo();
398 
399   const std::string name;
400   const int min;
401   const int max;
402   const size_t bucket_count;
403   std::map<int, int> samples;  // <value, # of events>
404 };
405 
406 // Enables collection of samples.
407 // This method should be called before any other call into webrtc.
408 void Enable();
409 
410 // Gets histograms and clears all samples.
411 void GetAndReset(
412     std::map<std::string, std::unique_ptr<SampleInfo>, rtc::AbslStringViewCmp>*
413         histograms);
414 
415 // Functions below are mainly for testing.
416 
417 // Clears all samples.
418 void Reset();
419 
420 // Returns the number of times the `sample` has been added to the histogram.
421 int NumEvents(absl::string_view name, int sample);
422 
423 // Returns the total number of added samples to the histogram.
424 int NumSamples(absl::string_view name);
425 
426 // Returns the minimum sample value (or -1 if the histogram has no samples).
427 int MinSample(absl::string_view name);
428 
429 // Returns a map with keys the samples with at least one event and values the
430 // number of events for that sample.
431 std::map<int, int> Samples(absl::string_view name);
432 
433 }  // namespace metrics
434 }  // namespace webrtc
435 
436 #endif  // SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
437