erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 1 | // Copyright (c) 2011 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 | |
| 12 | // The default layout of buckets is exponential. For example, buckets might |
| 13 | // contain (sequentially) the count of values in the following intervals: |
| 14 | // [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity) |
| 15 | // That bucket allocation would actually result from construction of a histogram |
| 16 | // for values between 1 and 64, with 8 buckets, such as: |
| 17 | // Histogram count(L"some name", 1, 64, 8); |
| 18 | // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity) |
| 19 | // are not counted by the constructor in the user supplied "bucket_count" |
| 20 | // argument. |
| 21 | // The above example has an exponential ratio of 2 (doubling the bucket width |
| 22 | // in each consecutive bucket. The Histogram class automatically calculates |
| 23 | // the smallest ratio that it can use to construct the number of buckets |
| 24 | // selected in the constructor. An another example, if you had 50 buckets, |
| 25 | // and millisecond time values from 1 to 10000, then the ratio between |
| 26 | // consecutive bucket widths will be approximately somewhere around the 50th |
| 27 | // root of 10000. This approach provides very fine grain (narrow) buckets |
| 28 | // at the low end of the histogram scale, but allows the histogram to cover a |
| 29 | // gigantic range with the addition of very few buckets. |
| 30 | |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 31 | // Histograms use a pattern involving a function static variable, that is a |
| 32 | // pointer to a histogram. This static is explicitly initialized on any thread |
| 33 | // that detects a uninitialized (NULL) pointer. The potentially racy |
| 34 | // initialization is not a problem as it is always set to point to the same |
| 35 | // value (i.e., the FactoryGet always returns the same value). FactoryGet |
| 36 | // is also completely thread safe, which results in a completely thread safe, |
| 37 | // and relatively fast, set of counters. To avoid races at shutdown, the static |
| 38 | // pointer is NOT deleted, and we leak the histograms at process termination. |
| 39 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 40 | #ifndef BASE_METRICS_HISTOGRAM_H_ |
| 41 | #define BASE_METRICS_HISTOGRAM_H_ |
thakis@chromium.org | 01d1452 | 2010-07-27 08:08:24 +0900 | [diff] [blame] | 42 | #pragma once |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 43 | |
| 44 | #include <map> |
| 45 | #include <string> |
| 46 | #include <vector> |
| 47 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 48 | #include "base/atomicops.h" |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 49 | #include "base/base_export.h" |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 50 | #include "base/gtest_prod_util.h" |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 51 | #include "base/logging.h" |
jar@chromium.org | 155b73c | 2009-04-11 07:29:29 +0900 | [diff] [blame] | 52 | #include "base/time.h" |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 53 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 54 | class Pickle; |
| 55 | |
| 56 | namespace base { |
erg@chromium.org | d972189 | 2010-07-17 05:30:47 +0900 | [diff] [blame] | 57 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 58 | class Lock; |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 59 | //------------------------------------------------------------------------------ |
| 60 | // Histograms are often put in areas where they are called many many times, and |
| 61 | // performance is critical. As a result, they are designed to have a very low |
| 62 | // recurring cost of executing (adding additional samples). Toward that end, |
| 63 | // the macros declare a static pointer to the histogram in question, and only |
| 64 | // take a "slow path" to construct (or find) the histogram on the first run |
| 65 | // through the macro. We leak the histograms at shutdown time so that we don't |
| 66 | // have to validate using the pointers at any time during the running of the |
| 67 | // process. |
| 68 | |
| 69 | // The following code is generally what a thread-safe static pointer |
| 70 | // initializaion looks like for a histogram (after a macro is expanded). This |
| 71 | // sample is an expansion (with comments) of the code for |
| 72 | // HISTOGRAM_CUSTOM_COUNTS(). |
| 73 | |
| 74 | /* |
| 75 | do { |
| 76 | // The pointer's presence indicates the initialization is complete. |
| 77 | // Initialization is idempotent, so it can safely be atomically repeated. |
| 78 | static base::subtle::AtomicWord atomic_histogram_pointer = 0; |
| 79 | |
| 80 | // Acquire_Load() ensures that we acquire visibility to the pointed-to data |
| 81 | // in the histogrom. |
| 82 | base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>( |
| 83 | base::subtle::Acquire_Load(&atomic_histogram_pointer))); |
| 84 | |
| 85 | if (!histogram_pointer) { |
| 86 | // This is the slow path, which will construct OR find the matching |
| 87 | // histogram. FactoryGet includes locks on a global histogram name map |
| 88 | // and is completely thread safe. |
| 89 | histogram_pointer = base::Histogram::FactoryGet( |
| 90 | name, min, max, bucket_count, base::Histogram::kNoFlags); |
| 91 | |
| 92 | // Use Release_Store to ensure that the histogram data is made available |
| 93 | // globally before we make the pointer visible. |
| 94 | // Several threads may perform this store, but the same value will be |
| 95 | // stored in all cases (for a given named/spec'ed histogram). |
| 96 | // We could do this without any barrier, since FactoryGet entered and |
| 97 | // exited a lock after construction, but this barrier makes things clear. |
| 98 | base::subtle::Release_Store(&atomic_histogram_pointer, |
| 99 | reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); |
| 100 | } |
| 101 | |
| 102 | // Ensure calling contract is upheld, and the name does NOT vary. |
| 103 | DCHECK(histogram_pointer->histogram_name() == constant_histogram_name); |
| 104 | |
| 105 | histogram_pointer->Add(sample); |
| 106 | } while (0); |
| 107 | */ |
| 108 | |
| 109 | // The above pattern is repeated in several macros. The only elements that |
| 110 | // vary are the invocation of the Add(sample) vs AddTime(sample), and the choice |
| 111 | // of which FactoryGet method to use. The different FactoryGet methods have |
| 112 | // various argument lists, so the function with its argument list is provided as |
| 113 | // a macro argument here. The name is only used in a DCHECK, to assure that |
| 114 | // callers don't try to vary the name of the histogram (which would tend to be |
| 115 | // ignored by the one-time initialization of the histogtram_pointer). |
| 116 | #define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \ |
| 117 | histogram_add_method_invocation, \ |
| 118 | histogram_factory_get_invocation) \ |
| 119 | do { \ |
| 120 | static base::subtle::AtomicWord atomic_histogram_pointer = 0; \ |
| 121 | base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>( \ |
| 122 | base::subtle::Acquire_Load(&atomic_histogram_pointer))); \ |
| 123 | if (!histogram_pointer) { \ |
| 124 | histogram_pointer = histogram_factory_get_invocation; \ |
| 125 | base::subtle::Release_Store(&atomic_histogram_pointer, \ |
| 126 | reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \ |
| 127 | } \ |
| 128 | DCHECK(histogram_pointer->histogram_name() == constant_histogram_name); \ |
| 129 | histogram_pointer->histogram_add_method_invocation; \ |
| 130 | } while (0) |
| 131 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 132 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 133 | //------------------------------------------------------------------------------ |
| 134 | // 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] | 135 | // The first four macros use 50 buckets. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 136 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 137 | #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \ |
| 138 | name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 139 | base::TimeDelta::FromSeconds(10), 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 140 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 141 | #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 142 | name, sample, 1, 1000000, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 143 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 144 | #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 145 | name, sample, 1, 100, 50) |
cpu@google.com | 04d6554 | 2009-02-05 11:13:49 +0900 | [diff] [blame] | 146 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 147 | #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 148 | name, sample, 1, 10000, 50) |
rvargas@google.com | ba686f6 | 2009-03-25 06:19:55 +0900 | [diff] [blame] | 149 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 150 | #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
| 151 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 152 | base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| 153 | base::Histogram::kNoFlags)) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 154 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 155 | #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| 156 | HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 157 | |
jar@chromium.org | 2393876 | 2009-06-21 07:32:51 +0900 | [diff] [blame] | 158 | // For folks that need real specific times, use this to select a precise range |
| 159 | // of times you want plotted, and the number of buckets you want used. |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 160 | #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
| 161 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \ |
| 162 | base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 163 | base::Histogram::kNoFlags)) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 164 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 165 | // Support histograming of an enumerated value. The samples should always be |
| 166 | // less than boundary_value. |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 167 | #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
| 168 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 169 | base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| 170 | boundary_value + 1, base::Histogram::kNoFlags)) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 171 | |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 172 | // Support histograming of an enumerated value. Samples should be one of the |
| 173 | // std::vector<int> list provided via |custom_ranges|. You can use the helper |
| 174 | // function |base::CustomHistogram::ArrayToCustomRanges(samples, num_samples)| |
| 175 | // to transform a C-style array of valid sample values to a std::vector<int>. |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 176 | #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
| 177 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 178 | base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| 179 | base::Histogram::kNoFlags)) |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 180 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 181 | //------------------------------------------------------------------------------ |
| 182 | // Define Debug vs non-debug flavors of macros. |
| 183 | #ifndef NDEBUG |
| 184 | |
| 185 | #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample) |
| 186 | #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 187 | #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\ |
| 188 | name, under_one_hundred) |
jar@chromium.org | 2393876 | 2009-06-21 07:32:51 +0900 | [diff] [blame] | 189 | #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
| 190 | HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 191 | #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ |
| 192 | HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 193 | #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 194 | HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) |
| 195 | #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
| 196 | HISTOGRAM_ENUMERATION(name, sample, boundary_value) |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 197 | #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
| 198 | HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 199 | |
| 200 | #else // NDEBUG |
| 201 | |
| 202 | #define DHISTOGRAM_TIMES(name, sample) do {} while (0) |
| 203 | #define DHISTOGRAM_COUNTS(name, sample) do {} while (0) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 204 | #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) do {} while (0) |
jar@chromium.org | 2393876 | 2009-06-21 07:32:51 +0900 | [diff] [blame] | 205 | #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
| 206 | do {} while (0) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 207 | #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ |
| 208 | do {} while (0) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 209 | #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 210 | do {} while (0) |
| 211 | #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) do {} while (0) |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 212 | #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
| 213 | do {} while (0) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 214 | |
| 215 | #endif // NDEBUG |
| 216 | |
| 217 | //------------------------------------------------------------------------------ |
| 218 | // The following macros provide typical usage scenarios for callers that wish |
| 219 | // to record histogram data, and have the data submitted/uploaded via UMA. |
| 220 | // Not all systems support such UMA, but if they do, the following macros |
| 221 | // should work with the service. |
| 222 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 223 | #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 224 | name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 225 | base::TimeDelta::FromSeconds(10), 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 226 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 227 | #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 228 | name, sample, base::TimeDelta::FromMilliseconds(10), \ |
| 229 | base::TimeDelta::FromMinutes(3), 50) |
jar@google.com | a5c410d | 2008-11-22 10:40:22 +0900 | [diff] [blame] | 230 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 231 | // 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] | 232 | #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 233 | name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 234 | base::TimeDelta::FromHours(1), 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 235 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 236 | #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
| 237 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \ |
| 238 | base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 239 | base::Histogram::kUmaTargetedHistogramFlag)) |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 240 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 241 | #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 242 | name, sample, 1, 1000000, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 243 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 244 | #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 245 | name, sample, 1, 100, 50) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 246 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 247 | #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 248 | name, sample, 1, 10000, 50) |
rvargas@google.com | ba686f6 | 2009-03-25 06:19:55 +0900 | [diff] [blame] | 249 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 250 | #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
| 251 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 252 | base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| 253 | base::Histogram::kUmaTargetedHistogramFlag)) |
jar@chromium.org | a88727c | 2009-06-30 01:40:13 +0900 | [diff] [blame] | 254 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 255 | #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 256 | name, sample, 1000, 500000, 50) |
| 257 | |
| 258 | #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 259 | name, sample, 1, 1000, 50) |
| 260 | |
| 261 | #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| 262 | UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
| 263 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 264 | #define UMA_HISTOGRAM_BOOLEAN(name, sample) \ |
| 265 | STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \ |
| 266 | base::BooleanHistogram::FactoryGet(name, \ |
| 267 | base::Histogram::kUmaTargetedHistogramFlag)) |
isherman@chromium.org | 8cdb021 | 2011-04-14 05:55:10 +0900 | [diff] [blame] | 268 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 269 | #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
| 270 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 271 | base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| 272 | boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag)) |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 273 | |
jar@chromium.org | c5d86fd | 2011-08-07 14:19:08 +0900 | [diff] [blame] | 274 | #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
| 275 | STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ |
| 276 | base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| 277 | base::Histogram::kUmaTargetedHistogramFlag)) |
jar@chromium.org | 775d977 | 2009-03-14 05:29:58 +0900 | [diff] [blame] | 278 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 279 | //------------------------------------------------------------------------------ |
| 280 | |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 281 | class BooleanHistogram; |
| 282 | class CustomHistogram; |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 283 | class Histogram; |
| 284 | class LinearHistogram; |
thestig@chromium.org | 05d9dd2 | 2009-04-04 03:18:55 +0900 | [diff] [blame] | 285 | |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 286 | class BASE_EXPORT Histogram { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 287 | public: |
| 288 | typedef int Sample; // Used for samples (and ranges of samples). |
| 289 | typedef int Count; // Used to count samples in a bucket. |
| 290 | static const Sample kSampleType_MAX = INT_MAX; |
rtenneti@chromium.org | 6ef07b5 | 2011-03-02 17:04:57 +0900 | [diff] [blame] | 291 | // Initialize maximum number of buckets in histograms as 16,384. |
rtenneti@chromium.org | 5a0b62f | 2011-02-24 07:31:18 +0900 | [diff] [blame] | 292 | static const size_t kBucketCount_MAX; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 293 | |
| 294 | typedef std::vector<Count> Counts; |
deanm@google.com | 1818847 | 2008-08-12 03:57:54 +0900 | [diff] [blame] | 295 | typedef std::vector<Sample> Ranges; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 296 | |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 297 | // These enums are used to facilitate deserialization of renderer histograms |
| 298 | // into the browser. |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 299 | enum ClassType { |
| 300 | HISTOGRAM, |
| 301 | LINEAR_HISTOGRAM, |
| 302 | BOOLEAN_HISTOGRAM, |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 303 | CUSTOM_HISTOGRAM, |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 304 | NOT_VALID_IN_RENDERER |
| 305 | }; |
| 306 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 307 | enum BucketLayout { |
| 308 | EXPONENTIAL, |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 309 | LINEAR, |
| 310 | CUSTOM |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 311 | }; |
| 312 | |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 313 | enum Flags { |
| 314 | kNoFlags = 0, |
| 315 | kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. |
| 316 | |
| 317 | // Indicate that the histogram was pickled to be sent across an IPC Channel. |
| 318 | // If we observe this flag on a histogram being aggregated into after IPC, |
| 319 | // then we are running in a single process mode, and the aggregation should |
| 320 | // not take place (as we would be aggregating back into the source |
| 321 | // histogram!). |
| 322 | kIPCSerializationSourceFlag = 0x10, |
| 323 | |
| 324 | kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported. |
| 325 | }; |
| 326 | |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 327 | enum Inconsistencies { |
| 328 | NO_INCONSISTENCIES = 0x0, |
| 329 | RANGE_CHECKSUM_ERROR = 0x1, |
| 330 | BUCKET_ORDER_ERROR = 0x2, |
| 331 | COUNT_HIGH_ERROR = 0x4, |
| 332 | COUNT_LOW_ERROR = 0x8, |
| 333 | |
| 334 | NEVER_EXCEEDED_VALUE = 0x10 |
| 335 | }; |
| 336 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 337 | struct DescriptionPair { |
| 338 | Sample sample; |
| 339 | const char* description; // Null means end of a list of pairs. |
| 340 | }; |
| 341 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 342 | //---------------------------------------------------------------------------- |
| 343 | // Statistic values, developed over the life of the histogram. |
| 344 | |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 345 | class BASE_EXPORT SampleSet { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 346 | public: |
| 347 | explicit SampleSet(); |
erg@google.com | 7191523 | 2010-09-29 07:54:58 +0900 | [diff] [blame] | 348 | ~SampleSet(); |
| 349 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 350 | // Adjust size of counts_ for use with given histogram. |
| 351 | void Resize(const Histogram& histogram); |
| 352 | void CheckSize(const Histogram& histogram) const; |
| 353 | |
| 354 | // Accessor for histogram to make routine additions. |
| 355 | void Accumulate(Sample value, Count count, size_t index); |
| 356 | |
| 357 | // Accessor methods. |
| 358 | Count counts(size_t i) const { return counts_[i]; } |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 359 | Count TotalCount() const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 360 | int64 sum() const { return sum_; } |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 361 | int64 redundant_count() const { return redundant_count_; } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 362 | |
| 363 | // Arithmetic manipulation of corresponding elements of the set. |
| 364 | void Add(const SampleSet& other); |
| 365 | void Subtract(const SampleSet& other); |
| 366 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 367 | bool Serialize(Pickle* pickle) const; |
| 368 | bool Deserialize(void** iter, const Pickle& pickle); |
| 369 | |
rvargas@google.com | 644c912 | 2008-09-25 08:51:25 +0900 | [diff] [blame] | 370 | protected: |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 371 | // Actual histogram data is stored in buckets, showing the count of values |
| 372 | // that fit into each bucket. |
| 373 | Counts counts_; |
| 374 | |
| 375 | // Save simple stats locally. Note that this MIGHT get done in base class |
| 376 | // without shared memory at some point. |
| 377 | int64 sum_; // sum of samples. |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 378 | |
| 379 | private: |
| 380 | // Allow tests to corrupt our innards for testing purposes. |
| 381 | FRIEND_TEST(HistogramTest, CorruptSampleCounts); |
| 382 | |
| 383 | // To help identify memory corruption, we reduntantly save the number of |
| 384 | // samples we've accumulated into all of our buckets. We can compare this |
| 385 | // count to the sum of the counts in all buckets, and detect problems. Note |
| 386 | // that due to races in histogram accumulation (if a histogram is indeed |
| 387 | // updated on several threads simultaneously), the tallies might mismatch, |
| 388 | // and also the snapshotting code may asynchronously get a mismatch (though |
| 389 | // generally either race based mismatch cause is VERY rare). |
| 390 | int64 redundant_count_; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 391 | }; |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 392 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 393 | //---------------------------------------------------------------------------- |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 394 | // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
| 395 | // default underflow bucket. |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 396 | static Histogram* FactoryGet(const std::string& name, |
| 397 | Sample minimum, |
| 398 | Sample maximum, |
| 399 | size_t bucket_count, |
| 400 | Flags flags); |
| 401 | static Histogram* FactoryTimeGet(const std::string& name, |
| 402 | base::TimeDelta minimum, |
| 403 | base::TimeDelta maximum, |
| 404 | size_t bucket_count, |
| 405 | Flags flags); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 406 | |
jar@chromium.org | 155b73c | 2009-04-11 07:29:29 +0900 | [diff] [blame] | 407 | void Add(int value); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 408 | |
| 409 | // This method is an interface, used only by BooleanHistogram. |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 410 | virtual void AddBoolean(bool value); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 411 | |
jar@chromium.org | 155b73c | 2009-04-11 07:29:29 +0900 | [diff] [blame] | 412 | // Accept a TimeDelta to increment. |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 413 | void AddTime(TimeDelta time) { |
jar@chromium.org | 155b73c | 2009-04-11 07:29:29 +0900 | [diff] [blame] | 414 | Add(static_cast<int>(time.InMilliseconds())); |
| 415 | } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 416 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 417 | void AddSampleSet(const SampleSet& sample); |
| 418 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 419 | // This method is an interface, used only by LinearHistogram. |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 420 | virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 421 | |
jar@google.com | a5c410d | 2008-11-22 10:40:22 +0900 | [diff] [blame] | 422 | // The following methods provide graphical histogram displays. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 423 | void WriteHTMLGraph(std::string* output) const; |
| 424 | void WriteAscii(bool graph_it, const std::string& newline, |
| 425 | std::string* output) const; |
| 426 | |
| 427 | // Support generic flagging of Histograms. |
| 428 | // 0x1 Currently used to mark this histogram to be recorded by UMA.. |
| 429 | // 0x8000 means print ranges in hex. |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 430 | void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); } |
| 431 | void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 432 | int flags() const { return flags_; } |
| 433 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 434 | // Convenience methods for serializing/deserializing the histograms. |
| 435 | // Histograms from Renderer process are serialized and sent to the browser. |
| 436 | // Browser process reconstructs the histogram from the pickled version |
| 437 | // accumulates the browser-side shadow copy of histograms (that mirror |
| 438 | // histograms created in the renderer). |
| 439 | |
| 440 | // Serialize the given snapshot of a Histogram into a String. Uses |
| 441 | // Pickle class to flatten the object. |
| 442 | static std::string SerializeHistogramInfo(const Histogram& histogram, |
| 443 | const SampleSet& snapshot); |
| 444 | // The following method accepts a list of pickled histograms and |
| 445 | // builds a histogram and updates shadow copy of histogram data in the |
| 446 | // browser process. |
jar@chromium.org | 1ac6a11 | 2009-05-29 07:02:46 +0900 | [diff] [blame] | 447 | static bool DeserializeHistogramInfo(const std::string& histogram_info); |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 448 | |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 449 | // Check to see if bucket ranges, counts and tallies in the snapshot are |
| 450 | // consistent with the bucket ranges and checksums in our histogram. This can |
| 451 | // produce a false-alarm if a race occurred in the reading of the data during |
| 452 | // a SnapShot process, but should otherwise be false at all times (unless we |
| 453 | // have memory over-writes, or DRAM failures). |
| 454 | virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const; |
| 455 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 456 | //---------------------------------------------------------------------------- |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 457 | // Accessors for factory constuction, serialization and testing. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 458 | //---------------------------------------------------------------------------- |
erg@google.com | 190e7b0 | 2010-12-10 03:25:03 +0900 | [diff] [blame] | 459 | virtual ClassType histogram_type() const; |
erg@chromium.org | d972189 | 2010-07-17 05:30:47 +0900 | [diff] [blame] | 460 | const std::string& histogram_name() const { return histogram_name_; } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 461 | Sample declared_min() const { return declared_min_; } |
| 462 | Sample declared_max() const { return declared_max_; } |
erg@google.com | 190e7b0 | 2010-12-10 03:25:03 +0900 | [diff] [blame] | 463 | virtual Sample ranges(size_t i) const; |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 464 | uint32 range_checksum() const { return range_checksum_; } |
erg@google.com | 190e7b0 | 2010-12-10 03:25:03 +0900 | [diff] [blame] | 465 | virtual size_t bucket_count() const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 466 | // Snapshot the current complete set of sample data. |
| 467 | // Override with atomic/locked snapshot if needed. |
| 468 | virtual void SnapshotSample(SampleSet* sample) const; |
| 469 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 470 | virtual bool HasConstructorArguments(Sample minimum, Sample maximum, |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 471 | size_t bucket_count); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 472 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 473 | virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, |
| 474 | TimeDelta maximum, |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 475 | size_t bucket_count); |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 476 | // Return true iff the range_checksum_ matches current ranges_ vector. |
| 477 | bool HasValidRangeChecksum() const; |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 478 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 479 | protected: |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 480 | Histogram(const std::string& name, Sample minimum, |
| 481 | Sample maximum, size_t bucket_count); |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 482 | Histogram(const std::string& name, TimeDelta minimum, |
| 483 | TimeDelta maximum, size_t bucket_count); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 484 | |
| 485 | virtual ~Histogram(); |
| 486 | |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 487 | // Initialize ranges_ mapping. |
| 488 | void InitializeBucketRange(); |
| 489 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 490 | // 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] | 491 | virtual bool PrintEmptyBucket(size_t index) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 492 | |
| 493 | //---------------------------------------------------------------------------- |
| 494 | // Methods to override to create histogram with different bucket widths. |
| 495 | //---------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 496 | // Find bucket to increment for sample value. |
| 497 | virtual size_t BucketIndex(Sample value) const; |
| 498 | // Get normalized size, relative to the ranges_[i]. |
| 499 | virtual double GetBucketSize(Count current, size_t i) const; |
| 500 | |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 501 | // Recalculate range_checksum_. |
| 502 | void ResetRangeChecksum(); |
| 503 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 504 | // Return a string description of what goes in a given bucket. |
| 505 | // Most commonly this is the numeric value, but in derived classes it may |
| 506 | // be a name (or string description) given to the bucket. |
| 507 | virtual const std::string GetAsciiBucketRange(size_t it) const; |
| 508 | |
| 509 | //---------------------------------------------------------------------------- |
| 510 | // Methods to override to create thread safe histogram. |
| 511 | //---------------------------------------------------------------------------- |
| 512 | // Update all our internal data, including histogram |
| 513 | virtual void Accumulate(Sample value, Count count, size_t index); |
| 514 | |
| 515 | //---------------------------------------------------------------------------- |
| 516 | // Accessors for derived classes. |
| 517 | //---------------------------------------------------------------------------- |
| 518 | void SetBucketRange(size_t i, Sample value); |
| 519 | |
| 520 | // Validate that ranges_ was created sensibly (top and bottom range |
| 521 | // values relate properly to the declared_min_ and declared_max_).. |
| 522 | bool ValidateBucketRanges() const; |
| 523 | |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 524 | virtual uint32 CalculateRangeChecksum() const; |
| 525 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 526 | private: |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 527 | // Allow tests to corrupt our innards for testing purposes. |
| 528 | FRIEND_TEST(HistogramTest, CorruptBucketBounds); |
| 529 | FRIEND_TEST(HistogramTest, CorruptSampleCounts); |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 530 | FRIEND_TEST(HistogramTest, Crc32SampleHash); |
| 531 | FRIEND_TEST(HistogramTest, Crc32TableTest); |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 532 | |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 533 | friend class StatisticsRecorder; // To allow it to delete duplicates. |
| 534 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 535 | // Post constructor initialization. |
| 536 | void Initialize(); |
| 537 | |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 538 | // Checksum function for accumulating range values into a checksum. |
| 539 | static uint32 Crc32(uint32 sum, Sample range); |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 540 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 541 | //---------------------------------------------------------------------------- |
| 542 | // Helpers for emitting Ascii graphic. Each method appends data to output. |
| 543 | |
| 544 | // Find out how large the (graphically) the largest bucket will appear to be. |
| 545 | double GetPeakBucketSize(const SampleSet& snapshot) const; |
| 546 | |
| 547 | // Write a common header message describing this histogram. |
| 548 | void WriteAsciiHeader(const SampleSet& snapshot, |
jar@chromium.org | 373b686 | 2009-02-02 15:50:03 +0900 | [diff] [blame] | 549 | Count sample_count, std::string* output) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 550 | |
| 551 | // Write information about previous, current, and next buckets. |
| 552 | // Information such as cumulative percentage, etc. |
| 553 | void WriteAsciiBucketContext(const int64 past, const Count current, |
| 554 | const int64 remaining, const size_t i, |
| 555 | std::string* output) const; |
| 556 | |
| 557 | // Write textual description of the bucket contents (relative to histogram). |
| 558 | // Output is the count in the buckets, as well as the percentage. |
| 559 | void WriteAsciiBucketValue(Count current, double scaled_sum, |
| 560 | std::string* output) const; |
| 561 | |
| 562 | // Produce actual graph (set of blank vs non blank char's) for a bucket. |
| 563 | void WriteAsciiBucketGraph(double current_size, double max_size, |
| 564 | std::string* output) const; |
| 565 | |
| 566 | //---------------------------------------------------------------------------- |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 567 | // Table for generating Crc32 values. |
| 568 | static const uint32 kCrcTable[256]; |
| 569 | //---------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 570 | // Invariant values set at/near construction time |
| 571 | |
| 572 | // ASCII version of original name given to the constructor. All identically |
jar@chromium.org | f5db368 | 2010-05-29 10:54:40 +0900 | [diff] [blame] | 573 | // named instances will be coalesced cross-project. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 574 | const std::string histogram_name_; |
| 575 | Sample declared_min_; // Less than this goes into counts_[0] |
| 576 | Sample declared_max_; // Over this goes into counts_[bucket_count_ - 1]. |
| 577 | size_t bucket_count_; // Dimension of counts_[]. |
| 578 | |
| 579 | // Flag the histogram for recording by UMA via metric_services.h. |
jar@chromium.org | ed5238a | 2009-12-28 15:59:52 +0900 | [diff] [blame] | 580 | Flags flags_; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 581 | |
| 582 | // For each index, show the least value that can be stored in the |
| 583 | // corresponding bucket. We also append one extra element in this array, |
| 584 | // containing kSampleType_MAX, to make calculations easy. |
| 585 | // The dimension of ranges_ is bucket_count + 1. |
| 586 | Ranges ranges_; |
| 587 | |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 588 | // For redundancy, we store a checksum of all the sample ranges when ranges |
| 589 | // are generated. If ever there is ever a difference, then the histogram must |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 590 | // have been corrupted. |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 591 | uint32 range_checksum_; |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 592 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 593 | // Finally, provide the state that changes with the addition of each new |
| 594 | // sample. |
| 595 | SampleSet sample_; |
| 596 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 597 | DISALLOW_COPY_AND_ASSIGN(Histogram); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 598 | }; |
| 599 | |
| 600 | //------------------------------------------------------------------------------ |
| 601 | |
| 602 | // LinearHistogram is a more traditional histogram, with evenly spaced |
| 603 | // buckets. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 604 | class BASE_EXPORT LinearHistogram : public Histogram { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 605 | public: |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 606 | virtual ~LinearHistogram(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 607 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 608 | /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit |
| 609 | default underflow bucket. */ |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 610 | static Histogram* FactoryGet(const std::string& name, |
| 611 | Sample minimum, |
| 612 | Sample maximum, |
| 613 | size_t bucket_count, |
| 614 | Flags flags); |
| 615 | static Histogram* FactoryTimeGet(const std::string& name, |
| 616 | TimeDelta minimum, |
| 617 | TimeDelta maximum, |
| 618 | size_t bucket_count, |
| 619 | Flags flags); |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 620 | |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 621 | // Overridden from Histogram: |
| 622 | virtual ClassType histogram_type() const; |
| 623 | |
| 624 | // Store a list of number/text values for use in rendering the histogram. |
| 625 | // The last element in the array has a null in its "description" slot. |
| 626 | virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); |
erg@google.com | 7191523 | 2010-09-29 07:54:58 +0900 | [diff] [blame] | 627 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 628 | protected: |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 629 | LinearHistogram(const std::string& name, Sample minimum, |
| 630 | Sample maximum, size_t bucket_count); |
| 631 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 632 | LinearHistogram(const std::string& name, TimeDelta minimum, |
| 633 | TimeDelta maximum, size_t bucket_count); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 634 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 635 | // Initialize ranges_ mapping. |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 636 | void InitializeBucketRange(); |
mmoss@google.com | b16d6e0 | 2008-08-14 04:38:25 +0900 | [diff] [blame] | 637 | virtual double GetBucketSize(Count current, size_t i) const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 638 | |
| 639 | // If we have a description for a bucket, then return that. Otherwise |
| 640 | // let parent class provide a (numeric) description. |
| 641 | virtual const std::string GetAsciiBucketRange(size_t i) const; |
| 642 | |
| 643 | // Skip printing of name for numeric range if we have a name (and if this is |
| 644 | // an empty bucket). |
| 645 | virtual bool PrintEmptyBucket(size_t index) const; |
| 646 | |
| 647 | private: |
| 648 | // For some ranges, we store a printable description of a bucket range. |
| 649 | // If there is no desciption, then GetAsciiBucketRange() uses parent class |
| 650 | // to provide a description. |
| 651 | typedef std::map<Sample, std::string> BucketDescriptionMap; |
| 652 | BucketDescriptionMap bucket_description_; |
| 653 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 654 | DISALLOW_COPY_AND_ASSIGN(LinearHistogram); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 655 | }; |
| 656 | |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 657 | //------------------------------------------------------------------------------ |
| 658 | |
| 659 | // BooleanHistogram is a histogram for booleans. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 660 | class BASE_EXPORT BooleanHistogram : public LinearHistogram { |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 661 | public: |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 662 | static Histogram* FactoryGet(const std::string& name, Flags flags); |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 663 | |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 664 | virtual ClassType histogram_type() const; |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 665 | |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 666 | virtual void AddBoolean(bool value); |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 667 | |
| 668 | private: |
erg@google.com | 6e67c1d | 2010-07-29 02:25:28 +0900 | [diff] [blame] | 669 | explicit BooleanHistogram(const std::string& name); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 670 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 671 | DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); |
abarth@chromium.org | 7ed364e | 2009-01-18 04:15:36 +0900 | [diff] [blame] | 672 | }; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 673 | |
| 674 | //------------------------------------------------------------------------------ |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 675 | |
| 676 | // CustomHistogram is a histogram for a set of custom integers. |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 677 | class BASE_EXPORT CustomHistogram : public Histogram { |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 678 | public: |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 679 | |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 680 | static Histogram* FactoryGet(const std::string& name, |
| 681 | const std::vector<Sample>& custom_ranges, |
| 682 | Flags flags); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 683 | |
erg@google.com | d5fffd4 | 2011-01-08 03:06:45 +0900 | [diff] [blame] | 684 | // Overridden from Histogram: |
| 685 | virtual ClassType histogram_type() const; |
| 686 | |
joi@chromium.org | fd1b87b | 2011-05-24 22:59:58 +0900 | [diff] [blame] | 687 | // Helper method for transforming an array of valid enumeration values |
| 688 | // to the std::vector<int> expected by HISTOGRAM_CUSTOM_ENUMERATION. |
| 689 | // This function ensures that a guard bucket exists right after any |
| 690 | // valid sample value (unless the next higher sample is also a valid value), |
| 691 | // so that invalid samples never fall into the same bucket as valid samples. |
| 692 | static std::vector<Sample> ArrayToCustomRanges(const Sample* values, |
| 693 | size_t num_values); |
| 694 | |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 695 | protected: |
| 696 | CustomHistogram(const std::string& name, |
jar@chromium.org | ae56e48 | 2010-11-04 08:36:24 +0900 | [diff] [blame] | 697 | const std::vector<Sample>& custom_ranges); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 698 | |
| 699 | // Initialize ranges_ mapping. |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 700 | void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges); |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 701 | virtual double GetBucketSize(Count current, size_t i) const; |
| 702 | |
jar@chromium.org | 84320c5 | 2010-04-30 07:39:55 +0900 | [diff] [blame] | 703 | DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
| 704 | }; |
| 705 | |
| 706 | //------------------------------------------------------------------------------ |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 707 | // StatisticsRecorder handles all histograms in the system. It provides a |
| 708 | // general place for histograms to register, and supports a global API for |
| 709 | // accessing (i.e., dumping, or graphing) the data in all the histograms. |
| 710 | |
darin@chromium.org | e585bed | 2011-08-06 00:34:00 +0900 | [diff] [blame] | 711 | class BASE_EXPORT StatisticsRecorder { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 712 | public: |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 713 | typedef std::vector<Histogram*> Histograms; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 714 | |
| 715 | StatisticsRecorder(); |
| 716 | |
| 717 | ~StatisticsRecorder(); |
| 718 | |
| 719 | // Find out if histograms can now be registered into our list. |
mad@chromium.org | 42f95b5 | 2010-12-23 23:40:10 +0900 | [diff] [blame] | 720 | static bool IsActive(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 721 | |
jar@chromium.org | cfdfbef | 2011-03-05 15:22:24 +0900 | [diff] [blame] | 722 | // Register, or add a new histogram to the collection of statistics. If an |
| 723 | // identically named histogram is already registered, then the argument |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 724 | // |histogram| will deleted. The returned value is always the registered |
| 725 | // histogram (either the argument, or the pre-existing registered histogram). |
| 726 | static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 727 | |
| 728 | // Methods for printing histograms. Only histograms which have query as |
| 729 | // a substring are written to output (an empty string will process all |
| 730 | // registered histograms). |
| 731 | static void WriteHTMLGraph(const std::string& query, std::string* output); |
| 732 | static void WriteGraph(const std::string& query, std::string* output); |
| 733 | |
| 734 | // Method for extracting histograms which were marked for use by UMA. |
| 735 | static void GetHistograms(Histograms* output); |
| 736 | |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 737 | // Find a histogram by name. It matches the exact name. This method is thread |
jar@chromium.org | 682dbbd | 2010-06-26 00:55:15 +0900 | [diff] [blame] | 738 | // safe. If a matching histogram is not found, then the |histogram| is |
| 739 | // not changed. |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 740 | static bool FindHistogram(const std::string& query, Histogram** histogram); |
jar@chromium.org | fe4c0d1 | 2009-12-06 09:09:37 +0900 | [diff] [blame] | 741 | |
| 742 | static bool dump_on_exit() { return dump_on_exit_; } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 743 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 744 | static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 745 | |
| 746 | // GetSnapshot copies some of the pointers to registered histograms into the |
| 747 | // caller supplied vector (Histograms). Only histograms with names matching |
| 748 | // query are returned. The query must be a substring of histogram name for its |
| 749 | // pointer to be copied. |
| 750 | static void GetSnapshot(const std::string& query, Histograms* snapshot); |
| 751 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 752 | |
| 753 | private: |
| 754 | // We keep all registered histograms in a map, from name to histogram. |
jar@chromium.org | 3457114 | 2011-04-05 13:48:53 +0900 | [diff] [blame] | 755 | typedef std::map<std::string, Histogram*> HistogramMap; |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 756 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 757 | static HistogramMap* histograms_; |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 758 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 759 | // lock protects access to the above map. |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 760 | static base::Lock* lock_; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 761 | |
| 762 | // Dump all known histograms to log. |
| 763 | static bool dump_on_exit_; |
| 764 | |
jar@chromium.org | bb363fd | 2009-02-25 15:10:17 +0900 | [diff] [blame] | 765 | DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 766 | }; |
| 767 | |
brettw@chromium.org | 275c2ec | 2010-10-14 13:38:38 +0900 | [diff] [blame] | 768 | } // namespace base |
| 769 | |
| 770 | #endif // BASE_METRICS_HISTOGRAM_H_ |