blob: 816458da9617d782b20490579f1b463862355dd8 [file] [log] [blame]
rkc@chromium.org67c1bb32012-01-06 11:13:28 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5// Histogram is an object that aggregates statistics, and can summarize them in
6// various forms, including ASCII graphical, HTML, and numerically (as a
7// vector of numbers corresponding to each of the aggregating buckets).
8
9// It supports calls to accumulate either time intervals (which are processed
10// as integral number of milliseconds), or arbitrary integral units.
11
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090012// For Histogram(exponential histogram), LinearHistogram and CustomHistogram,
13// the minimum for a declared range is 1 (instead of 0), while the maximum is
14// (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms
15// with ranges exceeding those limits (e.g. 0 as minimal or
16// HistogramBase::kSampleType_MAX as maximal), but those excesses will be
17// silently clamped to those limits (for backwards compatibility with existing
18// code). Best practice is to not exceed the limits.
19
gavinp@chromium.org3831bf42012-10-27 21:44:07 +090020// Each use of a histogram with the same name will reference the same underlying
21// data, so it is safe to record to the same histogram from multiple locations
22// in the code. It is a runtime error if all uses of the same histogram do not
23// agree exactly in type, bucket size and range.
24
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090025// For Histogram and LinearHistogram, the maximum for a declared range should
etienneb@chromium.org87d6a362013-11-20 17:37:34 +090026// always be larger (not equal) than minimal range. Zero and
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090027// HistogramBase::kSampleType_MAX are implicitly added as first and last ranges,
28// so the smallest legal bucket_count is 3. However CustomHistogram can have
29// bucket count as 2 (when you give a custom ranges vector containing only 1
30// range).
31// For these 3 kinds of histograms, the max bucket count is always
32// (Histogram::kBucketCount_MAX - 1).
33
34// The buckets layout of class Histogram is exponential. For example, buckets
35// might contain (sequentially) the count of values in the following intervals:
initial.commit3f4a7322008-07-27 06:49:38 +090036// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
37// That bucket allocation would actually result from construction of a histogram
38// for values between 1 and 64, with 8 buckets, such as:
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090039// Histogram count("some name", 1, 64, 8);
initial.commit3f4a7322008-07-27 06:49:38 +090040// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090041// are also counted by the constructor in the user supplied "bucket_count"
initial.commit3f4a7322008-07-27 06:49:38 +090042// argument.
43// The above example has an exponential ratio of 2 (doubling the bucket width
44// in each consecutive bucket. The Histogram class automatically calculates
45// the smallest ratio that it can use to construct the number of buckets
46// selected in the constructor. An another example, if you had 50 buckets,
47// and millisecond time values from 1 to 10000, then the ratio between
48// consecutive bucket widths will be approximately somewhere around the 50th
49// root of 10000. This approach provides very fine grain (narrow) buckets
50// at the low end of the histogram scale, but allows the histogram to cover a
51// gigantic range with the addition of very few buckets.
52
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090053// Usually we use macros to define and use a histogram. These macros use a
54// pattern involving a function static variable, that is a pointer to a
55// histogram. This static is explicitly initialized on any thread
jar@chromium.org34571142011-04-05 13:48:53 +090056// that detects a uninitialized (NULL) pointer. The potentially racy
57// initialization is not a problem as it is always set to point to the same
58// value (i.e., the FactoryGet always returns the same value). FactoryGet
59// is also completely thread safe, which results in a completely thread safe,
60// and relatively fast, set of counters. To avoid races at shutdown, the static
61// pointer is NOT deleted, and we leak the histograms at process termination.
62
brettw@chromium.org275c2ec2010-10-14 13:38:38 +090063#ifndef BASE_METRICS_HISTOGRAM_H_
64#define BASE_METRICS_HISTOGRAM_H_
initial.commit3f4a7322008-07-27 06:49:38 +090065
66#include <map>
67#include <string>
68#include <vector>
69
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +090070#include "base/atomicops.h"
darin@chromium.orge585bed2011-08-06 00:34:00 +090071#include "base/base_export.h"
kaiwang@chromium.org18643672012-08-09 14:14:15 +090072#include "base/basictypes.h"
fischman@chromium.org5c753a02011-11-13 13:19:15 +090073#include "base/compiler_specific.h"
jar@chromium.orgae56e482010-11-04 08:36:24 +090074#include "base/gtest_prod_util.h"
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +090075#include "base/logging.h"
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090076#include "base/memory/scoped_ptr.h"
kaiwang@chromium.org7c4acad2012-07-26 05:02:48 +090077#include "base/metrics/bucket_ranges.h"
kaiwang@chromium.org081c0f52012-07-19 14:31:49 +090078#include "base/metrics/histogram_base.h"
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090079#include "base/metrics/histogram_samples.h"
avi@chromium.orgb039e8b2013-06-28 09:49:07 +090080#include "base/time/time.h"
initial.commit3f4a7322008-07-27 06:49:38 +090081
brettw@chromium.org275c2ec2010-10-14 13:38:38 +090082class Pickle;
jbates@chromium.org0fc87362012-03-08 05:42:56 +090083class PickleIterator;
brettw@chromium.org275c2ec2010-10-14 13:38:38 +090084
85namespace base {
erg@chromium.orgd9721892010-07-17 05:30:47 +090086
brettw@chromium.orge439a962011-01-02 08:16:20 +090087class Lock;
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +090088//------------------------------------------------------------------------------
89// Histograms are often put in areas where they are called many many times, and
90// performance is critical. As a result, they are designed to have a very low
91// recurring cost of executing (adding additional samples). Toward that end,
92// the macros declare a static pointer to the histogram in question, and only
93// take a "slow path" to construct (or find) the histogram on the first run
94// through the macro. We leak the histograms at shutdown time so that we don't
95// have to validate using the pointers at any time during the running of the
96// process.
97
98// The following code is generally what a thread-safe static pointer
etienneb@chromium.org87d6a362013-11-20 17:37:34 +090099// initialization looks like for a histogram (after a macro is expanded). This
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900100// sample is an expansion (with comments) of the code for
asvitkine26a12032014-08-26 13:39:35 +0900101// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900102
103/*
104 do {
105 // The pointer's presence indicates the initialization is complete.
106 // Initialization is idempotent, so it can safely be atomically repeated.
107 static base::subtle::AtomicWord atomic_histogram_pointer = 0;
108
109 // Acquire_Load() ensures that we acquire visibility to the pointed-to data
etienneb@chromium.org87d6a362013-11-20 17:37:34 +0900110 // in the histogram.
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900111 base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
112 base::subtle::Acquire_Load(&atomic_histogram_pointer)));
113
114 if (!histogram_pointer) {
115 // This is the slow path, which will construct OR find the matching
116 // histogram. FactoryGet includes locks on a global histogram name map
117 // and is completely thread safe.
118 histogram_pointer = base::Histogram::FactoryGet(
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900119 name, min, max, bucket_count, base::HistogramBase::kNoFlags);
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900120
121 // Use Release_Store to ensure that the histogram data is made available
122 // globally before we make the pointer visible.
123 // Several threads may perform this store, but the same value will be
124 // stored in all cases (for a given named/spec'ed histogram).
125 // We could do this without any barrier, since FactoryGet entered and
126 // exited a lock after construction, but this barrier makes things clear.
127 base::subtle::Release_Store(&atomic_histogram_pointer,
128 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
129 }
130
131 // Ensure calling contract is upheld, and the name does NOT vary.
132 DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
133
134 histogram_pointer->Add(sample);
135 } while (0);
136*/
137
138// The above pattern is repeated in several macros. The only elements that
139// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
140// of which FactoryGet method to use. The different FactoryGet methods have
141// various argument lists, so the function with its argument list is provided as
142// a macro argument here. The name is only used in a DCHECK, to assure that
143// callers don't try to vary the name of the histogram (which would tend to be
144// ignored by the one-time initialization of the histogtram_pointer).
145#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
146 histogram_add_method_invocation, \
147 histogram_factory_get_invocation) \
148 do { \
149 static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900150 base::HistogramBase* histogram_pointer( \
151 reinterpret_cast<base::HistogramBase*>( \
152 base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900153 if (!histogram_pointer) { \
154 histogram_pointer = histogram_factory_get_invocation; \
155 base::subtle::Release_Store(&atomic_histogram_pointer, \
156 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
157 } \
wangxianzhu@chromium.org1eea1402014-03-15 03:39:53 +0900158 if (DCHECK_IS_ON) \
asvitkine@chromium.org52246622014-02-15 12:11:45 +0900159 histogram_pointer->CheckName(constant_histogram_name); \
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900160 histogram_pointer->histogram_add_method_invocation; \
161 } while (0)
162
brettw@chromium.orge439a962011-01-02 08:16:20 +0900163
initial.commit3f4a7322008-07-27 06:49:38 +0900164//------------------------------------------------------------------------------
165// Provide easy general purpose histogram in a macro, just like stats counters.
rvargas@google.comba686f62009-03-25 06:19:55 +0900166// The first four macros use 50 buckets.
initial.commit3f4a7322008-07-27 06:49:38 +0900167
asvitkine26a12032014-08-26 13:39:35 +0900168#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
jar@chromium.orged5238a2009-12-28 15:59:52 +0900169 name, sample, base::TimeDelta::FromMilliseconds(1), \
170 base::TimeDelta::FromSeconds(10), 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900171
gavinp@chromium.org794af232013-01-09 10:47:49 +0900172// For folks that need real specific times, use this to select a precise range
173// of times you want plotted, and the number of buckets you want used.
asvitkine26a12032014-08-26 13:39:35 +0900174#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
gavinp@chromium.org794af232013-01-09 10:47:49 +0900175 STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
176 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
177 base::HistogramBase::kNoFlags))
178
asvitkine26a12032014-08-26 13:39:35 +0900179#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
jar@chromium.orged5238a2009-12-28 15:59:52 +0900180 name, sample, 1, 1000000, 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900181
asvitkine26a12032014-08-26 13:39:35 +0900182#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
183 LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
cpu@google.com04d65542009-02-05 11:13:49 +0900184
asvitkine26a12032014-08-26 13:39:35 +0900185#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
186 LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
rvargas@google.comba686f62009-03-25 06:19:55 +0900187
asvitkine26a12032014-08-26 13:39:35 +0900188#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900189 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
190 base::Histogram::FactoryGet(name, min, max, bucket_count, \
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900191 base::HistogramBase::kNoFlags))
jar@chromium.orga88727c2009-06-30 01:40:13 +0900192
kkimlabs@chromium.org4464f4a2014-02-11 23:46:45 +0900193// This is a helper macro used by other macros and shouldn't be used directly.
194#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
195 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
196 base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
197 flag))
198
asvitkine26a12032014-08-26 13:39:35 +0900199#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
200 LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
jar@chromium.org775d9772009-03-14 05:29:58 +0900201
asvitkine26a12032014-08-26 13:39:35 +0900202#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
gavinp@chromium.org794af232013-01-09 10:47:49 +0900203 STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
204 base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
jar@chromium.org373b6862009-02-02 15:50:03 +0900205
jar@chromium.orged5238a2009-12-28 15:59:52 +0900206// Support histograming of an enumerated value. The samples should always be
isherman@chromium.org231024d2011-10-14 10:48:32 +0900207// strictly less than |boundary_value| -- this prevents you from running into
208// problems down the line if you add additional buckets to the histogram. Note
209// also that, despite explicitly setting the minimum bucket value to |1| below,
210// it is fine for enumerated histograms to be 0-indexed -- this is because
211// enumerated histograms should never have underflow.
asvitkine26a12032014-08-26 13:39:35 +0900212#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900213 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
214 base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900215 boundary_value + 1, base::HistogramBase::kNoFlags))
initial.commit3f4a7322008-07-27 06:49:38 +0900216
joi@chromium.orgfd1b87b2011-05-24 22:59:58 +0900217// Support histograming of an enumerated value. Samples should be one of the
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900218// std::vector<int> list provided via |custom_ranges|. See comments above
219// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
220// You can use the helper function CustomHistogram::ArrayToCustomRanges to
221// transform a C-style array of valid sample values to a std::vector<int>.
asvitkine26a12032014-08-26 13:39:35 +0900222#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900223 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
224 base::CustomHistogram::FactoryGet(name, custom_ranges, \
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900225 base::HistogramBase::kNoFlags))
jar@chromium.orged5238a2009-12-28 15:59:52 +0900226
asvitkine26a12032014-08-26 13:39:35 +0900227#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
marja@chromium.orgd6c4ad22013-01-15 22:22:57 +0900228 name, sample, 1000, 500000, 50)
229
initial.commit3f4a7322008-07-27 06:49:38 +0900230//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900231// The following macros provide typical usage scenarios for callers that wish
232// to record histogram data, and have the data submitted/uploaded via UMA.
233// Not all systems support such UMA, but if they do, the following macros
234// should work with the service.
235
jar@chromium.orged5238a2009-12-28 15:59:52 +0900236#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
237 name, sample, base::TimeDelta::FromMilliseconds(1), \
238 base::TimeDelta::FromSeconds(10), 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900239
jar@chromium.orged5238a2009-12-28 15:59:52 +0900240#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
241 name, sample, base::TimeDelta::FromMilliseconds(10), \
242 base::TimeDelta::FromMinutes(3), 50)
jar@google.coma5c410d2008-11-22 10:40:22 +0900243
initial.commit3f4a7322008-07-27 06:49:38 +0900244// Use this macro when times can routinely be much longer than 10 seconds.
jar@chromium.orged5238a2009-12-28 15:59:52 +0900245#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
246 name, sample, base::TimeDelta::FromMilliseconds(1), \
247 base::TimeDelta::FromHours(1), 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900248
rogerm@chromium.org2baaeb32013-09-14 02:30:07 +0900249// Use this macro when times can routinely be much longer than 10 seconds and
250// you want 100 buckets.
251#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
252 name, sample, base::TimeDelta::FromMilliseconds(1), \
253 base::TimeDelta::FromHours(1), 100)
254
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900255#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
256 STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
257 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900258 base::HistogramBase::kUmaTargetedHistogramFlag))
jar@chromium.org373b6862009-02-02 15:50:03 +0900259
jar@chromium.orged5238a2009-12-28 15:59:52 +0900260#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
261 name, sample, 1, 1000000, 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900262
jar@chromium.orged5238a2009-12-28 15:59:52 +0900263#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
264 name, sample, 1, 100, 50)
initial.commit3f4a7322008-07-27 06:49:38 +0900265
jar@chromium.orged5238a2009-12-28 15:59:52 +0900266#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
267 name, sample, 1, 10000, 50)
rvargas@google.comba686f62009-03-25 06:19:55 +0900268
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900269#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
270 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
271 base::Histogram::FactoryGet(name, min, max, bucket_count, \
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900272 base::HistogramBase::kUmaTargetedHistogramFlag))
jar@chromium.orga88727c2009-06-30 01:40:13 +0900273
jar@chromium.orged5238a2009-12-28 15:59:52 +0900274#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
275 name, sample, 1000, 500000, 50)
276
277#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
278 name, sample, 1, 1000, 50)
279
280#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
281 UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
282
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900283#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
284 STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
285 base::BooleanHistogram::FactoryGet(name, \
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900286 base::HistogramBase::kUmaTargetedHistogramFlag))
isherman@chromium.org8cdb0212011-04-14 05:55:10 +0900287
isherman@chromium.org231024d2011-10-14 10:48:32 +0900288// The samples should always be strictly less than |boundary_value|. For more
289// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900290#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
kkimlabs@chromium.org4464f4a2014-02-11 23:46:45 +0900291 HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
292 base::HistogramBase::kUmaTargetedHistogramFlag)
293
294// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
295// histograms. Use this if recording a histogram that should be part of the
296// initial stability log.
297#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
298 HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
299 base::HistogramBase::kUmaStabilityHistogramFlag)
initial.commit3f4a7322008-07-27 06:49:38 +0900300
jar@chromium.orgc5d86fd2011-08-07 14:19:08 +0900301#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
302 STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
303 base::CustomHistogram::FactoryGet(name, custom_ranges, \
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900304 base::HistogramBase::kUmaTargetedHistogramFlag))
jar@chromium.org775d9772009-03-14 05:29:58 +0900305
initial.commit3f4a7322008-07-27 06:49:38 +0900306//------------------------------------------------------------------------------
307
kaiwang@chromium.org7c4acad2012-07-26 05:02:48 +0900308class BucketRanges;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900309class SampleVector;
310
311class BooleanHistogram;
jar@chromium.org84320c52010-04-30 07:39:55 +0900312class CustomHistogram;
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +0900313class Histogram;
314class LinearHistogram;
thestig@chromium.org05d9dd22009-04-04 03:18:55 +0900315
kaiwang@chromium.org081c0f52012-07-19 14:31:49 +0900316class BASE_EXPORT Histogram : public HistogramBase {
initial.commit3f4a7322008-07-27 06:49:38 +0900317 public:
rtenneti@chromium.org6ef07b52011-03-02 17:04:57 +0900318 // Initialize maximum number of buckets in histograms as 16,384.
rtenneti@chromium.org5a0b62f2011-02-24 07:31:18 +0900319 static const size_t kBucketCount_MAX;
initial.commit3f4a7322008-07-27 06:49:38 +0900320
321 typedef std::vector<Count> Counts;
initial.commit3f4a7322008-07-27 06:49:38 +0900322
initial.commit3f4a7322008-07-27 06:49:38 +0900323 //----------------------------------------------------------------------------
rkc@chromium.org67c1bb32012-01-06 11:13:28 +0900324 // For a valid histogram, input should follow these restrictions:
325 // minimum > 0 (if a minimum below 1 is specified, it will implicitly be
326 // normalized up to 1)
327 // maximum > minimum
328 // buckets > 2 [minimum buckets needed: underflow, overflow and the range]
329 // Additionally,
330 // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have
331 // more buckets than the range of numbers; having more buckets than 1 per
332 // value in the range would be nonsensical.
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900333 static HistogramBase* FactoryGet(const std::string& name,
334 Sample minimum,
335 Sample maximum,
jar@chromium.org34571142011-04-05 13:48:53 +0900336 size_t bucket_count,
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900337 int32 flags);
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900338 static HistogramBase* FactoryTimeGet(const std::string& name,
339 base::TimeDelta minimum,
340 base::TimeDelta maximum,
341 size_t bucket_count,
342 int32 flags);
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900343
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900344 static void InitializeBucketRanges(Sample minimum,
345 Sample maximum,
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900346 BucketRanges* ranges);
347
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900348 // This constant if for FindCorruption. Since snapshots of histograms are
349 // taken asynchronously relative to sampling, and our counting code currently
350 // does not prevent race conditions, it is pretty likely that we'll catch a
351 // redundant count that doesn't match the sample count. We allow for a
352 // certain amount of slop before flagging this as an inconsistency. Even with
353 // an inconsistency, we'll snapshot it again (for UMA in about a half hour),
354 // so we'll eventually get the data, if it was not the result of a corruption.
355 static const int kCommonRaceBasedCountMismatch;
356
jar@chromium.orgae56e482010-11-04 08:36:24 +0900357 // Check to see if bucket ranges, counts and tallies in the snapshot are
358 // consistent with the bucket ranges and checksums in our histogram. This can
359 // produce a false-alarm if a race occurred in the reading of the data during
360 // a SnapShot process, but should otherwise be false at all times (unless we
361 // have memory over-writes, or DRAM failures).
kaiwang@chromium.org7881e422013-03-01 12:53:25 +0900362 virtual int FindCorruption(const HistogramSamples& samples) const OVERRIDE;
jar@chromium.orgae56e482010-11-04 08:36:24 +0900363
initial.commit3f4a7322008-07-27 06:49:38 +0900364 //----------------------------------------------------------------------------
etienneb@chromium.org87d6a362013-11-20 17:37:34 +0900365 // Accessors for factory construction, serialization and testing.
initial.commit3f4a7322008-07-27 06:49:38 +0900366 //----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900367 Sample declared_min() const { return declared_min_; }
368 Sample declared_max() const { return declared_max_; }
erg@google.com190e7b02010-12-10 03:25:03 +0900369 virtual Sample ranges(size_t i) const;
erg@google.com190e7b02010-12-10 03:25:03 +0900370 virtual size_t bucket_count() const;
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900371 const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
372
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900373 // This function validates histogram construction arguments. It returns false
374 // if some of the arguments are totally bad.
375 // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
376 // converts it to good input: 1.
377 // TODO(kaiwang): Be more restrict and return false for any bad input, and
378 // make this a readonly validating function.
379 static bool InspectConstructionArguments(const std::string& name,
380 Sample* minimum,
381 Sample* maximum,
382 size_t* bucket_count);
383
kaiwang@chromium.orgc6d1ac22012-10-24 17:18:52 +0900384 // HistogramBase implementation:
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900385 virtual HistogramType GetHistogramType() const OVERRIDE;
isherman@chromium.org5de6adb2013-06-27 23:38:45 +0900386 virtual bool HasConstructionArguments(
387 Sample expected_minimum,
388 Sample expected_maximum,
389 size_t expected_bucket_count) const OVERRIDE;
kaiwang@chromium.orgc6d1ac22012-10-24 17:18:52 +0900390 virtual void Add(Sample value) OVERRIDE;
391 virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900392 virtual void AddSamples(const HistogramSamples& samples) OVERRIDE;
393 virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE;
kaiwang@chromium.orgc6d1ac22012-10-24 17:18:52 +0900394 virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
395 virtual void WriteAscii(std::string* output) const OVERRIDE;
396
397 protected:
isherman@chromium.org5de6adb2013-06-27 23:38:45 +0900398 // |ranges| should contain the underflow and overflow buckets. See top
399 // comments for example.
kaiwang@chromium.orgc6d1ac22012-10-24 17:18:52 +0900400 Histogram(const std::string& name,
401 Sample minimum,
402 Sample maximum,
kaiwang@chromium.orgc6d1ac22012-10-24 17:18:52 +0900403 const BucketRanges* ranges);
404
405 virtual ~Histogram();
406
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900407 // HistogramBase implementation:
408 virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;
fischman@chromium.org5c753a02011-11-13 13:19:15 +0900409
initial.commit3f4a7322008-07-27 06:49:38 +0900410 // Method to override to skip the display of the i'th bucket if it's empty.
erg@google.com6e67c1d2010-07-29 02:25:28 +0900411 virtual bool PrintEmptyBucket(size_t index) const;
initial.commit3f4a7322008-07-27 06:49:38 +0900412
rtenneti@chromium.orgf84534c2011-10-20 09:55:00 +0900413 // Get normalized size, relative to the ranges(i).
initial.commit3f4a7322008-07-27 06:49:38 +0900414 virtual double GetBucketSize(Count current, size_t i) const;
415
416 // Return a string description of what goes in a given bucket.
417 // Most commonly this is the numeric value, but in derived classes it may
418 // be a name (or string description) given to the bucket.
419 virtual const std::string GetAsciiBucketRange(size_t it) const;
420
initial.commit3f4a7322008-07-27 06:49:38 +0900421 private:
jar@chromium.orgae56e482010-11-04 08:36:24 +0900422 // Allow tests to corrupt our innards for testing purposes.
kaiwang@chromium.org98a16202012-10-20 11:56:18 +0900423 FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
424 FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
robertshield@chromium.orgd84df402011-11-29 23:45:53 +0900425 FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
426 FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
gavinp@chromium.org3831bf42012-10-27 21:44:07 +0900427 FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
jar@chromium.orgae56e482010-11-04 08:36:24 +0900428
jar@chromium.org34571142011-04-05 13:48:53 +0900429 friend class StatisticsRecorder; // To allow it to delete duplicates.
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900430 friend class StatisticsRecorderTest;
jar@chromium.orgae56e482010-11-04 08:36:24 +0900431
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900432 friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
433 PickleIterator* iter);
434 static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
435
kaiwang@chromium.org98a16202012-10-20 11:56:18 +0900436 // Implementation of SnapshotSamples function.
437 scoped_ptr<SampleVector> SnapshotSampleVector() const;
438
initial.commit3f4a7322008-07-27 06:49:38 +0900439 //----------------------------------------------------------------------------
440 // Helpers for emitting Ascii graphic. Each method appends data to output.
441
kaiwang@chromium.org7c4acad2012-07-26 05:02:48 +0900442 void WriteAsciiImpl(bool graph_it,
443 const std::string& newline,
444 std::string* output) const;
445
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900446 // Find out how large (graphically) the largest bucket will appear to be.
447 double GetPeakBucketSize(const SampleVector& samples) const;
initial.commit3f4a7322008-07-27 06:49:38 +0900448
449 // Write a common header message describing this histogram.
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900450 void WriteAsciiHeader(const SampleVector& samples,
451 Count sample_count,
452 std::string* output) const;
initial.commit3f4a7322008-07-27 06:49:38 +0900453
454 // Write information about previous, current, and next buckets.
455 // Information such as cumulative percentage, etc.
456 void WriteAsciiBucketContext(const int64 past, const Count current,
457 const int64 remaining, const size_t i,
458 std::string* output) const;
459
marja@chromium.orge7ade4e2012-10-08 19:31:50 +0900460 // WriteJSON calls these.
461 virtual void GetParameters(DictionaryValue* params) const OVERRIDE;
462
463 virtual void GetCountAndBucketData(Count* count,
jeremy@chromium.orgdf894ed2013-05-10 18:32:58 +0900464 int64* sum,
marja@chromium.orge7ade4e2012-10-08 19:31:50 +0900465 ListValue* buckets) const OVERRIDE;
466
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900467 // Does not own this object. Should get from StatisticsRecorder.
468 const BucketRanges* bucket_ranges_;
initial.commit3f4a7322008-07-27 06:49:38 +0900469
isherman@chromium.org5de6adb2013-06-27 23:38:45 +0900470 Sample declared_min_; // Less than this goes into the first bucket.
471 Sample declared_max_; // Over this goes into the last bucket.
initial.commit3f4a7322008-07-27 06:49:38 +0900472
initial.commit3f4a7322008-07-27 06:49:38 +0900473 // Finally, provide the state that changes with the addition of each new
474 // sample.
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900475 scoped_ptr<SampleVector> samples_;
initial.commit3f4a7322008-07-27 06:49:38 +0900476
jar@chromium.orgbb363fd2009-02-25 15:10:17 +0900477 DISALLOW_COPY_AND_ASSIGN(Histogram);
initial.commit3f4a7322008-07-27 06:49:38 +0900478};
479
480//------------------------------------------------------------------------------
481
482// LinearHistogram is a more traditional histogram, with evenly spaced
483// buckets.
darin@chromium.orge585bed2011-08-06 00:34:00 +0900484class BASE_EXPORT LinearHistogram : public Histogram {
initial.commit3f4a7322008-07-27 06:49:38 +0900485 public:
erg@google.comd5fffd42011-01-08 03:06:45 +0900486 virtual ~LinearHistogram();
initial.commit3f4a7322008-07-27 06:49:38 +0900487
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +0900488 /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
489 default underflow bucket. */
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900490 static HistogramBase* FactoryGet(const std::string& name,
491 Sample minimum,
492 Sample maximum,
jar@chromium.org34571142011-04-05 13:48:53 +0900493 size_t bucket_count,
kaiwang@chromium.org18643672012-08-09 14:14:15 +0900494 int32 flags);
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900495 static HistogramBase* FactoryTimeGet(const std::string& name,
496 TimeDelta minimum,
497 TimeDelta maximum,
498 size_t bucket_count,
499 int32 flags);
jar@chromium.orgbb363fd2009-02-25 15:10:17 +0900500
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900501 struct DescriptionPair {
502 Sample sample;
503 const char* description; // Null means end of a list of pairs.
504 };
505
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900506 // Create a LinearHistogram and store a list of number/text values for use in
507 // writing the histogram graph.
508 // |descriptions| can be NULL, which means no special descriptions to set. If
509 // it's not NULL, the last element in the array must has a NULL in its
510 // "description" field.
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900511 static HistogramBase* FactoryGetWithRangeDescription(
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900512 const std::string& name,
513 Sample minimum,
514 Sample maximum,
515 size_t bucket_count,
516 int32 flags,
517 const DescriptionPair descriptions[]);
518
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900519 static void InitializeBucketRanges(Sample minimum,
520 Sample maximum,
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900521 BucketRanges* ranges);
522
erg@google.comd5fffd42011-01-08 03:06:45 +0900523 // Overridden from Histogram:
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900524 virtual HistogramType GetHistogramType() const OVERRIDE;
erg@google.com71915232010-09-29 07:54:58 +0900525
initial.commit3f4a7322008-07-27 06:49:38 +0900526 protected:
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900527 LinearHistogram(const std::string& name,
528 Sample minimum,
529 Sample maximum,
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900530 const BucketRanges* ranges);
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +0900531
avi@chromium.org08e6a602011-11-16 09:08:08 +0900532 virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;
initial.commit3f4a7322008-07-27 06:49:38 +0900533
534 // If we have a description for a bucket, then return that. Otherwise
535 // let parent class provide a (numeric) description.
avi@chromium.org08e6a602011-11-16 09:08:08 +0900536 virtual const std::string GetAsciiBucketRange(size_t i) const OVERRIDE;
initial.commit3f4a7322008-07-27 06:49:38 +0900537
538 // Skip printing of name for numeric range if we have a name (and if this is
539 // an empty bucket).
avi@chromium.org08e6a602011-11-16 09:08:08 +0900540 virtual bool PrintEmptyBucket(size_t index) const OVERRIDE;
initial.commit3f4a7322008-07-27 06:49:38 +0900541
542 private:
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900543 friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
544 PickleIterator* iter);
545 static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
546
initial.commit3f4a7322008-07-27 06:49:38 +0900547 // For some ranges, we store a printable description of a bucket range.
etienneb@chromium.org87d6a362013-11-20 17:37:34 +0900548 // If there is no description, then GetAsciiBucketRange() uses parent class
initial.commit3f4a7322008-07-27 06:49:38 +0900549 // to provide a description.
550 typedef std::map<Sample, std::string> BucketDescriptionMap;
551 BucketDescriptionMap bucket_description_;
552
jar@chromium.orgbb363fd2009-02-25 15:10:17 +0900553 DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
initial.commit3f4a7322008-07-27 06:49:38 +0900554};
555
abarth@chromium.org7ed364e2009-01-18 04:15:36 +0900556//------------------------------------------------------------------------------
557
558// BooleanHistogram is a histogram for booleans.
darin@chromium.orge585bed2011-08-06 00:34:00 +0900559class BASE_EXPORT BooleanHistogram : public LinearHistogram {
abarth@chromium.org7ed364e2009-01-18 04:15:36 +0900560 public:
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900561 static HistogramBase* FactoryGet(const std::string& name, int32 flags);
abarth@chromium.org7ed364e2009-01-18 04:15:36 +0900562
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900563 virtual HistogramType GetHistogramType() const OVERRIDE;
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +0900564
abarth@chromium.org7ed364e2009-01-18 04:15:36 +0900565 private:
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900566 BooleanHistogram(const std::string& name, const BucketRanges* ranges);
jar@chromium.orgfe4c0d12009-12-06 09:09:37 +0900567
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900568 friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
569 PickleIterator* iter);
570 static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
571
jar@chromium.orgbb363fd2009-02-25 15:10:17 +0900572 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
abarth@chromium.org7ed364e2009-01-18 04:15:36 +0900573};
initial.commit3f4a7322008-07-27 06:49:38 +0900574
575//------------------------------------------------------------------------------
jar@chromium.org84320c52010-04-30 07:39:55 +0900576
577// CustomHistogram is a histogram for a set of custom integers.
darin@chromium.orge585bed2011-08-06 00:34:00 +0900578class BASE_EXPORT CustomHistogram : public Histogram {
jar@chromium.org84320c52010-04-30 07:39:55 +0900579 public:
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900580 // |custom_ranges| contains a vector of limits on ranges. Each limit should be
581 // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward
582 // compatibility). The limits can be unordered or contain duplication, but
583 // client should not depend on this.
kaiwang@chromium.org1c030392013-01-23 13:12:17 +0900584 static HistogramBase* FactoryGet(const std::string& name,
585 const std::vector<Sample>& custom_ranges,
586 int32 flags);
jar@chromium.org84320c52010-04-30 07:39:55 +0900587
erg@google.comd5fffd42011-01-08 03:06:45 +0900588 // Overridden from Histogram:
kaiwang@chromium.org7c950a82012-10-31 15:20:25 +0900589 virtual HistogramType GetHistogramType() const OVERRIDE;
erg@google.comd5fffd42011-01-08 03:06:45 +0900590
joi@chromium.orgfd1b87b2011-05-24 22:59:58 +0900591 // Helper method for transforming an array of valid enumeration values
asvitkine26a12032014-08-26 13:39:35 +0900592 // to the std::vector<int> expected by UMA_HISTOGRAM_CUSTOM_ENUMERATION.
joi@chromium.orgfd1b87b2011-05-24 22:59:58 +0900593 // This function ensures that a guard bucket exists right after any
594 // valid sample value (unless the next higher sample is also a valid value),
595 // so that invalid samples never fall into the same bucket as valid samples.
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900596 // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
joi@chromium.orgfd1b87b2011-05-24 22:59:58 +0900597 static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
598 size_t num_values);
jar@chromium.org84320c52010-04-30 07:39:55 +0900599 protected:
600 CustomHistogram(const std::string& name,
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900601 const BucketRanges* ranges);
jar@chromium.org84320c52010-04-30 07:39:55 +0900602
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900603 // HistogramBase implementation:
604 virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;
fischman@chromium.org5c753a02011-11-13 13:19:15 +0900605
avi@chromium.org08e6a602011-11-16 09:08:08 +0900606 virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;
jar@chromium.org84320c52010-04-30 07:39:55 +0900607
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900608 private:
kaiwang@chromium.orge4e800c2013-01-12 06:52:44 +0900609 friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
610 PickleIterator* iter);
611 static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
612
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900613 static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
614 static BucketRanges* CreateBucketRangesFromCustomRanges(
615 const std::vector<Sample>& custom_ranges);
616
jar@chromium.org84320c52010-04-30 07:39:55 +0900617 DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
618};
619
brettw@chromium.org275c2ec2010-10-14 13:38:38 +0900620} // namespace base
621
622#endif // BASE_METRICS_HISTOGRAM_H_