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