rkc@chromium.org | 67c1bb3 | 2012-01-06 11:13:28 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 4 | |
| 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 12 | // 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.org | 3831bf4 | 2012-10-27 21:44:07 +0900 | [diff] [blame] | 20 | // 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 25 | // For Histogram and LinearHistogram, the maximum for a declared range should |
etienneb@chromium.org | 87d6a36 | 2013-11-20 17:37:34 +0900 | [diff] [blame] | 26 | // always be larger (not equal) than minimal range. Zero and |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 27 | // 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.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 36 | // [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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 39 | // Histogram count("some name", 1, 64, 8); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 40 | // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity) |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 41 | // are also counted by the constructor in the user supplied "bucket_count" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 42 | // 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 53 | // 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.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 56 | // 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.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 63 | #ifndef BASE_METRICS_HISTOGRAM_H_ |
| 64 | #define BASE_METRICS_HISTOGRAM_H_ |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 65 | |
| 66 | #include <map> |
| 67 | #include <string> |
| 68 | #include <vector> |
| 69 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 70 | #include "base/atomicops.h" |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 71 | #include "base/base_export.h" |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 72 | #include "base/basictypes.h" |
fischman@chromium.org | 5c753a0 | 2011-11-13 13:19:15 +0900 | [diff] [blame] | 73 | #include "base/compiler_specific.h" |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 74 | #include "base/gtest_prod_util.h" |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 75 | #include "base/logging.h" |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 76 | #include "base/memory/scoped_ptr.h" |
kaiwang@chromium.org | 7c4acad | 2012-07-26 05:02:48 +0900 | [diff] [blame] | 77 | #include "base/metrics/bucket_ranges.h" |
kaiwang@chromium.org | 081c0f5 | 2012-07-19 14:31:49 +0900 | [diff] [blame] | 78 | #include "base/metrics/histogram_base.h" |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 79 | #include "base/metrics/histogram_samples.h" |
avi@chromium.org | b039e8b | 2013-06-28 09:49:07 +0900 | [diff] [blame] | 80 | #include "base/time/time.h" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 81 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 82 | class Pickle; |
jbates@chromium.org | 0fc8736 | 2012-03-08 05:42:56 +0900 | [diff] [blame] | 83 | class PickleIterator; |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 84 | |
| 85 | namespace base { |
erg@chromium.org | d972189 | 2010-07-17 05:30:47 +0900 | [diff] [blame] | 86 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 87 | class Lock; |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 88 | //------------------------------------------------------------------------------ |
| 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.org | 87d6a36 | 2013-11-20 17:37:34 +0900 | [diff] [blame] | 99 | // initialization looks like for a histogram (after a macro is expanded). This |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 100 | // sample is an expansion (with comments) of the code for |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 101 | // LOCAL_HISTOGRAM_CUSTOM_COUNTS(). |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 102 | |
| 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.org | 87d6a36 | 2013-11-20 17:37:34 +0900 | [diff] [blame] | 110 | // in the histogram. |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 111 | 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.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 119 | name, min, max, bucket_count, base::HistogramBase::kNoFlags); |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 120 | |
| 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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 150 | base::HistogramBase* histogram_pointer( \ |
| 151 | reinterpret_cast<base::HistogramBase*>( \ |
| 152 | base::subtle::Acquire_Load(&atomic_histogram_pointer))); \ |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 153 | 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.org | 1eea140 | 2014-03-15 03:39:53 +0900 | [diff] [blame] | 158 | if (DCHECK_IS_ON) \ |
asvitkine@chromium.org | 5224662 | 2014-02-15 12:11:45 +0900 | [diff] [blame] | 159 | histogram_pointer->CheckName(constant_histogram_name); \ |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 160 | histogram_pointer->histogram_add_method_invocation; \ |
| 161 | } while (0) |
| 162 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 163 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 164 | //------------------------------------------------------------------------------ |
| 165 | // Provide easy general purpose histogram in a macro, just like stats counters. |
rvargas@google.com | ba686f6 | 2009-03-25 06:19:55 +0900 | [diff] [blame] | 166 | // The first four macros use 50 buckets. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 167 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 168 | #define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \ |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 169 | name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 170 | base::TimeDelta::FromSeconds(10), 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 171 | |
gavinp@chromium.org | 794af23 | 2013-01-09 10:47:49 +0900 | [diff] [blame] | 172 | // 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. |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 174 | #define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
gavinp@chromium.org | 794af23 | 2013-01-09 10:47:49 +0900 | [diff] [blame] | 175 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \ |
| 176 | base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 177 | base::HistogramBase::kNoFlags)) |
| 178 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 179 | #define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \ |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 180 | name, sample, 1, 1000000, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 181 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 182 | #define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \ |
| 183 | LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50) |
cpu@google.com | 04d6554 | 2009-02-05 11:13:49 +0900 | [diff] [blame] | 184 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 185 | #define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \ |
| 186 | LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50) |
rvargas@google.com | ba686f6 | 2009-03-25 06:19:55 +0900 | [diff] [blame] | 187 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 188 | #define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 189 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 190 | base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 191 | base::HistogramBase::kNoFlags)) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 192 | |
kkimlabs@chromium.org | 4464f4a | 2014-02-11 23:46:45 +0900 | [diff] [blame] | 193 | // 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 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 199 | #define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| 200 | LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 201 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 202 | #define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \ |
gavinp@chromium.org | 794af23 | 2013-01-09 10:47:49 +0900 | [diff] [blame] | 203 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \ |
| 204 | base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags)) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 205 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 206 | // Support histograming of an enumerated value. The samples should always be |
isherman@chromium.org | 231024d | 2011-10-14 10:48:32 +0900 | [diff] [blame] | 207 | // 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. |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 212 | #define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 213 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 214 | base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 215 | boundary_value + 1, base::HistogramBase::kNoFlags)) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 216 | |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 217 | // Support histograming of an enumerated value. Samples should be one of the |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 218 | // 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>. |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 222 | #define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 223 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 224 | base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 225 | base::HistogramBase::kNoFlags)) |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 226 | |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 227 | #define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \ |
marja@chromium.org | d6c4ad2 | 2013-01-15 22:22:57 +0900 | [diff] [blame] | 228 | name, sample, 1000, 500000, 50) |
| 229 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 230 | //------------------------------------------------------------------------------ |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 231 | // 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.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 236 | #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 237 | name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 238 | base::TimeDelta::FromSeconds(10), 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 239 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 240 | #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.com | a5c410d | 2008-11-22 10:40:22 +0900 | [diff] [blame] | 243 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 244 | // Use this macro when times can routinely be much longer than 10 seconds. |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 245 | #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.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 248 | |
rogerm@chromium.org | 2baaeb3 | 2013-09-14 02:30:07 +0900 | [diff] [blame] | 249 | // 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.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 255 | #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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 258 | base::HistogramBase::kUmaTargetedHistogramFlag)) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 259 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 260 | #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 261 | name, sample, 1, 1000000, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 262 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 263 | #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 264 | name, sample, 1, 100, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 265 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 266 | #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 267 | name, sample, 1, 10000, 50) |
rvargas@google.com | ba686f6 | 2009-03-25 06:19:55 +0900 | [diff] [blame] | 268 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 269 | #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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 272 | base::HistogramBase::kUmaTargetedHistogramFlag)) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 273 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 274 | #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.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 283 | #define UMA_HISTOGRAM_BOOLEAN(name, sample) \ |
| 284 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \ |
| 285 | base::BooleanHistogram::FactoryGet(name, \ |
kaiwang@chromium.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 286 | base::HistogramBase::kUmaTargetedHistogramFlag)) |
isherman@chromium.org | 8cdb021 | 2011-04-14 05:55:10 +0900 | [diff] [blame] | 287 | |
isherman@chromium.org | 231024d | 2011-10-14 10:48:32 +0900 | [diff] [blame] | 288 | // 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.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 290 | #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
kkimlabs@chromium.org | 4464f4a | 2014-02-11 23:46:45 +0900 | [diff] [blame] | 291 | 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.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 300 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 301 | #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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 304 | base::HistogramBase::kUmaTargetedHistogramFlag)) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 305 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 306 | //------------------------------------------------------------------------------ |
| 307 | |
kaiwang@chromium.org | 7c4acad | 2012-07-26 05:02:48 +0900 | [diff] [blame] | 308 | class BucketRanges; |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 309 | class SampleVector; |
| 310 | |
| 311 | class BooleanHistogram; |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 312 | class CustomHistogram; |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 313 | class Histogram; |
| 314 | class LinearHistogram; |
thestig@chromium.org | 05d9dd2 | 2009-04-04 03:18:55 +0900 | [diff] [blame] | 315 | |
kaiwang@chromium.org | 081c0f5 | 2012-07-19 14:31:49 +0900 | [diff] [blame] | 316 | class BASE_EXPORT Histogram : public HistogramBase { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 317 | public: |
rtenneti@chromium.org | 6ef07b5 | 2011-03-02 17:04:57 +0900 | [diff] [blame] | 318 | // Initialize maximum number of buckets in histograms as 16,384. |
rtenneti@chromium.org | 5a0b62f | 2011-02-24 07:31:18 +0900 | [diff] [blame] | 319 | static const size_t kBucketCount_MAX; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 320 | |
| 321 | typedef std::vector<Count> Counts; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 322 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 323 | //---------------------------------------------------------------------------- |
rkc@chromium.org | 67c1bb3 | 2012-01-06 11:13:28 +0900 | [diff] [blame] | 324 | // 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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 333 | static HistogramBase* FactoryGet(const std::string& name, |
| 334 | Sample minimum, |
| 335 | Sample maximum, |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 336 | size_t bucket_count, |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 337 | int32 flags); |
kaiwang@chromium.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 338 | 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 343 | |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 344 | static void InitializeBucketRanges(Sample minimum, |
| 345 | Sample maximum, |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 346 | BucketRanges* ranges); |
| 347 | |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 348 | // 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.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 357 | // 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.org | 7881e42 | 2013-03-01 12:53:25 +0900 | [diff] [blame] | 362 | virtual int FindCorruption(const HistogramSamples& samples) const OVERRIDE; |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 363 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 364 | //---------------------------------------------------------------------------- |
etienneb@chromium.org | 87d6a36 | 2013-11-20 17:37:34 +0900 | [diff] [blame] | 365 | // Accessors for factory construction, serialization and testing. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 366 | //---------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 367 | Sample declared_min() const { return declared_min_; } |
| 368 | Sample declared_max() const { return declared_max_; } |
erg@google.com | 190e7b0 | 2010-12-10 03:25:03 +0900 | [diff] [blame] | 369 | virtual Sample ranges(size_t i) const; |
erg@google.com | 190e7b0 | 2010-12-10 03:25:03 +0900 | [diff] [blame] | 370 | virtual size_t bucket_count() const; |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 371 | const BucketRanges* bucket_ranges() const { return bucket_ranges_; } |
| 372 | |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 373 | // 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.org | c6d1ac2 | 2012-10-24 17:18:52 +0900 | [diff] [blame] | 384 | // HistogramBase implementation: |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 385 | virtual HistogramType GetHistogramType() const OVERRIDE; |
isherman@chromium.org | 5de6adb | 2013-06-27 23:38:45 +0900 | [diff] [blame] | 386 | virtual bool HasConstructionArguments( |
| 387 | Sample expected_minimum, |
| 388 | Sample expected_maximum, |
| 389 | size_t expected_bucket_count) const OVERRIDE; |
kaiwang@chromium.org | c6d1ac2 | 2012-10-24 17:18:52 +0900 | [diff] [blame] | 390 | virtual void Add(Sample value) OVERRIDE; |
| 391 | virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE; |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 392 | virtual void AddSamples(const HistogramSamples& samples) OVERRIDE; |
| 393 | virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE; |
kaiwang@chromium.org | c6d1ac2 | 2012-10-24 17:18:52 +0900 | [diff] [blame] | 394 | virtual void WriteHTMLGraph(std::string* output) const OVERRIDE; |
| 395 | virtual void WriteAscii(std::string* output) const OVERRIDE; |
| 396 | |
| 397 | protected: |
isherman@chromium.org | 5de6adb | 2013-06-27 23:38:45 +0900 | [diff] [blame] | 398 | // |ranges| should contain the underflow and overflow buckets. See top |
| 399 | // comments for example. |
kaiwang@chromium.org | c6d1ac2 | 2012-10-24 17:18:52 +0900 | [diff] [blame] | 400 | Histogram(const std::string& name, |
| 401 | Sample minimum, |
| 402 | Sample maximum, |
kaiwang@chromium.org | c6d1ac2 | 2012-10-24 17:18:52 +0900 | [diff] [blame] | 403 | const BucketRanges* ranges); |
| 404 | |
| 405 | virtual ~Histogram(); |
| 406 | |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 407 | // HistogramBase implementation: |
| 408 | virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE; |
fischman@chromium.org | 5c753a0 | 2011-11-13 13:19:15 +0900 | [diff] [blame] | 409 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 410 | // Method to override to skip the display of the i'th bucket if it's empty. |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 411 | virtual bool PrintEmptyBucket(size_t index) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 412 | |
rtenneti@chromium.org | f84534c | 2011-10-20 09:55:00 +0900 | [diff] [blame] | 413 | // Get normalized size, relative to the ranges(i). |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 414 | 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.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 421 | private: |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 422 | // Allow tests to corrupt our innards for testing purposes. |
kaiwang@chromium.org | 98a1620 | 2012-10-20 11:56:18 +0900 | [diff] [blame] | 423 | FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest); |
| 424 | FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest); |
robertshield@chromium.org | d84df40 | 2011-11-29 23:45:53 +0900 | [diff] [blame] | 425 | FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds); |
| 426 | FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts); |
gavinp@chromium.org | 3831bf4 | 2012-10-27 21:44:07 +0900 | [diff] [blame] | 427 | FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest); |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 428 | |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 429 | friend class StatisticsRecorder; // To allow it to delete duplicates. |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 430 | friend class StatisticsRecorderTest; |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 431 | |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 432 | friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( |
| 433 | PickleIterator* iter); |
| 434 | static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); |
| 435 | |
kaiwang@chromium.org | 98a1620 | 2012-10-20 11:56:18 +0900 | [diff] [blame] | 436 | // Implementation of SnapshotSamples function. |
| 437 | scoped_ptr<SampleVector> SnapshotSampleVector() const; |
| 438 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 439 | //---------------------------------------------------------------------------- |
| 440 | // Helpers for emitting Ascii graphic. Each method appends data to output. |
| 441 | |
kaiwang@chromium.org | 7c4acad | 2012-07-26 05:02:48 +0900 | [diff] [blame] | 442 | void WriteAsciiImpl(bool graph_it, |
| 443 | const std::string& newline, |
| 444 | std::string* output) const; |
| 445 | |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 446 | // Find out how large (graphically) the largest bucket will appear to be. |
| 447 | double GetPeakBucketSize(const SampleVector& samples) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 448 | |
| 449 | // Write a common header message describing this histogram. |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 450 | void WriteAsciiHeader(const SampleVector& samples, |
| 451 | Count sample_count, |
| 452 | std::string* output) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 453 | |
| 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.org | e7ade4e | 2012-10-08 19:31:50 +0900 | [diff] [blame] | 460 | // WriteJSON calls these. |
| 461 | virtual void GetParameters(DictionaryValue* params) const OVERRIDE; |
| 462 | |
| 463 | virtual void GetCountAndBucketData(Count* count, |
jeremy@chromium.org | df894ed | 2013-05-10 18:32:58 +0900 | [diff] [blame] | 464 | int64* sum, |
marja@chromium.org | e7ade4e | 2012-10-08 19:31:50 +0900 | [diff] [blame] | 465 | ListValue* buckets) const OVERRIDE; |
| 466 | |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 467 | // Does not own this object. Should get from StatisticsRecorder. |
| 468 | const BucketRanges* bucket_ranges_; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 469 | |
isherman@chromium.org | 5de6adb | 2013-06-27 23:38:45 +0900 | [diff] [blame] | 470 | Sample declared_min_; // Less than this goes into the first bucket. |
| 471 | Sample declared_max_; // Over this goes into the last bucket. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 472 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 473 | // Finally, provide the state that changes with the addition of each new |
| 474 | // sample. |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 475 | scoped_ptr<SampleVector> samples_; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 476 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 477 | DISALLOW_COPY_AND_ASSIGN(Histogram); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 478 | }; |
| 479 | |
| 480 | //------------------------------------------------------------------------------ |
| 481 | |
| 482 | // LinearHistogram is a more traditional histogram, with evenly spaced |
| 483 | // buckets. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 484 | class BASE_EXPORT LinearHistogram : public Histogram { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 485 | public: |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 486 | virtual ~LinearHistogram(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 487 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 488 | /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit |
| 489 | default underflow bucket. */ |
kaiwang@chromium.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 490 | static HistogramBase* FactoryGet(const std::string& name, |
| 491 | Sample minimum, |
| 492 | Sample maximum, |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 493 | size_t bucket_count, |
kaiwang@chromium.org | 1864367 | 2012-08-09 14:14:15 +0900 | [diff] [blame] | 494 | int32 flags); |
kaiwang@chromium.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 495 | static HistogramBase* FactoryTimeGet(const std::string& name, |
| 496 | TimeDelta minimum, |
| 497 | TimeDelta maximum, |
| 498 | size_t bucket_count, |
| 499 | int32 flags); |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 500 | |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 501 | struct DescriptionPair { |
| 502 | Sample sample; |
| 503 | const char* description; // Null means end of a list of pairs. |
| 504 | }; |
| 505 | |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 506 | // 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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 511 | static HistogramBase* FactoryGetWithRangeDescription( |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 512 | 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 519 | static void InitializeBucketRanges(Sample minimum, |
| 520 | Sample maximum, |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 521 | BucketRanges* ranges); |
| 522 | |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 523 | // Overridden from Histogram: |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 524 | virtual HistogramType GetHistogramType() const OVERRIDE; |
erg@google.com | 7191523 | 2010-09-29 07:54:58 +0900 | [diff] [blame] | 525 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 526 | protected: |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 527 | LinearHistogram(const std::string& name, |
| 528 | Sample minimum, |
| 529 | Sample maximum, |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 530 | const BucketRanges* ranges); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 531 | |
avi@chromium.org | 08e6a60 | 2011-11-16 09:08:08 +0900 | [diff] [blame] | 532 | virtual double GetBucketSize(Count current, size_t i) const OVERRIDE; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 533 | |
| 534 | // If we have a description for a bucket, then return that. Otherwise |
| 535 | // let parent class provide a (numeric) description. |
avi@chromium.org | 08e6a60 | 2011-11-16 09:08:08 +0900 | [diff] [blame] | 536 | virtual const std::string GetAsciiBucketRange(size_t i) const OVERRIDE; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 537 | |
| 538 | // Skip printing of name for numeric range if we have a name (and if this is |
| 539 | // an empty bucket). |
avi@chromium.org | 08e6a60 | 2011-11-16 09:08:08 +0900 | [diff] [blame] | 540 | virtual bool PrintEmptyBucket(size_t index) const OVERRIDE; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 541 | |
| 542 | private: |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 543 | friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( |
| 544 | PickleIterator* iter); |
| 545 | static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); |
| 546 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 547 | // For some ranges, we store a printable description of a bucket range. |
etienneb@chromium.org | 87d6a36 | 2013-11-20 17:37:34 +0900 | [diff] [blame] | 548 | // If there is no description, then GetAsciiBucketRange() uses parent class |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 549 | // to provide a description. |
| 550 | typedef std::map<Sample, std::string> BucketDescriptionMap; |
| 551 | BucketDescriptionMap bucket_description_; |
| 552 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 553 | DISALLOW_COPY_AND_ASSIGN(LinearHistogram); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 554 | }; |
| 555 | |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 556 | //------------------------------------------------------------------------------ |
| 557 | |
| 558 | // BooleanHistogram is a histogram for booleans. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 559 | class BASE_EXPORT BooleanHistogram : public LinearHistogram { |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 560 | public: |
kaiwang@chromium.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 561 | static HistogramBase* FactoryGet(const std::string& name, int32 flags); |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 562 | |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 563 | virtual HistogramType GetHistogramType() const OVERRIDE; |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 564 | |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 565 | private: |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 566 | BooleanHistogram(const std::string& name, const BucketRanges* ranges); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 567 | |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 568 | friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( |
| 569 | PickleIterator* iter); |
| 570 | static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); |
| 571 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 572 | DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 573 | }; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 574 | |
| 575 | //------------------------------------------------------------------------------ |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 576 | |
| 577 | // CustomHistogram is a histogram for a set of custom integers. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 578 | class BASE_EXPORT CustomHistogram : public Histogram { |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 579 | public: |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 580 | // |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.org | 1c03039 | 2013-01-23 13:12:17 +0900 | [diff] [blame] | 584 | static HistogramBase* FactoryGet(const std::string& name, |
| 585 | const std::vector<Sample>& custom_ranges, |
| 586 | int32 flags); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 587 | |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 588 | // Overridden from Histogram: |
kaiwang@chromium.org | 7c950a8 | 2012-10-31 15:20:25 +0900 | [diff] [blame] | 589 | virtual HistogramType GetHistogramType() const OVERRIDE; |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 590 | |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 591 | // Helper method for transforming an array of valid enumeration values |
asvitkine | 26a1203 | 2014-08-26 13:39:35 +0900 | [diff] [blame] | 592 | // to the std::vector<int> expected by UMA_HISTOGRAM_CUSTOM_ENUMERATION. |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 593 | // 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.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 596 | // TODO(kaiwang): Change name to ArrayToCustomEnumRanges. |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 597 | static std::vector<Sample> ArrayToCustomRanges(const Sample* values, |
| 598 | size_t num_values); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 599 | protected: |
| 600 | CustomHistogram(const std::string& name, |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 601 | const BucketRanges* ranges); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 602 | |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 603 | // HistogramBase implementation: |
| 604 | virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE; |
fischman@chromium.org | 5c753a0 | 2011-11-13 13:19:15 +0900 | [diff] [blame] | 605 | |
avi@chromium.org | 08e6a60 | 2011-11-16 09:08:08 +0900 | [diff] [blame] | 606 | virtual double GetBucketSize(Count current, size_t i) const OVERRIDE; |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 607 | |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 608 | private: |
kaiwang@chromium.org | e4e800c | 2013-01-12 06:52:44 +0900 | [diff] [blame] | 609 | friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( |
| 610 | PickleIterator* iter); |
| 611 | static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); |
| 612 | |
kaiwang@chromium.org | a97a5ae | 2012-08-02 06:34:08 +0900 | [diff] [blame] | 613 | static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges); |
| 614 | static BucketRanges* CreateBucketRangesFromCustomRanges( |
| 615 | const std::vector<Sample>& custom_ranges); |
| 616 | |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 617 | DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
| 618 | }; |
| 619 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 620 | } // namespace base |
| 621 | |
| 622 | #endif // BASE_METRICS_HISTOGRAM_H_ |