ipc/chromium/src/base/histogram.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial