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