OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 18 matching lines...) Expand all Loading... |
29 // gigantic range with the addition of very few buckets. | 29 // gigantic range with the addition of very few buckets. |
30 | 30 |
31 #ifndef BASE_METRICS_HISTOGRAM_H_ | 31 #ifndef BASE_METRICS_HISTOGRAM_H_ |
32 #define BASE_METRICS_HISTOGRAM_H_ | 32 #define BASE_METRICS_HISTOGRAM_H_ |
33 #pragma once | 33 #pragma once |
34 | 34 |
35 #include <map> | 35 #include <map> |
36 #include <string> | 36 #include <string> |
37 #include <vector> | 37 #include <vector> |
38 | 38 |
| 39 #include "base/gtest_prod_util.h" |
39 #include "base/ref_counted.h" | 40 #include "base/ref_counted.h" |
40 #include "base/logging.h" | 41 #include "base/logging.h" |
41 #include "base/time.h" | 42 #include "base/time.h" |
42 | 43 |
43 class Lock; | 44 class Lock; |
44 class Pickle; | 45 class Pickle; |
45 | 46 |
46 namespace base { | 47 namespace base { |
47 | 48 |
48 //------------------------------------------------------------------------------ | 49 //------------------------------------------------------------------------------ |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 | 237 |
237 class Histogram : public base::RefCountedThreadSafe<Histogram> { | 238 class Histogram : public base::RefCountedThreadSafe<Histogram> { |
238 public: | 239 public: |
239 typedef int Sample; // Used for samples (and ranges of samples). | 240 typedef int Sample; // Used for samples (and ranges of samples). |
240 typedef int Count; // Used to count samples in a bucket. | 241 typedef int Count; // Used to count samples in a bucket. |
241 static const Sample kSampleType_MAX = INT_MAX; | 242 static const Sample kSampleType_MAX = INT_MAX; |
242 | 243 |
243 typedef std::vector<Count> Counts; | 244 typedef std::vector<Count> Counts; |
244 typedef std::vector<Sample> Ranges; | 245 typedef std::vector<Sample> Ranges; |
245 | 246 |
246 /* These enums are meant to facilitate deserialization of renderer histograms | 247 // These enums are used to facilitate deserialization of renderer histograms |
247 into the browser. */ | 248 // into the browser. |
248 enum ClassType { | 249 enum ClassType { |
249 HISTOGRAM, | 250 HISTOGRAM, |
250 LINEAR_HISTOGRAM, | 251 LINEAR_HISTOGRAM, |
251 BOOLEAN_HISTOGRAM, | 252 BOOLEAN_HISTOGRAM, |
252 CUSTOM_HISTOGRAM, | 253 CUSTOM_HISTOGRAM, |
253 NOT_VALID_IN_RENDERER | 254 NOT_VALID_IN_RENDERER |
254 }; | 255 }; |
255 | 256 |
256 enum BucketLayout { | 257 enum BucketLayout { |
257 EXPONENTIAL, | 258 EXPONENTIAL, |
258 LINEAR, | 259 LINEAR, |
259 CUSTOM | 260 CUSTOM |
260 }; | 261 }; |
261 | 262 |
262 enum Flags { | 263 enum Flags { |
263 kNoFlags = 0, | 264 kNoFlags = 0, |
264 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. | 265 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. |
265 | 266 |
266 // Indicate that the histogram was pickled to be sent across an IPC Channel. | 267 // Indicate that the histogram was pickled to be sent across an IPC Channel. |
267 // If we observe this flag on a histogram being aggregated into after IPC, | 268 // If we observe this flag on a histogram being aggregated into after IPC, |
268 // then we are running in a single process mode, and the aggregation should | 269 // then we are running in a single process mode, and the aggregation should |
269 // not take place (as we would be aggregating back into the source | 270 // not take place (as we would be aggregating back into the source |
270 // histogram!). | 271 // histogram!). |
271 kIPCSerializationSourceFlag = 0x10, | 272 kIPCSerializationSourceFlag = 0x10, |
272 | 273 |
273 kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported. | 274 kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported. |
274 }; | 275 }; |
275 | 276 |
| 277 enum Inconsistencies { |
| 278 NO_INCONSISTENCIES = 0x0, |
| 279 RANGE_CHECKSUM_ERROR = 0x1, |
| 280 BUCKET_ORDER_ERROR = 0x2, |
| 281 COUNT_HIGH_ERROR = 0x4, |
| 282 COUNT_LOW_ERROR = 0x8, |
| 283 |
| 284 NEVER_EXCEEDED_VALUE = 0x10 |
| 285 }; |
| 286 |
276 struct DescriptionPair { | 287 struct DescriptionPair { |
277 Sample sample; | 288 Sample sample; |
278 const char* description; // Null means end of a list of pairs. | 289 const char* description; // Null means end of a list of pairs. |
279 }; | 290 }; |
280 | 291 |
281 //---------------------------------------------------------------------------- | 292 //---------------------------------------------------------------------------- |
282 // Statistic values, developed over the life of the histogram. | 293 // Statistic values, developed over the life of the histogram. |
283 | 294 |
284 class SampleSet { | 295 class SampleSet { |
285 public: | 296 public: |
286 explicit SampleSet(); | 297 explicit SampleSet(); |
287 ~SampleSet(); | 298 ~SampleSet(); |
288 | 299 |
289 // Adjust size of counts_ for use with given histogram. | 300 // Adjust size of counts_ for use with given histogram. |
290 void Resize(const Histogram& histogram); | 301 void Resize(const Histogram& histogram); |
291 void CheckSize(const Histogram& histogram) const; | 302 void CheckSize(const Histogram& histogram) const; |
292 | 303 |
293 // Accessor for histogram to make routine additions. | 304 // Accessor for histogram to make routine additions. |
294 void Accumulate(Sample value, Count count, size_t index); | 305 void Accumulate(Sample value, Count count, size_t index); |
295 | 306 |
296 // Accessor methods. | 307 // Accessor methods. |
297 Count counts(size_t i) const { return counts_[i]; } | 308 Count counts(size_t i) const { return counts_[i]; } |
298 Count TotalCount() const; | 309 Count TotalCount() const; |
299 int64 sum() const { return sum_; } | 310 int64 sum() const { return sum_; } |
300 int64 square_sum() const { return square_sum_; } | 311 int64 square_sum() const { return square_sum_; } |
| 312 int64 redundant_count() const { return redundant_count_; } |
301 | 313 |
302 // Arithmetic manipulation of corresponding elements of the set. | 314 // Arithmetic manipulation of corresponding elements of the set. |
303 void Add(const SampleSet& other); | 315 void Add(const SampleSet& other); |
304 void Subtract(const SampleSet& other); | 316 void Subtract(const SampleSet& other); |
305 | 317 |
306 bool Serialize(Pickle* pickle) const; | 318 bool Serialize(Pickle* pickle) const; |
307 bool Deserialize(void** iter, const Pickle& pickle); | 319 bool Deserialize(void** iter, const Pickle& pickle); |
308 | 320 |
309 protected: | 321 protected: |
310 // Actual histogram data is stored in buckets, showing the count of values | 322 // Actual histogram data is stored in buckets, showing the count of values |
311 // that fit into each bucket. | 323 // that fit into each bucket. |
312 Counts counts_; | 324 Counts counts_; |
313 | 325 |
314 // Save simple stats locally. Note that this MIGHT get done in base class | 326 // Save simple stats locally. Note that this MIGHT get done in base class |
315 // without shared memory at some point. | 327 // without shared memory at some point. |
316 int64 sum_; // sum of samples. | 328 int64 sum_; // sum of samples. |
317 int64 square_sum_; // sum of squares of samples. | 329 int64 square_sum_; // sum of squares of samples. |
| 330 |
| 331 private: |
| 332 // Allow tests to corrupt our innards for testing purposes. |
| 333 FRIEND_TEST(HistogramTest, CorruptSampleCounts); |
| 334 |
| 335 // To help identify memory corruption, we reduntantly save the number of |
| 336 // samples we've accumulated into all of our buckets. We can compare this |
| 337 // count to the sum of the counts in all buckets, and detect problems. Note |
| 338 // that due to races in histogram accumulation (if a histogram is indeed |
| 339 // updated on several threads simultaneously), the tallies might mismatch, |
| 340 // and also the snapshotting code may asynchronously get a mismatch (though |
| 341 // generally either race based mismatch cause is VERY rare). |
| 342 int64 redundant_count_; |
318 }; | 343 }; |
| 344 |
319 //---------------------------------------------------------------------------- | 345 //---------------------------------------------------------------------------- |
320 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit | 346 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
321 // default underflow bucket. | 347 // default underflow bucket. |
322 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 348 static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
323 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); | 349 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); |
324 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, | 350 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, |
325 base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, | 351 base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, |
326 Flags flags); | 352 Flags flags); |
327 | 353 |
328 void Add(int value); | 354 void Add(int value); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 | 386 |
361 // Serialize the given snapshot of a Histogram into a String. Uses | 387 // Serialize the given snapshot of a Histogram into a String. Uses |
362 // Pickle class to flatten the object. | 388 // Pickle class to flatten the object. |
363 static std::string SerializeHistogramInfo(const Histogram& histogram, | 389 static std::string SerializeHistogramInfo(const Histogram& histogram, |
364 const SampleSet& snapshot); | 390 const SampleSet& snapshot); |
365 // The following method accepts a list of pickled histograms and | 391 // The following method accepts a list of pickled histograms and |
366 // builds a histogram and updates shadow copy of histogram data in the | 392 // builds a histogram and updates shadow copy of histogram data in the |
367 // browser process. | 393 // browser process. |
368 static bool DeserializeHistogramInfo(const std::string& histogram_info); | 394 static bool DeserializeHistogramInfo(const std::string& histogram_info); |
369 | 395 |
| 396 // Check to see if bucket ranges, counts and tallies in the snapshot are |
| 397 // consistent with the bucket ranges and checksums in our histogram. This can |
| 398 // produce a false-alarm if a race occurred in the reading of the data during |
| 399 // a SnapShot process, but should otherwise be false at all times (unless we |
| 400 // have memory over-writes, or DRAM failures). |
| 401 Inconsistencies FindCorruption(const SampleSet& snapshot) const; |
| 402 |
370 //---------------------------------------------------------------------------- | 403 //---------------------------------------------------------------------------- |
371 // Accessors for factory constuction, serialization and testing. | 404 // Accessors for factory constuction, serialization and testing. |
372 //---------------------------------------------------------------------------- | 405 //---------------------------------------------------------------------------- |
373 virtual ClassType histogram_type() const { return HISTOGRAM; } | 406 virtual ClassType histogram_type() const { return HISTOGRAM; } |
374 const std::string& histogram_name() const { return histogram_name_; } | 407 const std::string& histogram_name() const { return histogram_name_; } |
375 Sample declared_min() const { return declared_min_; } | 408 Sample declared_min() const { return declared_min_; } |
376 Sample declared_max() const { return declared_max_; } | 409 Sample declared_max() const { return declared_max_; } |
377 virtual Sample ranges(size_t i) const { return ranges_[i];} | 410 virtual Sample ranges(size_t i) const { return ranges_[i];} |
| 411 Sample range_checksum() const { return range_checksum_; } |
378 virtual size_t bucket_count() const { return bucket_count_; } | 412 virtual size_t bucket_count() const { return bucket_count_; } |
379 // Snapshot the current complete set of sample data. | 413 // Snapshot the current complete set of sample data. |
380 // Override with atomic/locked snapshot if needed. | 414 // Override with atomic/locked snapshot if needed. |
381 virtual void SnapshotSample(SampleSet* sample) const; | 415 virtual void SnapshotSample(SampleSet* sample) const; |
382 | 416 |
383 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, | 417 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, |
384 size_t bucket_count); | 418 size_t bucket_count); |
385 | 419 |
386 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, | 420 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, |
387 TimeDelta maximum, | 421 TimeDelta maximum, |
(...skipping 14 matching lines...) Expand all Loading... |
402 //---------------------------------------------------------------------------- | 436 //---------------------------------------------------------------------------- |
403 // Methods to override to create histogram with different bucket widths. | 437 // Methods to override to create histogram with different bucket widths. |
404 //---------------------------------------------------------------------------- | 438 //---------------------------------------------------------------------------- |
405 // Initialize ranges_ mapping. | 439 // Initialize ranges_ mapping. |
406 virtual void InitializeBucketRange(); | 440 virtual void InitializeBucketRange(); |
407 // Find bucket to increment for sample value. | 441 // Find bucket to increment for sample value. |
408 virtual size_t BucketIndex(Sample value) const; | 442 virtual size_t BucketIndex(Sample value) const; |
409 // Get normalized size, relative to the ranges_[i]. | 443 // Get normalized size, relative to the ranges_[i]. |
410 virtual double GetBucketSize(Count current, size_t i) const; | 444 virtual double GetBucketSize(Count current, size_t i) const; |
411 | 445 |
| 446 // Recalculate range_checksum_. |
| 447 void ResetRangeChecksum(); |
| 448 |
412 // Return a string description of what goes in a given bucket. | 449 // Return a string description of what goes in a given bucket. |
413 // Most commonly this is the numeric value, but in derived classes it may | 450 // Most commonly this is the numeric value, but in derived classes it may |
414 // be a name (or string description) given to the bucket. | 451 // be a name (or string description) given to the bucket. |
415 virtual const std::string GetAsciiBucketRange(size_t it) const; | 452 virtual const std::string GetAsciiBucketRange(size_t it) const; |
416 | 453 |
417 //---------------------------------------------------------------------------- | 454 //---------------------------------------------------------------------------- |
418 // Methods to override to create thread safe histogram. | 455 // Methods to override to create thread safe histogram. |
419 //---------------------------------------------------------------------------- | 456 //---------------------------------------------------------------------------- |
420 // Update all our internal data, including histogram | 457 // Update all our internal data, including histogram |
421 virtual void Accumulate(Sample value, Count count, size_t index); | 458 virtual void Accumulate(Sample value, Count count, size_t index); |
422 | 459 |
423 //---------------------------------------------------------------------------- | 460 //---------------------------------------------------------------------------- |
424 // Accessors for derived classes. | 461 // Accessors for derived classes. |
425 //---------------------------------------------------------------------------- | 462 //---------------------------------------------------------------------------- |
426 void SetBucketRange(size_t i, Sample value); | 463 void SetBucketRange(size_t i, Sample value); |
427 | 464 |
428 // Validate that ranges_ was created sensibly (top and bottom range | 465 // Validate that ranges_ was created sensibly (top and bottom range |
429 // values relate properly to the declared_min_ and declared_max_).. | 466 // values relate properly to the declared_min_ and declared_max_).. |
430 bool ValidateBucketRanges() const; | 467 bool ValidateBucketRanges() const; |
431 | 468 |
432 private: | 469 private: |
| 470 // Allow tests to corrupt our innards for testing purposes. |
| 471 FRIEND_TEST(HistogramTest, CorruptBucketBounds); |
| 472 FRIEND_TEST(HistogramTest, CorruptSampleCounts); |
| 473 |
433 // Post constructor initialization. | 474 // Post constructor initialization. |
434 void Initialize(); | 475 void Initialize(); |
435 | 476 |
| 477 // Return true iff the range_checksum_ matches current ranges_ vector. |
| 478 bool HasValidRangeChecksum() const; |
| 479 |
| 480 Sample CalculateRangeChecksum() const; |
| 481 |
436 //---------------------------------------------------------------------------- | 482 //---------------------------------------------------------------------------- |
437 // Helpers for emitting Ascii graphic. Each method appends data to output. | 483 // Helpers for emitting Ascii graphic. Each method appends data to output. |
438 | 484 |
439 // Find out how large the (graphically) the largest bucket will appear to be. | 485 // Find out how large the (graphically) the largest bucket will appear to be. |
440 double GetPeakBucketSize(const SampleSet& snapshot) const; | 486 double GetPeakBucketSize(const SampleSet& snapshot) const; |
441 | 487 |
442 // Write a common header message describing this histogram. | 488 // Write a common header message describing this histogram. |
443 void WriteAsciiHeader(const SampleSet& snapshot, | 489 void WriteAsciiHeader(const SampleSet& snapshot, |
444 Count sample_count, std::string* output) const; | 490 Count sample_count, std::string* output) const; |
445 | 491 |
(...skipping 24 matching lines...) Expand all Loading... |
470 | 516 |
471 // Flag the histogram for recording by UMA via metric_services.h. | 517 // Flag the histogram for recording by UMA via metric_services.h. |
472 Flags flags_; | 518 Flags flags_; |
473 | 519 |
474 // For each index, show the least value that can be stored in the | 520 // For each index, show the least value that can be stored in the |
475 // corresponding bucket. We also append one extra element in this array, | 521 // corresponding bucket. We also append one extra element in this array, |
476 // containing kSampleType_MAX, to make calculations easy. | 522 // containing kSampleType_MAX, to make calculations easy. |
477 // The dimension of ranges_ is bucket_count + 1. | 523 // The dimension of ranges_ is bucket_count + 1. |
478 Ranges ranges_; | 524 Ranges ranges_; |
479 | 525 |
| 526 // For redundancy, we store the sum of all the sample ranges when ranges are |
| 527 // generated. If ever there is ever a difference, then the histogram must |
| 528 // have been corrupted. |
| 529 Sample range_checksum_; |
| 530 |
480 // Finally, provide the state that changes with the addition of each new | 531 // Finally, provide the state that changes with the addition of each new |
481 // sample. | 532 // sample. |
482 SampleSet sample_; | 533 SampleSet sample_; |
483 | 534 |
484 DISALLOW_COPY_AND_ASSIGN(Histogram); | 535 DISALLOW_COPY_AND_ASSIGN(Histogram); |
485 }; | 536 }; |
486 | 537 |
487 //------------------------------------------------------------------------------ | 538 //------------------------------------------------------------------------------ |
488 | 539 |
489 // LinearHistogram is a more traditional histogram, with evenly spaced | 540 // LinearHistogram is a more traditional histogram, with evenly spaced |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 }; | 605 }; |
555 | 606 |
556 //------------------------------------------------------------------------------ | 607 //------------------------------------------------------------------------------ |
557 | 608 |
558 // CustomHistogram is a histogram for a set of custom integers. | 609 // CustomHistogram is a histogram for a set of custom integers. |
559 class CustomHistogram : public Histogram { | 610 class CustomHistogram : public Histogram { |
560 public: | 611 public: |
561 virtual ClassType histogram_type() const; | 612 virtual ClassType histogram_type() const; |
562 | 613 |
563 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 614 static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
564 const std::vector<int>& custom_ranges, Flags flags); | 615 const std::vector<Sample>& custom_ranges, Flags flags); |
565 | 616 |
566 protected: | 617 protected: |
567 CustomHistogram(const std::string& name, | 618 CustomHistogram(const std::string& name, |
568 const std::vector<int>& custom_ranges); | 619 const std::vector<Sample>& custom_ranges); |
569 | 620 |
570 // Initialize ranges_ mapping. | 621 // Initialize ranges_ mapping. |
571 virtual void InitializeBucketRange(); | 622 virtual void InitializeBucketRange(); |
572 virtual double GetBucketSize(Count current, size_t i) const; | 623 virtual double GetBucketSize(Count current, size_t i) const; |
573 | 624 |
574 private: | 625 private: |
575 // Temporary pointer used during construction/initialization, and then NULLed. | 626 // Temporary pointer used during construction/initialization, and then NULLed. |
576 const std::vector<int>* ranges_vector_; | 627 const std::vector<Sample>* ranges_vector_; |
577 | 628 |
578 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); | 629 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
579 }; | 630 }; |
580 | 631 |
581 //------------------------------------------------------------------------------ | 632 //------------------------------------------------------------------------------ |
582 // StatisticsRecorder handles all histograms in the system. It provides a | 633 // StatisticsRecorder handles all histograms in the system. It provides a |
583 // general place for histograms to register, and supports a global API for | 634 // general place for histograms to register, and supports a global API for |
584 // accessing (i.e., dumping, or graphing) the data in all the histograms. | 635 // accessing (i.e., dumping, or graphing) the data in all the histograms. |
585 | 636 |
586 class StatisticsRecorder { | 637 class StatisticsRecorder { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 | 685 |
635 // Dump all known histograms to log. | 686 // Dump all known histograms to log. |
636 static bool dump_on_exit_; | 687 static bool dump_on_exit_; |
637 | 688 |
638 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); | 689 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
639 }; | 690 }; |
640 | 691 |
641 } // namespace base | 692 } // namespace base |
642 | 693 |
643 #endif // BASE_METRICS_HISTOGRAM_H_ | 694 #endif // BASE_METRICS_HISTOGRAM_H_ |
OLD | NEW |