// Copyright 2014 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_MACROS_H_ #define BASE_METRICS_HISTOGRAM_MACROS_H_ #include "base/check_op.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_macros_internal.h" #include "base/metrics/histogram_macros_local.h" #include "base/time/time.h" // Macros for efficient use of histograms. // // 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 // All of these macros must be called with |name| as a runtime constant - it // doesn't have to literally be a constant, but it must be the same string on // all calls from a particular call site. If this rule is violated, it is // possible the data will be written to the wrong histogram. //------------------------------------------------------------------------------ // Enumeration histograms. // These macros create histograms for enumerated data. Ideally, the data should // be of the form of "event occurs, log the result". We recommended not putting // related but not directly connected data as enums within the same histogram. // You should be defining an associated Enum, and the input sample should be // an element of the Enum. // All of these macros must be called with |name| as a runtime constant. // The first variant of UMA_HISTOGRAM_ENUMERATION accepts two arguments: the // histogram name and the enum sample. It deduces the correct boundary value to // use by looking for an enumerator with the name kMaxValue. kMaxValue should // share the value of the highest enumerator: this avoids switch statements // having to handle a sentinel no-op value. // // Sample usage: // // These values are logged to UMA. Entries should not be renumbered and // // numeric values should never be reused. Please keep in sync with "MyEnum" // // in src/tools/metrics/histograms/enums.xml. // enum class MyEnum { // kFirstValue = 0, // kSecondValue = 1, // ... // kFinalValue = N, // kMaxValue = kFinalValue, // }; // UMA_HISTOGRAM_ENUMERATION("My.Enumeration", MyEnum::kSomeValue); // // The second variant requires three arguments: the first two are the same as // before, and the third argument is the enum boundary: this must be strictly // greater than any other enumerator that will be sampled. This only works for // enums with a fixed underlying type. // // Sample usage: // // These values are logged to UMA. Entries should not be renumbered and // // numeric values should never be reused. Please keep in sync with "MyEnum" // // in src/tools/metrics/histograms/enums.xml. // enum class MyEnum : uint8_t { // FIRST_VALUE = 0, // SECOND_VALUE = 1, // ... // FINAL_VALUE = N, // COUNT // }; // UMA_HISTOGRAM_ENUMERATION("My.Enumeration", // MyEnum::SOME_VALUE, MyEnum::COUNT); // // Note: If the enum is used in a switch, it is often desirable to avoid writing // a case statement to handle an unused sentinel value (i.e. COUNT in the above // example). For scoped enums, this is awkward since it requires casting the // enum to an arithmetic type and adding one. Instead, prefer the two argument // version of the macro which automatically deduces the boundary from kMaxValue. #define UMA_HISTOGRAM_ENUMERATION(name, ...) … // As above but "scaled" count to avoid overflows caused by increments of // large amounts. See UMA_HISTOGRAM_SCALED_EXACT_LINEAR for more information. // Only the new format utilizing an internal kMaxValue is supported. // It'll be necessary to #include "base/lazy_instance.h" to use this macro. // name: Full constant name of the histogram (must not change between calls). // sample: Bucket to be incremented. // count: Amount by which to increment. // scale: Amount by which |count| is divided. // Sample usage: // UMA_HISTOGRAM_SCALED_ENUMERATION("FooKiB", kEnumValue, byte_count, 1024) #define UMA_HISTOGRAM_SCALED_ENUMERATION(name, sample, count, scale) … // Histogram for boolean values. // Sample usage: // UMA_HISTOGRAM_BOOLEAN("Histogram.Boolean", bool); #define UMA_HISTOGRAM_BOOLEAN(name, sample) … //------------------------------------------------------------------------------ // Linear histograms. // All of these macros must be called with |name| as a runtime constant. // 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. #define UMA_HISTOGRAM_EXACT_LINEAR(name, sample, exclusive_max) … // Used for capturing basic percentages. This will be 100 buckets of size 1. // Sample usage: // UMA_HISTOGRAM_PERCENTAGE("Histogram.Percent", percent_as_int); #define UMA_HISTOGRAM_PERCENTAGE(name, percent_as_int) … //------------------------------------------------------------------------------ // Scaled linear histograms. // These take |count| and |scale| parameters to allow cumulative reporting of // large numbers. For example, code might pass a count of 1825 bytes and a scale // of 1024 bytes to report values in kilobytes. Only the scaled count is // reported, but the remainder is tracked between calls, so that multiple calls // will accumulate correctly. // It'll be necessary to #include "base/lazy_instance.h" to use this macro. // name: Full constant name of the histogram (must not change between calls). // sample: Bucket to be incremented. // count: Amount by which to increment. // sample_max: Maximum (exclusive) allowed sample value. // scale: Amount by which |count| is divided. // Sample usage: // UMA_HISTOGRAM_SCALED_EXACT_LINER("FooKiB", bucket_no, byte_count, // kBucketsMax+1, 1024) #define UMA_HISTOGRAM_SCALED_EXACT_LINEAR(name, sample, count, sample_max, \ scale) … //------------------------------------------------------------------------------ // Count histograms. These are used for collecting numeric data. Note that we // have macros for more specialized use cases below (memory, time, percentages). // The number suffixes here refer to the max size of the sample, i.e. COUNT_1000 // will be able to collect samples of counts up to 1000. The default number of // buckets in all default macros is 50. We recommend erring on the side of too // large a range versus too short a range. // These macros default to exponential histograms - i.e. the lengths of the // bucket ranges exponentially increase as the sample range increases. // These should *not* be used if you are interested in exact counts, i.e. a // bucket range of 1. In these cases, you should use the ENUMERATION macros // defined later. These should also not be used to capture the number of some // event, i.e. "button X was clicked N times". In this case, an enum should be // used, ideally with an appropriate baseline enum entry included. // All of these macros must be called with |name| as a runtime constant. // Sample usage: // UMA_HISTOGRAM_COUNTS_1M("My.Histogram", sample); #define UMA_HISTOGRAM_COUNTS_100(name, sample) … #define UMA_HISTOGRAM_COUNTS_1000(name, sample) … #define UMA_HISTOGRAM_COUNTS_10000(name, sample) … #define UMA_HISTOGRAM_COUNTS_100000(name, sample) … #define UMA_HISTOGRAM_COUNTS_1M(name, sample) … #define UMA_HISTOGRAM_COUNTS_10M(name, sample) … // This macro allows the min, max, and number of buckets to be customized. Any // samples whose values are outside of [min, exclusive_max-1] are put in the // underflow or overflow buckets. Note that |min| should be >=1 as emitted 0s go // into the underflow bucket. // Sample usage: // UMA_HISTOGRAM_CUSTOM_COUNTS("My.Histogram", sample, 1, 100000000, 50); #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, exclusive_max, \ bucket_count) … //------------------------------------------------------------------------------ // Timing histograms. These are used for collecting timing data (generally // latencies). // These macros create exponentially sized histograms (lengths of the bucket // ranges exponentially increase as the sample range increases). The input // sample is a base::TimeDelta. The output data is measured in ms granularity. // All of these macros must be called with |name| as a runtime constant. // Sample usage: // UMA_HISTOGRAM_TIMES("My.Timing.Histogram", time_delta); // Short timings - up to 10 seconds. For high-resolution (microseconds) timings, // see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES. #define UMA_HISTOGRAM_TIMES(name, sample) … // TODO(crbug.com/353712922): rename and reintroduce this function/macro // Warning: There is another UMA logging function with a very similar name // which buckets data differently than this one. // https://source.chromium.org/chromium/chromium/src/+/main:base/metrics/histogram_functions.h?q=UmaHistogramMediumTimes // If you modify your logging to use that other function, you will be making a // meaningful semantic change to your data, and should change your histogram's // name, as per the guidelines at // https://chromium.googlesource.com/chromium/src/tools/+/HEAD/metrics/histograms/README.md#revising-histograms. // Medium timings - up to 3 minutes. Note this starts at 10ms (no good reason, // but not worth changing). #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) … // Long timings - up to an hour. #define UMA_HISTOGRAM_LONG_TIMES(name, sample) … // Long timings with higher granularity - up to an hour with 100 buckets. #define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) … // This can be used when the default ranges are not sufficient. This macro lets // the metric developer customize the min and max of the sampled range, as well // as the number of buckets recorded. // Sample usage: // UMA_HISTOGRAM_CUSTOM_TIMES("Very.Long.Timing.Histogram", time_delta, // base::Seconds(1), base::Days(1), 100); #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) … // Same as UMA_HISTOGRAM_CUSTOM_TIMES but reports |sample| in microseconds, // dropping the report if this client doesn't have a high-resolution clock. // // Note: dropping reports on clients with low-resolution clocks means these // reports will be biased to a portion of the population on Windows. See // Windows.HasHighResolutionTimeTicks for the affected sample. // // Sample usage: // UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( // "High.Resolution.TimingMicroseconds.Histogram", time_delta, // base::Microseconds(1), // base::Milliseconds(10), 100); #define UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sample, min, max, \ bucket_count) … // Scoped class which logs its time on this earth in milliseconds as a UMA // statistic. This is recommended for when you want a histogram which measures // the time it takes for a method to execute. This measures up to 10 seconds. It // uses UMA_HISTOGRAM_TIMES under the hood. // Sample usage: // void Function() { // SCOPED_UMA_HISTOGRAM_TIMER("Component.FunctionTime"); // ... // } enum class ScopedHistogramTiming { … }; #define SCOPED_UMA_HISTOGRAM_TIMER(name) … // Similar scoped histogram timer, but this uses UMA_HISTOGRAM_LONG_TIMES_100, // which measures up to an hour, and uses 100 buckets. This is more expensive // to store, so only use if this often takes >10 seconds. #define SCOPED_UMA_HISTOGRAM_LONG_TIMER(name) … // Similar scoped histogram timer, but this uses // UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES, measuring from 1 microseconds to 1 // second, with 50 buckets. #define SCOPED_UMA_HISTOGRAM_TIMER_MICROS(name) … //------------------------------------------------------------------------------ // Memory histograms. // These macros create exponentially sized histograms (lengths of the bucket // ranges exponentially increase as the sample range increases). The input // sample must be a number measured in kilobytes. // All of these macros must be called with |name| as a runtime constant. // Sample usage: // UMA_HISTOGRAM_MEMORY_KB("My.Memory.Histogram", memory_in_kb); // Used to measure common KB-granularity memory stats. Range is up to 500000KB - // approximately 500M. #define UMA_HISTOGRAM_MEMORY_KB(name, sample) … // Used to measure common MB-granularity memory stats. Range is up to 4000MiB - // approximately 4GiB. #define UMA_HISTOGRAM_MEMORY_MEDIUM_MB(name, sample) … // Used to measure common MB-granularity memory stats. Range is up to ~64G. #define UMA_HISTOGRAM_MEMORY_LARGE_MB(name, sample) … //------------------------------------------------------------------------------ // Stability-specific histograms. // Histograms logged in as stability histograms will be included in the initial // stability log. See comments by declaration of // MetricsService::PrepareInitialStabilityLog(). // All of these macros must be called with |name| as a runtime constant. // For details on usage, see the documentation on the non-stability equivalents. #define UMA_STABILITY_HISTOGRAM_BOOLEAN(name, sample) … #define UMA_STABILITY_HISTOGRAM_COUNTS_100(name, sample) … #define UMA_STABILITY_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, \ bucket_count) … #define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, ...) … #define UMA_STABILITY_HISTOGRAM_LONG_TIMES(name, sample) … #define UMA_STABILITY_HISTOGRAM_PERCENTAGE(name, percent_as_int) … //------------------------------------------------------------------------------ // 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. // // For important details on performance, data size, and usage, see the // documentation on the regular function equivalents (histogram_functions.h). #define UMA_HISTOGRAM_SPARSE(name, sample) … //------------------------------------------------------------------------------ // Histogram instantiation helpers. // Support a collection of histograms, perhaps one for each entry in an // enumeration. This macro manages a block of pointers, adding to a specific // one by its index. // // A typical instantiation looks something like this: // STATIC_HISTOGRAM_POINTER_GROUP( // GetHistogramNameForIndex(histogram_index), // histogram_index, MAXIMUM_HISTOGRAM_INDEX, Add(some_delta), // base::Histogram::FactoryGet( // GetHistogramNameForIndex(histogram_index), // MINIMUM_SAMPLE, MAXIMUM_SAMPLE, BUCKET_COUNT, // base::HistogramBase::kUmaTargetedHistogramFlag)); // // Though it seems inefficient to generate the name twice, the first // instance will be used only for DCHECK builds and the second will // execute only during the first access to the given index, after which // the pointer is cached and the name never needed again. #define STATIC_HISTOGRAM_POINTER_GROUP( \ constant_histogram_name, index, constant_maximum, \ histogram_add_method_invocation, histogram_factory_get_invocation) … //------------------------------------------------------------------------------ // Deprecated histogram macros. Not recommended for current use. // Legacy name for UMA_HISTOGRAM_COUNTS_1M. Suggest using explicit naming // and not using this macro going forward. #define UMA_HISTOGRAM_COUNTS(name, sample) … // MB-granularity memory metric. This has a short max (1G). #define UMA_HISTOGRAM_MEMORY_MB(name, sample) … // For an enum with customized range. In general, sparse histograms should be // used instead. // Samples should be one of the std::vector<int> list provided via // |custom_ranges|. See comments above CustomRanges::FactoryGet about the // requirement of |custom_ranges|. You can use the helper function // CustomHistogram::ArrayToCustomEnumRanges to transform a C-style array of // valid sample values to a std::vector<int>. #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) … // Helper to split `histogram_name` based on whether the reported sample was // sampled at a different (lower) priority than normal. Typically used for // timing-related histograms that can be affected by running at a lower priority // (e.g. in a best-effort renderer). // // Specifically, `histogram_name` is reported suffixed with ".BestEffort" if the // current process was running at `Process::Priority::kBestEffort` for any // portion of that range and as `histogram_name` directly by default otherwise. // This check is atomic and thus suitable for performance critical histogram // samples. // // A typical instantiation looks something like this: // const TimeTicks start_time = TimeTicks::Now(); // DoSomething(); // const TimeTicks end_time = TimeTicks::Now(); // const TimeDelta sample_interval = end_time - start_time; // // `value`is equal to `sample_interval` in this simple example but it // // could differ. // const TimeDelta value = end_time - start_time; // UMA_HISTOGRAM_SPLIT_BY_PROCESS_PRIORITY( // UMA_HISTOGRAM_MEDIUM_TIMES, end_time, sample_interval, "MyHistogram", // value); // // Note: While this can be called from any process, only renderer processes are // currently supported to detect best-effort priority. // TODO(crbug.com/334983411): Add support for other process types running at // lower priorities. #define UMA_HISTOGRAM_SPLIT_BY_PROCESS_PRIORITY( \ histogram_macro, sample_time, sample_interval, histogram_name, ...) … #endif // BASE_METRICS_HISTOGRAM_MACROS_H_