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 <string>
15 
16 #include "common_types.h"  // NOLINT(build/include)
17 #include "rtc_base/atomicops.h"
18 #include "rtc_base/checks.h"
19 
20 // Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
21 // statistics.
22 //
23 // Histogram for counters.
24 // RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count);
25 //
26 // Histogram for enumerators.
27 // The boundary should be above the max enumerator sample.
28 // RTC_HISTOGRAM_ENUMERATION(name, sample, boundary);
29 //
30 //
31 // The macros use the methods HistogramFactoryGetCounts,
32 // HistogramFactoryGetEnumeration and HistogramAdd.
33 //
34 // Therefore, WebRTC clients must either:
35 //
36 // - provide implementations of
37 //   Histogram* webrtc::metrics::HistogramFactoryGetCounts(
38 //       const std::string& name, int sample, int min, int max,
39 //       int bucket_count);
40 //   Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
41 //       const std::string& name, int sample, int boundary);
42 //   void webrtc::metrics::HistogramAdd(
43 //       Histogram* histogram_pointer, const std::string& name, int sample);
44 //
45 // - or link with the default implementations (i.e.
46 //   system_wrappers:metrics_default).
47 //
48 //
49 // Example usage:
50 //
51 // RTC_HISTOGRAM_COUNTS("WebRTC.Video.NacksSent", nacks_sent, 1, 100000, 100);
52 //
53 // enum Types {
54 //   kTypeX,
55 //   kTypeY,
56 //   kBoundary,
57 // };
58 //
59 // RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary);
60 //
61 // NOTE: It is recommended to do the Chromium review for modifications to
62 // histograms.xml before new metrics are committed to WebRTC.
63 
64 // Macros for adding samples to a named histogram.
65 
66 // Histogram for counters (exponentially spaced buckets).
67 #define RTC_HISTOGRAM_COUNTS_100(name, sample) \
68   RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)
69 
70 #define RTC_HISTOGRAM_COUNTS_200(name, sample) \
71   RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)
72 
73 #define RTC_HISTOGRAM_COUNTS_500(name, sample) \
74   RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)
75 
76 #define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
77   RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)
78 
79 #define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
80   RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)
81 
82 #define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
83   RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
84 
85 #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count)       \
86   RTC_HISTOGRAM_COMMON_BLOCK(name, sample,                               \
87                              webrtc::metrics::HistogramFactoryGetCounts( \
88                                  name, min, max, bucket_count))
89 
90 #define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count)      \
91   RTC_HISTOGRAM_COMMON_BLOCK(name, sample,                                     \
92                              webrtc::metrics::HistogramFactoryGetCountsLinear( \
93                                  name, min, max, bucket_count))
94 
95 // Slow metrics: pointer to metric is acquired at each call and is not cached.
96 //
97 #define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
98   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
99 
100 #define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \
101   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 200, 50)
102 
103 #define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \
104   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 500, 50)
105 
106 #define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \
107   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 1000, 50)
108 
109 #define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \
110   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 10000, 50)
111 
112 #define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \
113   RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100000, 50)
114 
115 #define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count)     \
116   RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample,                               \
117                                   webrtc::metrics::HistogramFactoryGetCounts( \
118                                       name, min, max, bucket_count))
119 
120 // Histogram for percentage (evenly spaced buckets).
121 #define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
122   RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
123 
124 // Histogram for booleans.
125 #define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \
126   RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 2)
127 
128 // Histogram for enumerators (evenly spaced buckets).
129 // |boundary| should be above the max enumerator sample.
130 #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
131   RTC_HISTOGRAM_COMMON_BLOCK_SLOW(                               \
132       name, sample,                                              \
133       webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
134 
135 // Histogram for percentage (evenly spaced buckets).
136 #define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
137   RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
138 
139 // Histogram for booleans.
140 #define RTC_HISTOGRAM_BOOLEAN(name, sample) \
141   RTC_HISTOGRAM_ENUMERATION(name, sample, 2)
142 
143 // Histogram for enumerators (evenly spaced buckets).
144 // |boundary| should be above the max enumerator sample.
145 #define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
146   RTC_HISTOGRAM_COMMON_BLOCK(                             \
147       name, sample,                                       \
148       webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
149 
150 // The name of the histogram should not vary.
151 // TODO(asapersson): Consider changing string to const char*.
152 #define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample,                  \
153                                    factory_get_invocation)                 \
154   do {                                                                     \
155     static webrtc::metrics::Histogram* atomic_histogram_pointer = nullptr; \
156     webrtc::metrics::Histogram* histogram_pointer =                        \
157         rtc::AtomicOps::AcquireLoadPtr(&atomic_histogram_pointer);         \
158     if (!histogram_pointer) {                                              \
159       histogram_pointer = factory_get_invocation;                          \
160       webrtc::metrics::Histogram* prev_pointer =                           \
161           rtc::AtomicOps::CompareAndSwapPtr(                               \
162               &atomic_histogram_pointer,                                   \
163               static_cast<webrtc::metrics::Histogram*>(nullptr),           \
164               histogram_pointer);                                          \
165       RTC_DCHECK(prev_pointer == nullptr ||                                \
166                  prev_pointer == histogram_pointer);                       \
167     }                                                                      \
168     if (histogram_pointer) {                                               \
169       webrtc::metrics::HistogramAdd(histogram_pointer, sample);            \
170     }                                                                      \
171   } while (0)
172 
173 // Deprecated.
174 // The histogram is constructed/found for each call.
175 // May be used for histograms with infrequent updates.`
176 #define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
177   do {                                                                        \
178     webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation;   \
179     if (histogram_pointer) {                                                  \
180       webrtc::metrics::HistogramAdd(histogram_pointer, sample);               \
181     }                                                                         \
182   } while (0)
183 
184 // Helper macros.
185 // Macros for calling a histogram with varying name (e.g. when using a metric
186 // in different modes such as real-time vs screenshare). Fast, because pointer
187 // is cached. |index| should be different for different names. Allowed |index|
188 // values are 0, 1, and 2.
189 #define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \
190   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
191                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50))
192 
193 #define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \
194   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
195                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50))
196 
197 #define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \
198   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
199                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50))
200 
201 #define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
202   RTC_HISTOGRAMS_COMMON(index, name, sample,            \
203                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50))
204 
205 #define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
206   RTC_HISTOGRAMS_COMMON(index, name, sample,             \
207                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50))
208 
209 #define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
210   RTC_HISTOGRAMS_COMMON(index, name, sample,              \
211                         RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50))
212 
213 #define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
214   RTC_HISTOGRAMS_COMMON(index, name, sample,                      \
215                         RTC_HISTOGRAM_ENUMERATION(name, sample, boundary))
216 
217 #define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \
218   RTC_HISTOGRAMS_COMMON(index, name, sample,           \
219                         RTC_HISTOGRAM_PERCENTAGE(name, sample))
220 
221 #define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
222   do {                                                               \
223     switch (index) {                                                 \
224       case 0:                                                        \
225         macro_invocation;                                            \
226         break;                                                       \
227       case 1:                                                        \
228         macro_invocation;                                            \
229         break;                                                       \
230       case 2:                                                        \
231         macro_invocation;                                            \
232         break;                                                       \
233       default:                                                       \
234         RTC_NOTREACHED();                                            \
235     }                                                                \
236   } while (0)
237 
238 namespace webrtc {
239 namespace metrics {
240 
241 // Time that should have elapsed for stats that are gathered once per call.
242 enum { kMinRunTimeInSeconds = 10 };
243 
244 class Histogram;
245 
246 // Functions for getting pointer to histogram (constructs or finds the named
247 // histogram).
248 
249 // Get histogram for counters.
250 Histogram* HistogramFactoryGetCounts(const std::string& name,
251                                      int min,
252                                      int max,
253                                      int bucket_count);
254 
255 // Get histogram for counters with linear bucket spacing.
256 Histogram* HistogramFactoryGetCountsLinear(const std::string& name,
257                                            int min,
258                                            int max,
259                                            int bucket_count);
260 
261 // Get histogram for enumerators.
262 // |boundary| should be above the max enumerator sample.
263 Histogram* HistogramFactoryGetEnumeration(const std::string& name,
264                                           int boundary);
265 
266 // Function for adding a |sample| to a histogram.
267 void HistogramAdd(Histogram* histogram_pointer, int sample);
268 
269 }  // namespace metrics
270 }  // namespace webrtc
271 
272 #endif  // SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
273