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