1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_METRICS_HISTOGRAM_FUNCTIONS_H_
6 #define BASE_METRICS_HISTOGRAM_FUNCTIONS_H_
7
8 #include <stdint.h>
9
10 #include <string>
11 #include <string_view>
12 #include <type_traits>
13
14 #include "base/base_export.h"
15 #include "base/check_op.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/histogram_base.h"
18 #include "base/metrics/histogram_functions_internal_overloads.h" // IWYU pragma: export
19 #include "base/time/time.h"
20
21 // TODO(crbug.com/40801421): Update this file's function comments to provide
22 // more detail, like histogram_macros.h.
23 //
24 // Functions for recording metrics.
25 //
26 // For best practices on deciding when to emit to a histogram and what form
27 // the histogram should take, see
28 // https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md
29 //
30 // For deciding whether to use the function or macro APIs, see
31 // https://chromium.googlesource.com/chromium/src/+/HEAD/tools/metrics/histograms/README.md#coding-emitting-to-histograms"
32 //
33 // Every function is duplicated to also support both std::string and char* for
34 // the name for improved binary size. These declarations are moved to a separate
35 // header for readability, see
36 // https://chromium.googlesource.com/chromium/src/+/HEAD/base/metrics/histogram_functions_internal_overloads.h.
37 namespace base {
38
39 // For numeric measurements where you want exact integer values up to
40 // |exclusive_max|. |exclusive_max| itself is included in the overflow bucket.
41 // Therefore, if you want an accurate measure up to kMax, then |exclusive_max|
42 // should be set to kMax + 1.
43 //
44 // |exclusive_max| should be 101 or less. If you need to capture a larger range,
45 // we recommend the use of the COUNT histograms below.
46 //
47 // Sample usage:
48 // base::UmaHistogramExactLinear("Histogram.Linear", sample, kMax + 1);
49 // In this case, buckets are 1, 2, .., kMax, kMax+1, where the kMax+1 bucket
50 // captures everything kMax+1 and above.
51 // LINT.IfChange(UmaHistogramExactLinear)
52 BASE_EXPORT void UmaHistogramExactLinear(std::string_view name,
53 int sample,
54 int exclusive_max);
55 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramExactLinear)
56
57 // For adding a sample to an enumerated histogram.
58 // Sample usage:
59 // // These values are persisted to logs. Entries should not be renumbered and
60 // // numeric values should never be reused.
61 // enum class NewTabPageAction {
62 // kUseOmnibox = 0,
63 // kClickTitle = 1,
64 // // kUseSearchbox = 2, // no longer used, combined into omnibox
65 // kOpenBookmark = 3,
66 // kMaxValue = kOpenBookmark,
67 // };
68 // base::UmaHistogramEnumeration("My.Enumeration",
69 // NewTabPageAction::kClickTitle);
70 //
71 // Note that there are code that refer implementation details of this function.
72 // Keep them synchronized.
73 // LINT.IfChange(UmaHistogramEnumeration)
74 template <typename T>
UmaHistogramEnumeration(std::string_view name,T sample)75 void UmaHistogramEnumeration(std::string_view name, T sample) {
76 static_assert(std::is_enum_v<T>, "T is not an enum.");
77 // This also ensures that an enumeration that doesn't define kMaxValue fails
78 // with a semi-useful error ("no member named 'kMaxValue' in ...").
79 static_assert(static_cast<uintmax_t>(T::kMaxValue) <=
80 static_cast<uintmax_t>(INT_MAX) - 1,
81 "Enumeration's kMaxValue is out of range of INT_MAX!");
82 DCHECK_LE(static_cast<uintmax_t>(sample),
83 static_cast<uintmax_t>(T::kMaxValue));
84 return UmaHistogramExactLinear(name, static_cast<int>(sample),
85 static_cast<int>(T::kMaxValue) + 1);
86 }
87
88 // Some legacy histograms may manually specify the enum size, with a kCount,
89 // COUNT, kMaxValue, or MAX_VALUE sentinel like so:
90 // // These values are persisted to logs. Entries should not be renumbered and
91 // // numeric values should never be reused.
92 // enum class NewTabPageAction {
93 // kUseOmnibox = 0,
94 // kClickTitle = 1,
95 // // kUseSearchbox = 2, // no longer used, combined into omnibox
96 // kOpenBookmark = 3,
97 // kCount,
98 // };
99 // base::UmaHistogramEnumeration("My.Enumeration",
100 // NewTabPageAction::kClickTitle,
101 // kCount);
102 // Note: The value in |sample| must be strictly less than |enum_size|. This is
103 // otherwise functionally equivalent to the above.
104 template <typename T>
UmaHistogramEnumeration(std::string_view name,T sample,T enum_size)105 void UmaHistogramEnumeration(std::string_view name, T sample, T enum_size) {
106 static_assert(std::is_enum_v<T>, "T is not an enum.");
107 DCHECK_LE(static_cast<uintmax_t>(enum_size), static_cast<uintmax_t>(INT_MAX));
108 DCHECK_LT(static_cast<uintmax_t>(sample), static_cast<uintmax_t>(enum_size));
109 return UmaHistogramExactLinear(name, static_cast<int>(sample),
110 static_cast<int>(enum_size));
111 }
112 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramEnumeration)
113
114 // For adding boolean sample to histogram.
115 // Sample usage:
116 // base::UmaHistogramBoolean("My.Boolean", true)
117 // LINT.IfChange(UmaHistogramBoolean)
118 BASE_EXPORT void UmaHistogramBoolean(std::string_view name, bool sample);
119 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramBoolean)
120
121 // For adding histogram sample denoting a percentage.
122 // Percents are integers between 1 and 100, inclusively.
123 // Sample usage:
124 // base::UmaHistogramPercentage("My.Percent", 69)
125 // LINT.IfChange(UmaHistogramPercentage)
126 BASE_EXPORT void UmaHistogramPercentage(std::string_view name, int percent);
127
128 // Obsolete. Use |UmaHistogramPercentage| instead. See crbug/1121318.
129 BASE_EXPORT void UmaHistogramPercentageObsoleteDoNotUse(std::string_view name,
130 int percent);
131 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramPercentage)
132
133 // For adding counts histogram.
134 // Sample usage:
135 // base::UmaHistogramCustomCounts("My.Counts", some_value, 1, 600, 30)
136 // LINT.IfChange(UmaHistogramCounts)
137 BASE_EXPORT void UmaHistogramCustomCounts(std::string_view name,
138 int sample,
139 int min,
140 int exclusive_max,
141 size_t buckets);
142
143 // Counts specialization for maximum counts 100, 1000, 10k, 100k, 1M and 10M.
144 BASE_EXPORT void UmaHistogramCounts100(std::string_view name, int sample);
145 BASE_EXPORT void UmaHistogramCounts1000(std::string_view name, int sample);
146 BASE_EXPORT void UmaHistogramCounts10000(std::string_view name, int sample);
147 BASE_EXPORT void UmaHistogramCounts100000(std::string_view name, int sample);
148 BASE_EXPORT void UmaHistogramCounts1M(std::string_view name, int sample);
149 BASE_EXPORT void UmaHistogramCounts10M(std::string_view name, int sample);
150 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramCounts)
151
152 // For histograms storing times. It uses milliseconds granularity.
153 // LINT.IfChange(UmaHistogramTimes)
154 BASE_EXPORT void UmaHistogramCustomTimes(std::string_view name,
155 TimeDelta sample,
156 TimeDelta min,
157 TimeDelta max,
158 size_t buckets);
159
160 // Reference ScopedUmaHistogramTimer::ScopedHistogramTiming for timing.
161 // For short timings from 1 ms up to 10 seconds (50 buckets).
162 BASE_EXPORT void UmaHistogramTimes(std::string_view name, TimeDelta sample);
163
164 // For medium timings up to 3 minutes (50 buckets).
165 BASE_EXPORT void UmaHistogramMediumTimes(std::string_view name,
166 TimeDelta sample);
167 // For time intervals up to 1 hr (50 buckets).
168 BASE_EXPORT void UmaHistogramLongTimes(std::string_view name, TimeDelta sample);
169
170 // For time intervals up to 1 hr (100 buckets).
171 BASE_EXPORT void UmaHistogramLongTimes100(std::string_view name,
172 TimeDelta sample);
173 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramTimes)
174
175 // For histograms storing times with microseconds granularity.
176 // LINT.IfChange(UmaHistogramMicrosecondsTimes)
177 BASE_EXPORT void UmaHistogramCustomMicrosecondsTimes(std::string_view name,
178 TimeDelta sample,
179 TimeDelta min,
180 TimeDelta max,
181 size_t buckets);
182
183 // For microseconds timings from 1 microsecond up to 10 seconds (50 buckets).
184 BASE_EXPORT void UmaHistogramMicrosecondsTimes(std::string_view name,
185 TimeDelta sample);
186 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramMicrosecondsTimes)
187
188 // For recording memory related histograms.
189 // LINT.IfChange(UmaHistogramMemory)
190 // Used to measure common KB-granularity memory stats. Range is up to 500M.
191 BASE_EXPORT void UmaHistogramMemoryKB(std::string_view name, int sample);
192 // Used to measure common MB-granularity memory stats. Range is up to ~1G.
193 BASE_EXPORT void UmaHistogramMemoryMB(std::string_view name, int sample);
194 // Used to measure common MB-granularity memory stats. Range is up to ~64G.
195 BASE_EXPORT void UmaHistogramMemoryLargeMB(std::string_view name, int sample);
196 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramMemory)
197
198 // For recording sparse histograms.
199 // The |sample| can be a negative or non-negative number.
200 //
201 // Sparse histograms are well suited for recording counts of exact sample values
202 // that are sparsely distributed over a relatively large range, in cases where
203 // ultra-fast performance is not critical. For instance, Sqlite.Version.* are
204 // sparse because for any given database, there's going to be exactly one
205 // version logged.
206 //
207 // Performance:
208 // ------------
209 // Sparse histograms are typically more memory-efficient but less time-efficient
210 // than other histograms. Essentially, they sparse histograms use a map rather
211 // than a vector for their backing storage; they also require lock acquisition
212 // to increment a sample, whereas other histogram do not. Hence, each increment
213 // operation is a bit slower than for other histograms. But, if the data is
214 // sparse, then they use less memory client-side, because they allocate buckets
215 // on demand rather than preallocating.
216 //
217 // Data size:
218 // ----------
219 // Note that server-side, we still need to load all buckets, across all users,
220 // at once. Thus, please avoid exploding such histograms, i.e. uploading many
221 // many distinct values to the server (across all users). Concretely, keep the
222 // number of distinct values <= 100 ideally, definitely <= 1000. If you have no
223 // guarantees on the range of your data, use clamping, e.g.:
224 // UmaHistogramSparse("My.Histogram", std::clamp(value, 0, 200));
225 // LINT.IfChange(UmaHistogramSparse)
226 BASE_EXPORT void UmaHistogramSparse(std::string_view name, int sample);
227 // LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramSparse)
228
229 // Scoped class which logs its time on this earth in milliseconds as an UMA
230 // histogram. This is recommended for when you want a histogram which measures
231 // the time it takes for a method to execute. It uses UmaHistogramTimes() and
232 // its variations under the hood.
233 //
234 // This is equivalent to SCOPED_UMA_HISTOGRAM_TIMER.
235 //
236 // Sample usages:
237 // void Function() {
238 // ScopedUmaHistogramTimer("Component.FunctionTime");
239 // // useful stuff here
240 // ...
241 // }
242 //
243 // void Function() {
244 // ScopedUmaHistogramTimer("Component.FunctionTime",
245 // ScopedUmaHistogramTimer::kMicroSecondTimes);
246 // // useful stuff here
247 // ...
248 // }
249 class BASE_EXPORT ScopedUmaHistogramTimer {
250 public:
251 // Reference UmaHistogramTiming() function declarations for timing details
252 // below.
253 enum class ScopedHistogramTiming {
254 // For microseconds timings from 1 microsecond up to 10 seconds (50
255 // buckets).
256 kMicrosecondTimes,
257 // For short timings from 1 ms up to 10 seconds (50 buckets).
258 kShortTimes,
259 // For medium timings up to 3 minutes (50 buckets).
260 kMediumTimes,
261 // For time intervals up to 1 hr (50 buckets).
262 kLongTimes
263 };
264
265 // Constructs the scoped timer with the given histogram name.
266 explicit ScopedUmaHistogramTimer(
267 std::string_view name,
268 ScopedHistogramTiming timing = ScopedHistogramTiming::kShortTimes);
269
270 ScopedUmaHistogramTimer(const ScopedUmaHistogramTimer&) = delete;
271 ScopedUmaHistogramTimer& operator=(const ScopedUmaHistogramTimer&) = delete;
272
273 ~ScopedUmaHistogramTimer();
274
275 private:
276 const base::TimeTicks constructed_;
277 const ScopedHistogramTiming timing_;
278 const std::string name_;
279 };
280
281 } // namespace base
282
283 #endif // BASE_METRICS_HISTOGRAM_FUNCTIONS_H_
284