• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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