| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // See header file for details and examples. | 8 // See header file for details and examples. |
| 9 | 9 |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 } | 77 } |
| 78 | 78 |
| 79 } // namespace | 79 } // namespace |
| 80 | 80 |
| 81 typedef HistogramBase::Count Count; | 81 typedef HistogramBase::Count Count; |
| 82 typedef HistogramBase::Sample Sample; | 82 typedef HistogramBase::Sample Sample; |
| 83 | 83 |
| 84 // static | 84 // static |
| 85 const size_t Histogram::kBucketCount_MAX = 16384u; | 85 const size_t Histogram::kBucketCount_MAX = 16384u; |
| 86 | 86 |
| 87 // TODO(rtenneti): delete this code after debugging. | |
| 88 void CheckCorruption(const Histogram& histogram, bool new_histogram) { | |
| 89 const std::string& histogram_name = histogram.histogram_name(); | |
| 90 char histogram_name_buf[128]; | |
| 91 base::strlcpy(histogram_name_buf, | |
| 92 histogram_name.c_str(), | |
| 93 arraysize(histogram_name_buf)); | |
| 94 base::debug::Alias(histogram_name_buf); | |
| 95 | |
| 96 bool debug_new_histogram[1]; | |
| 97 debug_new_histogram[0] = new_histogram; | |
| 98 base::debug::Alias(debug_new_histogram); | |
| 99 | |
| 100 Sample previous_range = -1; // Bottom range is always 0. | |
| 101 for (size_t index = 0; index < histogram.bucket_count(); ++index) { | |
| 102 int new_range = histogram.ranges(index); | |
| 103 CHECK_LT(previous_range, new_range); | |
| 104 previous_range = new_range; | |
| 105 } | |
| 106 | |
| 107 CHECK(histogram.bucket_ranges()->HasValidChecksum()); | |
| 108 } | |
| 109 | |
| 110 HistogramBase* Histogram::FactoryGet(const string& name, | 87 HistogramBase* Histogram::FactoryGet(const string& name, |
| 111 Sample minimum, | 88 Sample minimum, |
| 112 Sample maximum, | 89 Sample maximum, |
| 113 size_t bucket_count, | 90 size_t bucket_count, |
| 114 int32 flags) { | 91 int32 flags) { |
| 115 bool valid_arguments = | 92 bool valid_arguments = |
| 116 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
| 117 DCHECK(valid_arguments); | 94 DCHECK(valid_arguments); |
| 118 | 95 |
| 119 Histogram* histogram = StatisticsRecorder::FindHistogram(name); | 96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 120 if (!histogram) { | 97 if (!histogram) { |
| 121 // To avoid racy destruction at shutdown, the following will be leaked. | 98 // To avoid racy destruction at shutdown, the following will be leaked. |
| 122 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 99 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
| 123 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); | 100 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); |
| 124 const BucketRanges* registered_ranges = | 101 const BucketRanges* registered_ranges = |
| 125 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 102 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 126 | 103 |
| 127 Histogram* tentative_histogram = | 104 Histogram* tentative_histogram = |
| 128 new Histogram(name, minimum, maximum, bucket_count, registered_ranges); | 105 new Histogram(name, minimum, maximum, bucket_count, registered_ranges); |
| 129 CheckCorruption(*tentative_histogram, true); | |
| 130 | 106 |
| 131 tentative_histogram->SetFlags(flags); | 107 tentative_histogram->SetFlags(flags); |
| 132 histogram = | 108 histogram = |
| 133 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 109 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 134 } | 110 } |
| 135 // TODO(rtenneti): delete this code after debugging. | |
| 136 CheckCorruption(*histogram, false); | |
| 137 | 111 |
| 138 CHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | 112 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); |
| 139 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); | 113 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); |
| 140 return histogram; | 114 return histogram; |
| 141 } | 115 } |
| 142 | 116 |
| 143 HistogramBase* Histogram::FactoryTimeGet(const string& name, | 117 HistogramBase* Histogram::FactoryTimeGet(const string& name, |
| 144 TimeDelta minimum, | 118 TimeDelta minimum, |
| 145 TimeDelta maximum, | 119 TimeDelta maximum, |
| 146 size_t bucket_count, | 120 size_t bucket_count, |
| 147 int32 flags) { | 121 int32 flags) { |
| 148 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), | 122 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 ++current; // Just do a narrow bucket, and keep trying. | 167 ++current; // Just do a narrow bucket, and keep trying. |
| 194 ranges->set_range(bucket_index, current); | 168 ranges->set_range(bucket_index, current); |
| 195 } | 169 } |
| 196 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); | 170 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); |
| 197 ranges->ResetChecksum(); | 171 ranges->ResetChecksum(); |
| 198 } | 172 } |
| 199 | 173 |
| 200 // static | 174 // static |
| 201 const int Histogram::kCommonRaceBasedCountMismatch = 5; | 175 const int Histogram::kCommonRaceBasedCountMismatch = 5; |
| 202 | 176 |
| 203 Histogram::Inconsistencies Histogram::FindCorruption( | 177 int Histogram::FindCorruption(const HistogramSamples& samples) const { |
| 204 const HistogramSamples& samples) const { | |
| 205 int inconsistencies = NO_INCONSISTENCIES; | 178 int inconsistencies = NO_INCONSISTENCIES; |
| 206 Sample previous_range = -1; // Bottom range is always 0. | 179 Sample previous_range = -1; // Bottom range is always 0. |
| 207 for (size_t index = 0; index < bucket_count(); ++index) { | 180 for (size_t index = 0; index < bucket_count(); ++index) { |
| 208 int new_range = ranges(index); | 181 int new_range = ranges(index); |
| 209 if (previous_range >= new_range) | 182 if (previous_range >= new_range) |
| 210 inconsistencies |= BUCKET_ORDER_ERROR; | 183 inconsistencies |= BUCKET_ORDER_ERROR; |
| 211 previous_range = new_range; | 184 previous_range = new_range; |
| 212 } | 185 } |
| 213 | 186 |
| 214 if (!bucket_ranges()->HasValidChecksum()) | 187 if (!bucket_ranges()->HasValidChecksum()) |
| 215 inconsistencies |= RANGE_CHECKSUM_ERROR; | 188 inconsistencies |= RANGE_CHECKSUM_ERROR; |
| 216 | 189 |
| 217 int64 delta64 = samples.redundant_count() - samples.TotalCount(); | 190 int64 delta64 = samples.redundant_count() - samples.TotalCount(); |
| 218 if (delta64 != 0) { | 191 if (delta64 != 0) { |
| 219 int delta = static_cast<int>(delta64); | 192 int delta = static_cast<int>(delta64); |
| 220 if (delta != delta64) | 193 if (delta != delta64) |
| 221 delta = INT_MAX; // Flag all giant errors as INT_MAX. | 194 delta = INT_MAX; // Flag all giant errors as INT_MAX. |
| 222 if (delta > 0) { | 195 if (delta > 0) { |
| 223 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); | 196 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); |
| 224 if (delta > kCommonRaceBasedCountMismatch) | 197 if (delta > kCommonRaceBasedCountMismatch) |
| 225 inconsistencies |= COUNT_HIGH_ERROR; | 198 inconsistencies |= COUNT_HIGH_ERROR; |
| 226 } else { | 199 } else { |
| 227 DCHECK_GT(0, delta); | 200 DCHECK_GT(0, delta); |
| 228 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); | 201 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); |
| 229 if (-delta > kCommonRaceBasedCountMismatch) | 202 if (-delta > kCommonRaceBasedCountMismatch) |
| 230 inconsistencies |= COUNT_LOW_ERROR; | 203 inconsistencies |= COUNT_LOW_ERROR; |
| 231 } | 204 } |
| 232 } | 205 } |
| 233 return static_cast<Inconsistencies>(inconsistencies); | 206 return inconsistencies; |
| 234 } | 207 } |
| 235 | 208 |
| 236 Sample Histogram::ranges(size_t i) const { | 209 Sample Histogram::ranges(size_t i) const { |
| 237 return bucket_ranges_->range(i); | 210 return bucket_ranges_->range(i); |
| 238 } | 211 } |
| 239 | 212 |
| 240 size_t Histogram::bucket_count() const { | 213 size_t Histogram::bucket_count() const { |
| 241 return bucket_count_; | 214 return bucket_count_; |
| 242 } | 215 } |
| 243 | 216 |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 const std::string& name, | 565 const std::string& name, |
| 593 Sample minimum, | 566 Sample minimum, |
| 594 Sample maximum, | 567 Sample maximum, |
| 595 size_t bucket_count, | 568 size_t bucket_count, |
| 596 int32 flags, | 569 int32 flags, |
| 597 const DescriptionPair descriptions[]) { | 570 const DescriptionPair descriptions[]) { |
| 598 bool valid_arguments = Histogram::InspectConstructionArguments( | 571 bool valid_arguments = Histogram::InspectConstructionArguments( |
| 599 name, &minimum, &maximum, &bucket_count); | 572 name, &minimum, &maximum, &bucket_count); |
| 600 DCHECK(valid_arguments); | 573 DCHECK(valid_arguments); |
| 601 | 574 |
| 602 Histogram* histogram = StatisticsRecorder::FindHistogram(name); | 575 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 603 if (!histogram) { | 576 if (!histogram) { |
| 604 // To avoid racy destruction at shutdown, the following will be leaked. | 577 // To avoid racy destruction at shutdown, the following will be leaked. |
| 605 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 578 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
| 606 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); | 579 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); |
| 607 const BucketRanges* registered_ranges = | 580 const BucketRanges* registered_ranges = |
| 608 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 581 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 609 | 582 |
| 610 LinearHistogram* tentative_histogram = | 583 LinearHistogram* tentative_histogram = |
| 611 new LinearHistogram(name, minimum, maximum, bucket_count, | 584 new LinearHistogram(name, minimum, maximum, bucket_count, |
| 612 registered_ranges); | 585 registered_ranges); |
| 613 CheckCorruption(*tentative_histogram, true); | |
| 614 | 586 |
| 615 // Set range descriptions. | 587 // Set range descriptions. |
| 616 if (descriptions) { | 588 if (descriptions) { |
| 617 for (int i = 0; descriptions[i].description; ++i) { | 589 for (int i = 0; descriptions[i].description; ++i) { |
| 618 tentative_histogram->bucket_description_[descriptions[i].sample] = | 590 tentative_histogram->bucket_description_[descriptions[i].sample] = |
| 619 descriptions[i].description; | 591 descriptions[i].description; |
| 620 } | 592 } |
| 621 } | 593 } |
| 622 | 594 |
| 623 tentative_histogram->SetFlags(flags); | 595 tentative_histogram->SetFlags(flags); |
| 624 histogram = | 596 histogram = |
| 625 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 597 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 626 } | 598 } |
| 627 // TODO(rtenneti): delete this code after debugging. | |
| 628 CheckCorruption(*histogram, false); | |
| 629 | 599 |
| 630 CHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | 600 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); |
| 631 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); | 601 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); |
| 632 return histogram; | 602 return histogram; |
| 633 } | 603 } |
| 634 | 604 |
| 635 HistogramType LinearHistogram::GetHistogramType() const { | 605 HistogramType LinearHistogram::GetHistogramType() const { |
| 636 return LINEAR_HISTOGRAM; | 606 return LINEAR_HISTOGRAM; |
| 637 } | 607 } |
| 638 | 608 |
| 639 LinearHistogram::LinearHistogram(const string& name, | 609 LinearHistogram::LinearHistogram(const string& name, |
| 640 Sample minimum, | 610 Sample minimum, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 return NULL; | 673 return NULL; |
| 704 } | 674 } |
| 705 return histogram; | 675 return histogram; |
| 706 } | 676 } |
| 707 | 677 |
| 708 //------------------------------------------------------------------------------ | 678 //------------------------------------------------------------------------------ |
| 709 // This section provides implementation for BooleanHistogram. | 679 // This section provides implementation for BooleanHistogram. |
| 710 //------------------------------------------------------------------------------ | 680 //------------------------------------------------------------------------------ |
| 711 | 681 |
| 712 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { | 682 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { |
| 713 Histogram* histogram = StatisticsRecorder::FindHistogram(name); | 683 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 714 if (!histogram) { | 684 if (!histogram) { |
| 715 // To avoid racy destruction at shutdown, the following will be leaked. | 685 // To avoid racy destruction at shutdown, the following will be leaked. |
| 716 BucketRanges* ranges = new BucketRanges(4); | 686 BucketRanges* ranges = new BucketRanges(4); |
| 717 LinearHistogram::InitializeBucketRanges(1, 2, 3, ranges); | 687 LinearHistogram::InitializeBucketRanges(1, 2, 3, ranges); |
| 718 const BucketRanges* registered_ranges = | 688 const BucketRanges* registered_ranges = |
| 719 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 689 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 720 | 690 |
| 721 BooleanHistogram* tentative_histogram = | 691 BooleanHistogram* tentative_histogram = |
| 722 new BooleanHistogram(name, registered_ranges); | 692 new BooleanHistogram(name, registered_ranges); |
| 723 CheckCorruption(*tentative_histogram, true); | |
| 724 | 693 |
| 725 tentative_histogram->SetFlags(flags); | 694 tentative_histogram->SetFlags(flags); |
| 726 histogram = | 695 histogram = |
| 727 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 696 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 728 } | 697 } |
| 729 // TODO(rtenneti): delete this code after debugging. | |
| 730 CheckCorruption(*histogram, false); | |
| 731 | 698 |
| 732 CHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | 699 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
| 733 return histogram; | 700 return histogram; |
| 734 } | 701 } |
| 735 | 702 |
| 736 HistogramType BooleanHistogram::GetHistogramType() const { | 703 HistogramType BooleanHistogram::GetHistogramType() const { |
| 737 return BOOLEAN_HISTOGRAM; | 704 return BOOLEAN_HISTOGRAM; |
| 738 } | 705 } |
| 739 | 706 |
| 740 BooleanHistogram::BooleanHistogram(const string& name, | 707 BooleanHistogram::BooleanHistogram(const string& name, |
| 741 const BucketRanges* ranges) | 708 const BucketRanges* ranges) |
| 742 : LinearHistogram(name, 1, 2, 3, ranges) {} | 709 : LinearHistogram(name, 1, 2, 3, ranges) {} |
| (...skipping 22 matching lines...) Expand all Loading... |
| 765 | 732 |
| 766 //------------------------------------------------------------------------------ | 733 //------------------------------------------------------------------------------ |
| 767 // CustomHistogram: | 734 // CustomHistogram: |
| 768 //------------------------------------------------------------------------------ | 735 //------------------------------------------------------------------------------ |
| 769 | 736 |
| 770 HistogramBase* CustomHistogram::FactoryGet(const string& name, | 737 HistogramBase* CustomHistogram::FactoryGet(const string& name, |
| 771 const vector<Sample>& custom_ranges, | 738 const vector<Sample>& custom_ranges, |
| 772 int32 flags) { | 739 int32 flags) { |
| 773 CHECK(ValidateCustomRanges(custom_ranges)); | 740 CHECK(ValidateCustomRanges(custom_ranges)); |
| 774 | 741 |
| 775 Histogram* histogram = StatisticsRecorder::FindHistogram(name); | 742 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 776 if (!histogram) { | 743 if (!histogram) { |
| 777 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | 744 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); |
| 778 const BucketRanges* registered_ranges = | 745 const BucketRanges* registered_ranges = |
| 779 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 746 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 780 | 747 |
| 781 // To avoid racy destruction at shutdown, the following will be leaked. | 748 // To avoid racy destruction at shutdown, the following will be leaked. |
| 782 CustomHistogram* tentative_histogram = | 749 CustomHistogram* tentative_histogram = |
| 783 new CustomHistogram(name, registered_ranges); | 750 new CustomHistogram(name, registered_ranges); |
| 784 CheckCorruption(*tentative_histogram, true); | |
| 785 | 751 |
| 786 tentative_histogram->SetFlags(flags); | 752 tentative_histogram->SetFlags(flags); |
| 787 | 753 |
| 788 histogram = | 754 histogram = |
| 789 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 755 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 790 } | 756 } |
| 791 // TODO(rtenneti): delete this code after debugging. | |
| 792 CheckCorruption(*histogram, false); | |
| 793 | 757 |
| 794 CHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | 758 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); |
| 795 return histogram; | 759 return histogram; |
| 796 } | 760 } |
| 797 | 761 |
| 798 HistogramType CustomHistogram::GetHistogramType() const { | 762 HistogramType CustomHistogram::GetHistogramType() const { |
| 799 return CUSTOM_HISTOGRAM; | 763 return CUSTOM_HISTOGRAM; |
| 800 } | 764 } |
| 801 | 765 |
| 802 // static | 766 // static |
| 803 vector<Sample> CustomHistogram::ArrayToCustomRanges( | 767 vector<Sample> CustomHistogram::ArrayToCustomRanges( |
| 804 const Sample* values, size_t num_values) { | 768 const Sample* values, size_t num_values) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 | 860 |
| 897 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | 861 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
| 898 for (size_t i = 0; i < ranges.size(); i++) { | 862 for (size_t i = 0; i < ranges.size(); i++) { |
| 899 bucket_ranges->set_range(i, ranges[i]); | 863 bucket_ranges->set_range(i, ranges[i]); |
| 900 } | 864 } |
| 901 bucket_ranges->ResetChecksum(); | 865 bucket_ranges->ResetChecksum(); |
| 902 return bucket_ranges; | 866 return bucket_ranges; |
| 903 } | 867 } |
| 904 | 868 |
| 905 } // namespace base | 869 } // namespace base |
| OLD | NEW |