Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Histogram is an object that aggregates statistics, and can summarize them in | 5 // Histogram is an object that aggregates statistics, and can summarize them in |
| 6 // various forms, including ASCII graphical, HTML, and numerically (as a | 6 // various forms, including ASCII graphical, HTML, and numerically (as a |
| 7 // vector of numbers corresponding to each of the aggregating buckets). | 7 // vector of numbers corresponding to each of the aggregating buckets). |
| 8 | 8 |
| 9 // It supports calls to accumulate either time intervals (which are processed | 9 // It supports calls to accumulate either time intervals (which are processed |
| 10 // as integral number of milliseconds), or arbitrary integral units. | 10 // as integral number of milliseconds), or arbitrary integral units. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 // The above example has an exponential ratio of 2 (doubling the bucket width | 21 // The above example has an exponential ratio of 2 (doubling the bucket width |
| 22 // in each consecutive bucket. The Histogram class automatically calculates | 22 // in each consecutive bucket. The Histogram class automatically calculates |
| 23 // the smallest ratio that it can use to construct the number of buckets | 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, | 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 | 25 // and millisecond time values from 1 to 10000, then the ratio between |
| 26 // consecutive bucket widths will be approximately somewhere around the 50th | 26 // consecutive bucket widths will be approximately somewhere around the 50th |
| 27 // root of 10000. This approach provides very fine grain (narrow) buckets | 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 | 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. | 29 // gigantic range with the addition of very few buckets. |
| 30 | 30 |
| 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. | |
|
rvargas (doing something else)
2011/04/01 19:20:52
Have you considered using LazyInstance<> instead?
jar (doing other things)
2011/04/01 21:50:27
As per discussion, one major point is that this co
willchan no longer on Chromium
2011/04/02 07:43:31
I think you misunderstand LazyInstance. Both LazyI
| |
| 39 | |
| 31 #ifndef BASE_METRICS_HISTOGRAM_H_ | 40 #ifndef BASE_METRICS_HISTOGRAM_H_ |
| 32 #define BASE_METRICS_HISTOGRAM_H_ | 41 #define BASE_METRICS_HISTOGRAM_H_ |
| 33 #pragma once | 42 #pragma once |
| 34 | 43 |
| 35 #include <map> | 44 #include <map> |
| 36 #include <string> | 45 #include <string> |
| 37 #include <vector> | 46 #include <vector> |
| 38 | 47 |
| 39 #include "base/base_api.h" | 48 #include "base/base_api.h" |
| 40 #include "base/gtest_prod_util.h" | 49 #include "base/gtest_prod_util.h" |
| 41 #include "base/logging.h" | 50 #include "base/logging.h" |
| 42 #include "base/memory/ref_counted.h" | |
| 43 #include "base/time.h" | 51 #include "base/time.h" |
| 44 | 52 |
| 45 class Pickle; | 53 class Pickle; |
| 46 | 54 |
| 47 namespace base { | 55 namespace base { |
| 48 | 56 |
| 49 class Lock; | 57 class Lock; |
| 50 | 58 |
| 51 //------------------------------------------------------------------------------ | 59 //------------------------------------------------------------------------------ |
| 52 // Provide easy general purpose histogram in a macro, just like stats counters. | 60 // Provide easy general purpose histogram in a macro, just like stats counters. |
| 53 // The first four macros use 50 buckets. | 61 // The first four macros use 50 buckets. |
| 54 | 62 |
| 55 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \ | 63 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \ |
| 56 name, sample, base::TimeDelta::FromMilliseconds(1), \ | 64 name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 57 base::TimeDelta::FromSeconds(10), 50) | 65 base::TimeDelta::FromSeconds(10), 50) |
| 58 | 66 |
| 59 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ | 67 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 60 name, sample, 1, 1000000, 50) | 68 name, sample, 1, 1000000, 50) |
| 61 | 69 |
| 62 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ | 70 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 63 name, sample, 1, 100, 50) | 71 name, sample, 1, 100, 50) |
| 64 | 72 |
| 65 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ | 73 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
| 66 name, sample, 1, 10000, 50) | 74 name, sample, 1, 10000, 50) |
| 67 | 75 |
| 68 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ | 76 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
| 69 scoped_refptr<base::Histogram> counter = \ | 77 static base::Histogram* counter(NULL); \ |
| 70 base::Histogram::FactoryGet(name, min, max, bucket_count, \ | 78 if (!counter) \ |
| 71 base::Histogram::kNoFlags); \ | 79 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| 80 base::Histogram::kNoFlags); \ | |
| 72 DCHECK_EQ(name, counter->histogram_name()); \ | 81 DCHECK_EQ(name, counter->histogram_name()); \ |
| 73 if (counter.get()) counter->Add(sample); \ | 82 counter->Add(sample); \ |
| 74 } while (0) | 83 } while (0) |
| 75 | 84 |
| 76 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ | 85 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| 77 HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) | 86 HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
| 78 | 87 |
| 79 // For folks that need real specific times, use this to select a precise range | 88 // For folks that need real specific times, use this to select a precise range |
| 80 // of times you want plotted, and the number of buckets you want used. | 89 // of times you want plotted, and the number of buckets you want used. |
| 81 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ | 90 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
| 82 scoped_refptr<base::Histogram> counter = \ | 91 static base::Histogram* counter(NULL); \ |
| 83 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ | 92 if (!counter) \ |
| 84 base::Histogram::kNoFlags); \ | 93 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 94 base::Histogram::kNoFlags); \ | |
| 85 DCHECK_EQ(name, counter->histogram_name()); \ | 95 DCHECK_EQ(name, counter->histogram_name()); \ |
| 86 if (counter.get()) counter->AddTime(sample); \ | 96 counter->AddTime(sample); \ |
| 87 } while (0) | 97 } while (0) |
| 88 | 98 |
| 89 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. | 99 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. .... |
|
ramant (doing other things)
2011/04/01 20:05:38
More than 80 characters. Did you want to delete th
jar (doing other things)
2011/04/01 21:50:27
Done.
| |
| 90 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ | 100 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
| 91 scoped_refptr<base::Histogram> counter = \ | 101 static base::Histogram* counter(NULL); \ |
| 92 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ | 102 if (!counter) \ |
| 93 base::Histogram::kNoFlags); \ | 103 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 104 base::Histogram::kNoFlags); \ | |
| 94 DCHECK_EQ(name, counter->histogram_name()); \ | 105 DCHECK_EQ(name, counter->histogram_name()); \ |
| 95 if ((sample) < (max) && counter.get()) counter->AddTime(sample); \ | 106 if ((sample) < (max)) counter->AddTime(sample); \ |
| 96 } while (0) | 107 } while (0) |
| 97 | 108 |
| 98 // Support histograming of an enumerated value. The samples should always be | 109 // Support histograming of an enumerated value. The samples should always be |
| 99 // less than boundary_value. | 110 // less than boundary_value. |
| 100 | 111 |
| 101 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ | 112 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
| 102 scoped_refptr<base::Histogram> counter = \ | 113 static base::Histogram* counter(NULL); \ |
| 103 base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ | 114 if (!counter) \ |
| 104 boundary_value + 1, \ | 115 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| 105 base::Histogram::kNoFlags); \ | 116 boundary_value + 1, base::Histogram::kNoFlags); \ |
| 106 DCHECK_EQ(name, counter->histogram_name()); \ | 117 DCHECK_EQ(name, counter->histogram_name()); \ |
| 107 if (counter.get()) counter->Add(sample); \ | 118 counter->Add(sample); \ |
| 108 } while (0) | 119 } while (0) |
| 109 | 120 |
| 110 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ | 121 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
| 111 scoped_refptr<base::Histogram> counter = \ | 122 static base::Histogram* counter(NULL); \ |
| 112 base::CustomHistogram::FactoryGet(name, custom_ranges, \ | 123 if (!counter) \ |
| 113 base::Histogram::kNoFlags); \ | 124 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| 125 base::Histogram::kNoFlags); \ | |
| 114 DCHECK_EQ(name, counter->histogram_name()); \ | 126 DCHECK_EQ(name, counter->histogram_name()); \ |
| 115 if (counter.get()) counter->Add(sample); \ | 127 counter->Add(sample); \ |
| 116 } while (0) | 128 } while (0) |
| 117 | 129 |
| 118 | 130 |
| 119 //------------------------------------------------------------------------------ | 131 //------------------------------------------------------------------------------ |
| 120 // Define Debug vs non-debug flavors of macros. | 132 // Define Debug vs non-debug flavors of macros. |
| 121 #ifndef NDEBUG | 133 #ifndef NDEBUG |
| 122 | 134 |
| 123 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample) | 135 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample) |
| 124 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample) | 136 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample) |
| 125 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\ | 137 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\ |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ | 177 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 166 name, sample, base::TimeDelta::FromMilliseconds(10), \ | 178 name, sample, base::TimeDelta::FromMilliseconds(10), \ |
| 167 base::TimeDelta::FromMinutes(3), 50) | 179 base::TimeDelta::FromMinutes(3), 50) |
| 168 | 180 |
| 169 // Use this macro when times can routinely be much longer than 10 seconds. | 181 // Use this macro when times can routinely be much longer than 10 seconds. |
| 170 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ | 182 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| 171 name, sample, base::TimeDelta::FromMilliseconds(1), \ | 183 name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| 172 base::TimeDelta::FromHours(1), 50) | 184 base::TimeDelta::FromHours(1), 50) |
| 173 | 185 |
| 174 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ | 186 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
| 175 scoped_refptr<base::Histogram> counter = \ | 187 static base::Histogram* counter(NULL); \ |
| 176 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ | 188 if (!counter) \ |
| 189 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ | |
| 177 base::Histogram::kUmaTargetedHistogramFlag); \ | 190 base::Histogram::kUmaTargetedHistogramFlag); \ |
| 178 DCHECK_EQ(name, counter->histogram_name()); \ | 191 DCHECK_EQ(name, counter->histogram_name()); \ |
| 179 if (counter.get()) counter->AddTime(sample); \ | 192 counter->AddTime(sample); \ |
| 180 } while (0) | 193 } while (0) |
| 181 | 194 |
| 182 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. | 195 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. |
| 183 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ | 196 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
| 184 scoped_refptr<base::Histogram> counter = \ | 197 static base::Histogram* counter(NULL); \ |
| 185 base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ | 198 if (!counter) \ |
| 186 base::Histogram::kUmaTargetedHistogramFlag); \ | 199 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| 200 base::Histogram::kUmaTargetedHistogramFlag); \ | |
| 187 DCHECK_EQ(name, counter->histogram_name()); \ | 201 DCHECK_EQ(name, counter->histogram_name()); \ |
| 188 if ((sample) < (max) && counter.get()) counter->AddTime(sample); \ | 202 if ((sample) < (max)) counter->AddTime(sample); \ |
| 189 } while (0) | 203 } while (0) |
| 190 | 204 |
| 191 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ | 205 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 192 name, sample, 1, 1000000, 50) | 206 name, sample, 1, 1000000, 50) |
| 193 | 207 |
| 194 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ | 208 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 195 name, sample, 1, 100, 50) | 209 name, sample, 1, 100, 50) |
| 196 | 210 |
| 197 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ | 211 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 198 name, sample, 1, 10000, 50) | 212 name, sample, 1, 10000, 50) |
| 199 | 213 |
| 200 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ | 214 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
| 201 scoped_refptr<base::Histogram> counter = \ | 215 static base::Histogram* counter(NULL); \ |
| 202 base::Histogram::FactoryGet(name, min, max, bucket_count, \ | 216 if (!counter) \ |
| 203 base::Histogram::kUmaTargetedHistogramFlag); \ | 217 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| 218 base::Histogram::kUmaTargetedHistogramFlag); \ | |
| 204 DCHECK_EQ(name, counter->histogram_name()); \ | 219 DCHECK_EQ(name, counter->histogram_name()); \ |
| 205 if (counter.get()) counter->Add(sample); \ | 220 counter->Add(sample); \ |
| 206 } while (0) | 221 } while (0) |
| 207 | 222 |
| 208 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ | 223 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 209 name, sample, 1000, 500000, 50) | 224 name, sample, 1000, 500000, 50) |
| 210 | 225 |
| 211 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ | 226 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| 212 name, sample, 1, 1000, 50) | 227 name, sample, 1, 1000, 50) |
| 213 | 228 |
| 214 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ | 229 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| 215 UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) | 230 UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
| 216 | 231 |
| 217 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ | 232 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
| 218 scoped_refptr<base::Histogram> counter = \ | 233 static base::Histogram* counter(NULL); \ |
| 219 base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ | 234 if (!counter) \ |
| 220 boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \ | 235 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| 236 boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \ | |
| 221 DCHECK_EQ(name, counter->histogram_name()); \ | 237 DCHECK_EQ(name, counter->histogram_name()); \ |
| 222 if (counter.get()) counter->Add(sample); \ | 238 counter->Add(sample); \ |
| 223 } while (0) | 239 } while (0) |
| 224 | 240 |
| 225 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ | 241 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
| 226 scoped_refptr<base::Histogram> counter = \ | 242 static base::Histogram* counter(NULL); \ |
| 227 base::CustomHistogram::FactoryGet(name, custom_ranges, \ | 243 if (!counter) \ |
| 228 base::Histogram::kUmaTargetedHistogramFlag); \ | 244 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| 245 base::Histogram::kUmaTargetedHistogramFlag); \ | |
| 229 DCHECK_EQ(name, counter->histogram_name()); \ | 246 DCHECK_EQ(name, counter->histogram_name()); \ |
| 230 if (counter.get()) counter->Add(sample); \ | 247 counter->Add(sample); \ |
| 231 } while (0) | 248 } while (0) |
| 232 | 249 |
| 233 //------------------------------------------------------------------------------ | 250 //------------------------------------------------------------------------------ |
| 234 | 251 |
| 235 class BooleanHistogram; | 252 class BooleanHistogram; |
| 236 class CustomHistogram; | 253 class CustomHistogram; |
| 237 class Histogram; | 254 class Histogram; |
| 238 class LinearHistogram; | 255 class LinearHistogram; |
| 239 | 256 |
| 240 class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> { | 257 class BASE_API Histogram { |
| 241 public: | 258 public: |
| 242 typedef int Sample; // Used for samples (and ranges of samples). | 259 typedef int Sample; // Used for samples (and ranges of samples). |
| 243 typedef int Count; // Used to count samples in a bucket. | 260 typedef int Count; // Used to count samples in a bucket. |
| 244 static const Sample kSampleType_MAX = INT_MAX; | 261 static const Sample kSampleType_MAX = INT_MAX; |
| 245 // Initialize maximum number of buckets in histograms as 16,384. | 262 // Initialize maximum number of buckets in histograms as 16,384. |
| 246 static const size_t kBucketCount_MAX; | 263 static const size_t kBucketCount_MAX; |
| 247 | 264 |
| 248 typedef std::vector<Count> Counts; | 265 typedef std::vector<Count> Counts; |
| 249 typedef std::vector<Sample> Ranges; | 266 typedef std::vector<Sample> Ranges; |
| 250 | 267 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 // that due to races in histogram accumulation (if a histogram is indeed | 357 // that due to races in histogram accumulation (if a histogram is indeed |
| 341 // updated on several threads simultaneously), the tallies might mismatch, | 358 // updated on several threads simultaneously), the tallies might mismatch, |
| 342 // and also the snapshotting code may asynchronously get a mismatch (though | 359 // and also the snapshotting code may asynchronously get a mismatch (though |
| 343 // generally either race based mismatch cause is VERY rare). | 360 // generally either race based mismatch cause is VERY rare). |
| 344 int64 redundant_count_; | 361 int64 redundant_count_; |
| 345 }; | 362 }; |
| 346 | 363 |
| 347 //---------------------------------------------------------------------------- | 364 //---------------------------------------------------------------------------- |
| 348 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit | 365 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
| 349 // default underflow bucket. | 366 // default underflow bucket. |
| 350 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 367 static Histogram* FactoryGet(const std::string& name, |
| 351 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); | 368 Sample minimum, |
| 352 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, | 369 Sample maximum, |
| 353 base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, | 370 size_t bucket_count, |
| 354 Flags flags); | 371 Flags flags); |
| 372 static Histogram* FactoryTimeGet(const std::string& name, | |
| 373 base::TimeDelta minimum, | |
| 374 base::TimeDelta maximum, | |
| 375 size_t bucket_count, | |
| 376 Flags flags); | |
| 355 | 377 |
| 356 void Add(int value); | 378 void Add(int value); |
| 357 | 379 |
| 358 // This method is an interface, used only by BooleanHistogram. | 380 // This method is an interface, used only by BooleanHistogram. |
| 359 virtual void AddBoolean(bool value); | 381 virtual void AddBoolean(bool value); |
| 360 | 382 |
| 361 // Accept a TimeDelta to increment. | 383 // Accept a TimeDelta to increment. |
| 362 void AddTime(TimeDelta time) { | 384 void AddTime(TimeDelta time) { |
| 363 Add(static_cast<int>(time.InMilliseconds())); | 385 Add(static_cast<int>(time.InMilliseconds())); |
| 364 } | 386 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 419 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, | 441 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, |
| 420 size_t bucket_count); | 442 size_t bucket_count); |
| 421 | 443 |
| 422 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, | 444 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, |
| 423 TimeDelta maximum, | 445 TimeDelta maximum, |
| 424 size_t bucket_count); | 446 size_t bucket_count); |
| 425 // Return true iff the range_checksum_ matches current ranges_ vector. | 447 // Return true iff the range_checksum_ matches current ranges_ vector. |
| 426 bool HasValidRangeChecksum() const; | 448 bool HasValidRangeChecksum() const; |
| 427 | 449 |
| 428 protected: | 450 protected: |
| 429 friend class base::RefCountedThreadSafe<Histogram>; | |
| 430 Histogram(const std::string& name, Sample minimum, | 451 Histogram(const std::string& name, Sample minimum, |
| 431 Sample maximum, size_t bucket_count); | 452 Sample maximum, size_t bucket_count); |
| 432 Histogram(const std::string& name, TimeDelta minimum, | 453 Histogram(const std::string& name, TimeDelta minimum, |
| 433 TimeDelta maximum, size_t bucket_count); | 454 TimeDelta maximum, size_t bucket_count); |
| 434 | 455 |
| 435 virtual ~Histogram(); | 456 virtual ~Histogram(); |
| 436 | 457 |
| 437 // Initialize ranges_ mapping. | 458 // Initialize ranges_ mapping. |
| 438 void InitializeBucketRange(); | 459 void InitializeBucketRange(); |
| 439 | 460 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 | 494 |
| 474 virtual uint32 CalculateRangeChecksum() const; | 495 virtual uint32 CalculateRangeChecksum() const; |
| 475 | 496 |
| 476 private: | 497 private: |
| 477 // Allow tests to corrupt our innards for testing purposes. | 498 // Allow tests to corrupt our innards for testing purposes. |
| 478 FRIEND_TEST(HistogramTest, CorruptBucketBounds); | 499 FRIEND_TEST(HistogramTest, CorruptBucketBounds); |
| 479 FRIEND_TEST(HistogramTest, CorruptSampleCounts); | 500 FRIEND_TEST(HistogramTest, CorruptSampleCounts); |
| 480 FRIEND_TEST(HistogramTest, Crc32SampleHash); | 501 FRIEND_TEST(HistogramTest, Crc32SampleHash); |
| 481 FRIEND_TEST(HistogramTest, Crc32TableTest); | 502 FRIEND_TEST(HistogramTest, Crc32TableTest); |
| 482 | 503 |
| 504 friend class StatisticsRecorder; // To allow it to delete duplicates. | |
| 505 | |
| 483 // Post constructor initialization. | 506 // Post constructor initialization. |
| 484 void Initialize(); | 507 void Initialize(); |
| 485 | 508 |
| 486 // Checksum function for accumulating range values into a checksum. | 509 // Checksum function for accumulating range values into a checksum. |
| 487 static uint32 Crc32(uint32 sum, Sample range); | 510 static uint32 Crc32(uint32 sum, Sample range); |
| 488 | 511 |
| 489 //---------------------------------------------------------------------------- | 512 //---------------------------------------------------------------------------- |
| 490 // Helpers for emitting Ascii graphic. Each method appends data to output. | 513 // Helpers for emitting Ascii graphic. Each method appends data to output. |
| 491 | 514 |
| 492 // Find out how large the (graphically) the largest bucket will appear to be. | 515 // Find out how large the (graphically) the largest bucket will appear to be. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 548 //------------------------------------------------------------------------------ | 571 //------------------------------------------------------------------------------ |
| 549 | 572 |
| 550 // LinearHistogram is a more traditional histogram, with evenly spaced | 573 // LinearHistogram is a more traditional histogram, with evenly spaced |
| 551 // buckets. | 574 // buckets. |
| 552 class BASE_API LinearHistogram : public Histogram { | 575 class BASE_API LinearHistogram : public Histogram { |
| 553 public: | 576 public: |
| 554 virtual ~LinearHistogram(); | 577 virtual ~LinearHistogram(); |
| 555 | 578 |
| 556 /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit | 579 /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit |
| 557 default underflow bucket. */ | 580 default underflow bucket. */ |
| 558 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 581 static Histogram* FactoryGet(const std::string& name, |
| 559 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); | 582 Sample minimum, |
| 560 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, | 583 Sample maximum, |
| 561 TimeDelta minimum, TimeDelta maximum, size_t bucket_count, | 584 size_t bucket_count, |
| 562 Flags flags); | 585 Flags flags); |
| 586 static Histogram* FactoryTimeGet(const std::string& name, | |
| 587 TimeDelta minimum, | |
| 588 TimeDelta maximum, | |
| 589 size_t bucket_count, | |
| 590 Flags flags); | |
| 563 | 591 |
| 564 // Overridden from Histogram: | 592 // Overridden from Histogram: |
| 565 virtual ClassType histogram_type() const; | 593 virtual ClassType histogram_type() const; |
| 566 | 594 |
| 567 // Store a list of number/text values for use in rendering the histogram. | 595 // Store a list of number/text values for use in rendering the histogram. |
| 568 // The last element in the array has a null in its "description" slot. | 596 // The last element in the array has a null in its "description" slot. |
| 569 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); | 597 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); |
| 570 | 598 |
| 571 protected: | 599 protected: |
| 572 LinearHistogram(const std::string& name, Sample minimum, | 600 LinearHistogram(const std::string& name, Sample minimum, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 595 BucketDescriptionMap bucket_description_; | 623 BucketDescriptionMap bucket_description_; |
| 596 | 624 |
| 597 DISALLOW_COPY_AND_ASSIGN(LinearHistogram); | 625 DISALLOW_COPY_AND_ASSIGN(LinearHistogram); |
| 598 }; | 626 }; |
| 599 | 627 |
| 600 //------------------------------------------------------------------------------ | 628 //------------------------------------------------------------------------------ |
| 601 | 629 |
| 602 // BooleanHistogram is a histogram for booleans. | 630 // BooleanHistogram is a histogram for booleans. |
| 603 class BASE_API BooleanHistogram : public LinearHistogram { | 631 class BASE_API BooleanHistogram : public LinearHistogram { |
| 604 public: | 632 public: |
| 605 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 633 static Histogram* FactoryGet(const std::string& name, Flags flags); |
| 606 Flags flags); | |
| 607 | 634 |
| 608 virtual ClassType histogram_type() const; | 635 virtual ClassType histogram_type() const; |
| 609 | 636 |
| 610 virtual void AddBoolean(bool value); | 637 virtual void AddBoolean(bool value); |
| 611 | 638 |
| 612 private: | 639 private: |
| 613 explicit BooleanHistogram(const std::string& name); | 640 explicit BooleanHistogram(const std::string& name); |
| 614 | 641 |
| 615 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); | 642 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); |
| 616 }; | 643 }; |
| 617 | 644 |
| 618 //------------------------------------------------------------------------------ | 645 //------------------------------------------------------------------------------ |
| 619 | 646 |
| 620 // CustomHistogram is a histogram for a set of custom integers. | 647 // CustomHistogram is a histogram for a set of custom integers. |
| 621 class BASE_API CustomHistogram : public Histogram { | 648 class BASE_API CustomHistogram : public Histogram { |
| 622 public: | 649 public: |
| 623 | 650 |
| 624 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 651 static Histogram* FactoryGet(const std::string& name, |
| 625 const std::vector<Sample>& custom_ranges, Flags flags); | 652 const std::vector<Sample>& custom_ranges, |
| 653 Flags flags); | |
| 626 | 654 |
| 627 // Overridden from Histogram: | 655 // Overridden from Histogram: |
| 628 virtual ClassType histogram_type() const; | 656 virtual ClassType histogram_type() const; |
| 629 | 657 |
| 630 protected: | 658 protected: |
| 631 CustomHistogram(const std::string& name, | 659 CustomHistogram(const std::string& name, |
| 632 const std::vector<Sample>& custom_ranges); | 660 const std::vector<Sample>& custom_ranges); |
| 633 | 661 |
| 634 // Initialize ranges_ mapping. | 662 // Initialize ranges_ mapping. |
| 635 void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges); | 663 void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges); |
| 636 virtual double GetBucketSize(Count current, size_t i) const; | 664 virtual double GetBucketSize(Count current, size_t i) const; |
| 637 | 665 |
| 638 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); | 666 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
| 639 }; | 667 }; |
| 640 | 668 |
| 641 //------------------------------------------------------------------------------ | 669 //------------------------------------------------------------------------------ |
| 642 // StatisticsRecorder handles all histograms in the system. It provides a | 670 // StatisticsRecorder handles all histograms in the system. It provides a |
| 643 // general place for histograms to register, and supports a global API for | 671 // general place for histograms to register, and supports a global API for |
| 644 // accessing (i.e., dumping, or graphing) the data in all the histograms. | 672 // accessing (i.e., dumping, or graphing) the data in all the histograms. |
| 645 | 673 |
| 646 class BASE_API StatisticsRecorder { | 674 class BASE_API StatisticsRecorder { |
| 647 public: | 675 public: |
| 648 typedef std::vector<scoped_refptr<Histogram> > Histograms; | 676 typedef std::vector<Histogram*> Histograms; |
| 649 | 677 |
| 650 StatisticsRecorder(); | 678 StatisticsRecorder(); |
| 651 | 679 |
| 652 ~StatisticsRecorder(); | 680 ~StatisticsRecorder(); |
| 653 | 681 |
| 654 // Find out if histograms can now be registered into our list. | 682 // Find out if histograms can now be registered into our list. |
| 655 static bool IsActive(); | 683 static bool IsActive(); |
| 656 | 684 |
| 657 // Register, or add a new histogram to the collection of statistics. If an | 685 // Register, or add a new histogram to the collection of statistics. If an |
| 658 // identically named histogram is already registered, then the argument | 686 // identically named histogram is already registered, then the argument |
| 659 // |histogram| will be replaced by the previously registered value, discarding | 687 // |histogram| will deleted. The returns value is always the registered |
|
rvargas (doing something else)
2011/04/01 19:20:52
nit: the returned value
jar (doing other things)
2011/04/01 21:50:27
Done.
| |
| 660 // the referenced argument. | 688 // histogram (either the argument, or the pre-existing registered histogram). |
| 661 static void RegisterOrDiscardDuplicate(scoped_refptr<Histogram>* histogram); | 689 static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram); |
| 662 | 690 |
| 663 // Methods for printing histograms. Only histograms which have query as | 691 // Methods for printing histograms. Only histograms which have query as |
| 664 // a substring are written to output (an empty string will process all | 692 // a substring are written to output (an empty string will process all |
| 665 // registered histograms). | 693 // registered histograms). |
| 666 static void WriteHTMLGraph(const std::string& query, std::string* output); | 694 static void WriteHTMLGraph(const std::string& query, std::string* output); |
| 667 static void WriteGraph(const std::string& query, std::string* output); | 695 static void WriteGraph(const std::string& query, std::string* output); |
| 668 | 696 |
| 669 // Method for extracting histograms which were marked for use by UMA. | 697 // Method for extracting histograms which were marked for use by UMA. |
| 670 static void GetHistograms(Histograms* output); | 698 static void GetHistograms(Histograms* output); |
| 671 | 699 |
| 672 // Find a histogram by name. It matches the exact name. This method is thread | 700 // Find a histogram by name. It matches the exact name. This method is thread |
| 673 // safe. If a matching histogram is not found, then the |histogram| is | 701 // safe. If a matching histogram is not found, then the |histogram| is |
| 674 // not changed. | 702 // not changed. |
| 675 static bool FindHistogram(const std::string& query, | 703 static bool FindHistogram(const std::string& query, Histogram** histogram); |
| 676 scoped_refptr<Histogram>* histogram); | |
| 677 | 704 |
| 678 static bool dump_on_exit() { return dump_on_exit_; } | 705 static bool dump_on_exit() { return dump_on_exit_; } |
| 679 | 706 |
| 680 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } | 707 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } |
| 681 | 708 |
| 682 // GetSnapshot copies some of the pointers to registered histograms into the | 709 // GetSnapshot copies some of the pointers to registered histograms into the |
| 683 // caller supplied vector (Histograms). Only histograms with names matching | 710 // caller supplied vector (Histograms). Only histograms with names matching |
| 684 // query are returned. The query must be a substring of histogram name for its | 711 // query are returned. The query must be a substring of histogram name for its |
| 685 // pointer to be copied. | 712 // pointer to be copied. |
| 686 static void GetSnapshot(const std::string& query, Histograms* snapshot); | 713 static void GetSnapshot(const std::string& query, Histograms* snapshot); |
| 687 | 714 |
| 688 | 715 |
| 689 private: | 716 private: |
| 690 // We keep all registered histograms in a map, from name to histogram. | 717 // We keep all registered histograms in a map, from name to histogram. |
| 691 typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap; | 718 typedef std::map<std::string, Histogram*> HistogramMap; |
| 692 | 719 |
| 693 static HistogramMap* histograms_; | 720 static HistogramMap* histograms_; |
| 694 | 721 |
| 695 // lock protects access to the above map. | 722 // lock protects access to the above map. |
| 696 static base::Lock* lock_; | 723 static base::Lock* lock_; |
| 697 | 724 |
| 698 // Dump all known histograms to log. | 725 // Dump all known histograms to log. |
| 699 static bool dump_on_exit_; | 726 static bool dump_on_exit_; |
| 700 | 727 |
| 701 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); | 728 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
| 702 }; | 729 }; |
| 703 | 730 |
| 704 } // namespace base | 731 } // namespace base |
| 705 | 732 |
| 706 #endif // BASE_METRICS_HISTOGRAM_H_ | 733 #endif // BASE_METRICS_HISTOGRAM_H_ |
| OLD | NEW |