1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283

base / metrics / histogram_functions.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_METRICS_HISTOGRAM_FUNCTIONS_H_
#define BASE_METRICS_HISTOGRAM_FUNCTIONS_H_

#include <stdint.h>

#include <string>
#include <string_view>
#include <type_traits>

#include "base/base_export.h"
#include "base/check_op.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_functions_internal_overloads.h"  // IWYU pragma: export
#include "base/time/time.h"

// TODO(crbug.com/40801421): Update this file's function comments to provide
// more detail, like histogram_macros.h.
//
// Functions for recording metrics.
//
// For best practices on deciding when to emit to a histogram and what form
// the histogram should take, see
// https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md
//
// For deciding whether to use the function or macro APIs, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/tools/metrics/histograms/README.md#coding-emitting-to-histograms"
//
// Every function is duplicated to also support both std::string and char* for
// the name for improved binary size. These declarations are moved to a separate
// header for readability, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/base/metrics/histogram_functions_internal_overloads.h.
namespace base {

// For numeric measurements where you want exact integer values up to
// |exclusive_max|. |exclusive_max| itself is included in the overflow bucket.
// Therefore, if you want an accurate measure up to kMax, then |exclusive_max|
// should be set to kMax + 1.
//
// |exclusive_max| should be 101 or less. If you need to capture a larger range,
// we recommend the use of the COUNT histograms below.
//
// Sample usage:
//   base::UmaHistogramExactLinear("Histogram.Linear", sample, kMax + 1);
// In this case, buckets are 1, 2, .., kMax, kMax+1, where the kMax+1 bucket
// captures everything kMax+1 and above.
// LINT.IfChange(UmaHistogramExactLinear)
BASE_EXPORT void UmaHistogramExactLinear(std::string_view name,
                                         int sample,
                                         int exclusive_max);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramExactLinear)

// For adding a sample to an enumerated histogram.
// Sample usage:
//   // These values are persisted to logs. Entries should not be renumbered and
//   // numeric values should never be reused.
//   enum class NewTabPageAction {
//     kUseOmnibox = 0,
//     kClickTitle = 1,
//     // kUseSearchbox = 2,  // no longer used, combined into omnibox
//     kOpenBookmark = 3,
//     kMaxValue = kOpenBookmark,
//   };
//   base::UmaHistogramEnumeration("My.Enumeration",
//                                 NewTabPageAction::kClickTitle);
//
// Note that there are code that refer implementation details of this function.
// Keep them synchronized.
// LINT.IfChange(UmaHistogramEnumeration)
template <typename T>
void UmaHistogramEnumeration(std::string_view name, T sample) {
  static_assert(std::is_enum_v<T>, "T is not an enum.");
  // This also ensures that an enumeration that doesn't define kMaxValue fails
  // with a semi-useful error ("no member named 'kMaxValue' in ...").
  static_assert(static_cast<uintmax_t>(T::kMaxValue) <=
                    static_cast<uintmax_t>(INT_MAX) - 1,
                "Enumeration's kMaxValue is out of range of INT_MAX!");
  DCHECK_LE(static_cast<uintmax_t>(sample),
            static_cast<uintmax_t>(T::kMaxValue));
  return UmaHistogramExactLinear(name, static_cast<int>(sample),
                                 static_cast<int>(T::kMaxValue) + 1);
}

// Some legacy histograms may manually specify the enum size, with a kCount,
// COUNT, kMaxValue, or MAX_VALUE sentinel like so:
//   // These values are persisted to logs. Entries should not be renumbered and
//   // numeric values should never be reused.
//   enum class NewTabPageAction {
//     kUseOmnibox = 0,
//     kClickTitle = 1,
//     // kUseSearchbox = 2,  // no longer used, combined into omnibox
//     kOpenBookmark = 3,
//     kCount,
//   };
//   base::UmaHistogramEnumeration("My.Enumeration",
//                                 NewTabPageAction::kClickTitle,
//                                 kCount);
// Note: The value in |sample| must be strictly less than |enum_size|. This is
// otherwise functionally equivalent to the above.
template <typename T>
void UmaHistogramEnumeration(std::string_view name, T sample, T enum_size) {
  static_assert(std::is_enum_v<T>, "T is not an enum.");
  DCHECK_LE(static_cast<uintmax_t>(enum_size), static_cast<uintmax_t>(INT_MAX));
  DCHECK_LT(static_cast<uintmax_t>(sample), static_cast<uintmax_t>(enum_size));
  return UmaHistogramExactLinear(name, static_cast<int>(sample),
                                 static_cast<int>(enum_size));
}
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramEnumeration)

// For adding boolean sample to histogram.
// Sample usage:
//   base::UmaHistogramBoolean("My.Boolean", true)
// LINT.IfChange(UmaHistogramBoolean)
BASE_EXPORT void UmaHistogramBoolean(std::string_view name, bool sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramBoolean)

// For adding histogram sample denoting a percentage.
// Percents are integers between 1 and 100, inclusively.
// Sample usage:
//   base::UmaHistogramPercentage("My.Percent", 69)
// LINT.IfChange(UmaHistogramPercentage)
BASE_EXPORT void UmaHistogramPercentage(std::string_view name, int percent);

// Obsolete. Use |UmaHistogramPercentage| instead. See crbug/1121318.
BASE_EXPORT void UmaHistogramPercentageObsoleteDoNotUse(std::string_view name,
                                                        int percent);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramPercentage)

// For adding counts histogram.
// Sample usage:
//   base::UmaHistogramCustomCounts("My.Counts", some_value, 1, 600, 30)
// LINT.IfChange(UmaHistogramCounts)
BASE_EXPORT void UmaHistogramCustomCounts(std::string_view name,
                                          int sample,
                                          int min,
                                          int exclusive_max,
                                          size_t buckets);

// Counts specialization for maximum counts 100, 1000, 10k, 100k, 1M and 10M.
BASE_EXPORT void UmaHistogramCounts100(std::string_view name, int sample);
BASE_EXPORT void UmaHistogramCounts1000(std::string_view name, int sample);
BASE_EXPORT void UmaHistogramCounts10000(std::string_view name, int sample);
BASE_EXPORT void UmaHistogramCounts100000(std::string_view name, int sample);
BASE_EXPORT void UmaHistogramCounts1M(std::string_view name, int sample);
BASE_EXPORT void UmaHistogramCounts10M(std::string_view name, int sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramCounts)

// For histograms storing times. It uses milliseconds granularity.
// LINT.IfChange(UmaHistogramTimes)
BASE_EXPORT void UmaHistogramCustomTimes(std::string_view name,
                                         TimeDelta sample,
                                         TimeDelta min,
                                         TimeDelta max,
                                         size_t buckets);

// Reference ScopedUmaHistogramTimer::ScopedHistogramTiming for timing.
// For short timings from 1 ms up to 10 seconds (50 buckets).
BASE_EXPORT void UmaHistogramTimes(std::string_view name, TimeDelta sample);

// For medium timings up to 3 minutes (50 buckets).
BASE_EXPORT void UmaHistogramMediumTimes(std::string_view name,
                                         TimeDelta sample);
// For time intervals up to 1 hr (50 buckets).
BASE_EXPORT void UmaHistogramLongTimes(std::string_view name, TimeDelta sample);

// For time intervals up to 1 hr (100 buckets).
BASE_EXPORT void UmaHistogramLongTimes100(std::string_view name,
                                          TimeDelta sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramTimes)

// For histograms storing times with microseconds granularity.
// LINT.IfChange(UmaHistogramMicrosecondsTimes)
BASE_EXPORT void UmaHistogramCustomMicrosecondsTimes(std::string_view name,
                                                     TimeDelta sample,
                                                     TimeDelta min,
                                                     TimeDelta max,
                                                     size_t buckets);

// For microseconds timings from 1 microsecond up to 10 seconds (50 buckets).
BASE_EXPORT void UmaHistogramMicrosecondsTimes(std::string_view name,
                                               TimeDelta sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramMicrosecondsTimes)

// For recording memory related histograms.
// LINT.IfChange(UmaHistogramMemory)
// Used to measure common KB-granularity memory stats. Range is up to 500M.
BASE_EXPORT void UmaHistogramMemoryKB(std::string_view name, int sample);
// Used to measure common MB-granularity memory stats. Range is up to ~1G.
BASE_EXPORT void UmaHistogramMemoryMB(std::string_view name, int sample);
// Used to measure common MB-granularity memory stats. Range is up to ~64G.
BASE_EXPORT void UmaHistogramMemoryLargeMB(std::string_view name, int sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramMemory)

// For recording sparse histograms.
// The |sample| can be a negative or non-negative number.
//
// Sparse histograms are well suited for recording counts of exact sample values
// that are sparsely distributed over a relatively large range, in cases where
// ultra-fast performance is not critical. For instance, Sqlite.Version.* are
// sparse because for any given database, there's going to be exactly one
// version logged.
//
// Performance:
// ------------
// Sparse histograms are typically more memory-efficient but less time-efficient
// than other histograms. Essentially, they sparse histograms use a map rather
// than a vector for their backing storage; they also require lock acquisition
// to increment a sample, whereas other histogram do not. Hence, each increment
// operation is a bit slower than for other histograms. But, if the data is
// sparse, then they use less memory client-side, because they allocate buckets
// on demand rather than preallocating.
//
// Data size:
// ----------
// Note that server-side, we still need to load all buckets, across all users,
// at once. Thus, please avoid exploding such histograms, i.e. uploading many
// many distinct values to the server (across all users). Concretely, keep the
// number of distinct values <= 100 ideally, definitely <= 1000. If you have no
// guarantees on the range of your data, use clamping, e.g.:
//   UmaHistogramSparse("My.Histogram", std::clamp(value, 0, 200));
// LINT.IfChange(UmaHistogramSparse)
BASE_EXPORT void UmaHistogramSparse(std::string_view name, int sample);
// LINT.ThenChange(/base/metrics/histogram_functions_internal_overloads.h:UmaHistogramSparse)

// Scoped class which logs its time on this earth in milliseconds as an UMA
// histogram. This is recommended for when you want a histogram which measures
// the time it takes for a method to execute. It uses UmaHistogramTimes() and
// its variations under the hood.
//
// This is equivalent to SCOPED_UMA_HISTOGRAM_TIMER.
//
// Sample usages:
//   void Function() {
//     ScopedUmaHistogramTimer("Component.FunctionTime");
//     // useful stuff here
//     ...
//   }
//
//   void Function() {
//     ScopedUmaHistogramTimer("Component.FunctionTime",
//       ScopedUmaHistogramTimer::kMicroSecondTimes);
//     // useful stuff here
//     ...
//   }
class BASE_EXPORT ScopedUmaHistogramTimer {
 public:
  // Reference UmaHistogramTiming() function declarations for timing details
  // below.
  enum class ScopedHistogramTiming {
    // For microseconds timings from 1 microsecond up to 10 seconds (50
    // buckets).
    kMicrosecondTimes,
    // For short timings from 1 ms up to 10 seconds (50 buckets).
    kShortTimes,
    // For medium timings up to 3 minutes (50 buckets).
    kMediumTimes,
    // For time intervals up to 1 hr (50 buckets).
    kLongTimes
  };

  // Constructs the scoped timer with the given histogram name.
  explicit ScopedUmaHistogramTimer(
      std::string_view name,
      ScopedHistogramTiming timing = ScopedHistogramTiming::kShortTimes);

  ScopedUmaHistogramTimer(const ScopedUmaHistogramTimer&) = delete;
  ScopedUmaHistogramTimer& operator=(const ScopedUmaHistogramTimer&) = delete;

  ~ScopedUmaHistogramTimer();

 private:
  const base::TimeTicks constructed_;
  const ScopedHistogramTiming timing_;
  const std::string name_;
};

}  // namespace base

#endif  // BASE_METRICS_HISTOGRAM_FUNCTIONS_H_