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 |