OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, | 66 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, |
67 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, | 67 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, |
68 0x2d02ef8dL, | 68 0x2d02ef8dL, |
69 }; | 69 }; |
70 | 70 |
71 typedef Histogram::Count Count; | 71 typedef Histogram::Count Count; |
72 | 72 |
73 // static | 73 // static |
74 const size_t Histogram::kBucketCount_MAX = 16384u; | 74 const size_t Histogram::kBucketCount_MAX = 16384u; |
75 | 75 |
76 scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name, | 76 Histogram* Histogram::FactoryGet(const std::string& name, |
77 Sample minimum, Sample maximum, size_t bucket_count, Flags flags) { | 77 Sample minimum, |
78 scoped_refptr<Histogram> histogram(NULL); | 78 Sample maximum, |
| 79 size_t bucket_count, |
| 80 Flags flags) { |
| 81 Histogram* histogram(NULL); |
79 | 82 |
80 // Defensive code. | 83 // Defensive code. |
81 if (minimum < 1) | 84 if (minimum < 1) |
82 minimum = 1; | 85 minimum = 1; |
83 if (maximum > kSampleType_MAX - 1) | 86 if (maximum > kSampleType_MAX - 1) |
84 maximum = kSampleType_MAX - 1; | 87 maximum = kSampleType_MAX - 1; |
85 | 88 |
86 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 89 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
87 histogram = new Histogram(name, minimum, maximum, bucket_count); | 90 // Extra variable is not needed... but this keeps this section basically |
88 histogram->InitializeBucketRange(); | 91 // identical to other derived classes in this file (and compiler will |
89 histogram->SetFlags(flags); | 92 // optimize away the extra variable. |
90 StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram); | 93 // To avoid racy destruction at shutdown, the following will be leaked. |
| 94 Histogram* tentative_histogram = |
| 95 new Histogram(name, minimum, maximum, bucket_count); |
| 96 tentative_histogram->InitializeBucketRange(); |
| 97 tentative_histogram->SetFlags(flags); |
| 98 histogram = |
| 99 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
91 } | 100 } |
92 | 101 |
93 DCHECK_EQ(HISTOGRAM, histogram->histogram_type()); | 102 DCHECK_EQ(HISTOGRAM, histogram->histogram_type()); |
94 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); | 103 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); |
95 return histogram; | 104 return histogram; |
96 } | 105 } |
97 | 106 |
98 scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name, | 107 Histogram* Histogram::FactoryTimeGet(const std::string& name, |
99 TimeDelta minimum, | 108 TimeDelta minimum, |
100 TimeDelta maximum, | 109 TimeDelta maximum, |
101 size_t bucket_count, | 110 size_t bucket_count, |
102 Flags flags) { | 111 Flags flags) { |
103 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), | 112 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), |
104 bucket_count, flags); | 113 bucket_count, flags); |
105 } | 114 } |
106 | 115 |
107 void Histogram::Add(int value) { | 116 void Histogram::Add(int value) { |
108 if (value > kSampleType_MAX - 1) | 117 if (value > kSampleType_MAX - 1) |
109 value = kSampleType_MAX - 1; | 118 value = kSampleType_MAX - 1; |
110 if (value < 0) | 119 if (value < 0) |
111 value = 0; | 120 value = 0; |
112 size_t index = BucketIndex(value); | 121 size_t index = BucketIndex(value); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || | 261 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || |
253 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) { | 262 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) { |
254 LOG(ERROR) << "Values error decoding Histogram: " << histogram_name; | 263 LOG(ERROR) << "Values error decoding Histogram: " << histogram_name; |
255 return false; | 264 return false; |
256 } | 265 } |
257 | 266 |
258 Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag); | 267 Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag); |
259 | 268 |
260 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type); | 269 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type); |
261 | 270 |
262 scoped_refptr<Histogram> render_histogram(NULL); | 271 Histogram* render_histogram(NULL); |
263 | 272 |
264 if (histogram_type == HISTOGRAM) { | 273 if (histogram_type == HISTOGRAM) { |
265 render_histogram = Histogram::FactoryGet( | 274 render_histogram = Histogram::FactoryGet( |
266 histogram_name, declared_min, declared_max, bucket_count, flags); | 275 histogram_name, declared_min, declared_max, bucket_count, flags); |
267 } else if (histogram_type == LINEAR_HISTOGRAM) { | 276 } else if (histogram_type == LINEAR_HISTOGRAM) { |
268 render_histogram = LinearHistogram::FactoryGet( | 277 render_histogram = LinearHistogram::FactoryGet( |
269 histogram_name, declared_min, declared_max, bucket_count, flags); | 278 histogram_name, declared_min, declared_max, bucket_count, flags); |
270 } else if (histogram_type == BOOLEAN_HISTOGRAM) { | 279 } else if (histogram_type == BOOLEAN_HISTOGRAM) { |
271 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags); | 280 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags); |
272 } else { | 281 } else { |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 } | 763 } |
755 | 764 |
756 //------------------------------------------------------------------------------ | 765 //------------------------------------------------------------------------------ |
757 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 766 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
758 // buckets. | 767 // buckets. |
759 //------------------------------------------------------------------------------ | 768 //------------------------------------------------------------------------------ |
760 | 769 |
761 LinearHistogram::~LinearHistogram() { | 770 LinearHistogram::~LinearHistogram() { |
762 } | 771 } |
763 | 772 |
764 scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name, | 773 Histogram* LinearHistogram::FactoryGet(const std::string& name, |
765 Sample minimum, | 774 Sample minimum, |
766 Sample maximum, | 775 Sample maximum, |
767 size_t bucket_count, | 776 size_t bucket_count, |
768 Flags flags) { | 777 Flags flags) { |
769 scoped_refptr<Histogram> histogram(NULL); | 778 Histogram* histogram(NULL); |
770 | 779 |
771 if (minimum < 1) | 780 if (minimum < 1) |
772 minimum = 1; | 781 minimum = 1; |
773 if (maximum > kSampleType_MAX - 1) | 782 if (maximum > kSampleType_MAX - 1) |
774 maximum = kSampleType_MAX - 1; | 783 maximum = kSampleType_MAX - 1; |
775 | 784 |
776 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 785 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
777 LinearHistogram* linear_histogram = | 786 // To avoid racy destruction at shutdown, the following will be leaked. |
| 787 LinearHistogram* tentative_histogram = |
778 new LinearHistogram(name, minimum, maximum, bucket_count); | 788 new LinearHistogram(name, minimum, maximum, bucket_count); |
779 linear_histogram->InitializeBucketRange(); | 789 tentative_histogram->InitializeBucketRange(); |
780 histogram = linear_histogram; | 790 tentative_histogram->SetFlags(flags); |
781 histogram->SetFlags(flags); | 791 histogram = |
782 StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram); | 792 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
783 } | 793 } |
784 | 794 |
785 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type()); | 795 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type()); |
786 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); | 796 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); |
787 return histogram; | 797 return histogram; |
788 } | 798 } |
789 | 799 |
790 scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet( | 800 Histogram* LinearHistogram::FactoryTimeGet(const std::string& name, |
791 const std::string& name, | 801 TimeDelta minimum, |
792 TimeDelta minimum, | 802 TimeDelta maximum, |
793 TimeDelta maximum, | 803 size_t bucket_count, |
794 size_t bucket_count, | 804 Flags flags) { |
795 Flags flags) { | |
796 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), | 805 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), |
797 bucket_count, flags); | 806 bucket_count, flags); |
798 } | 807 } |
799 | 808 |
800 Histogram::ClassType LinearHistogram::histogram_type() const { | 809 Histogram::ClassType LinearHistogram::histogram_type() const { |
801 return LINEAR_HISTOGRAM; | 810 return LINEAR_HISTOGRAM; |
802 } | 811 } |
803 | 812 |
804 void LinearHistogram::SetRangeDescriptions( | 813 void LinearHistogram::SetRangeDescriptions( |
805 const DescriptionPair descriptions[]) { | 814 const DescriptionPair descriptions[]) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 | 864 |
856 bool LinearHistogram::PrintEmptyBucket(size_t index) const { | 865 bool LinearHistogram::PrintEmptyBucket(size_t index) const { |
857 return bucket_description_.find(ranges(index)) == bucket_description_.end(); | 866 return bucket_description_.find(ranges(index)) == bucket_description_.end(); |
858 } | 867 } |
859 | 868 |
860 | 869 |
861 //------------------------------------------------------------------------------ | 870 //------------------------------------------------------------------------------ |
862 // This section provides implementation for BooleanHistogram. | 871 // This section provides implementation for BooleanHistogram. |
863 //------------------------------------------------------------------------------ | 872 //------------------------------------------------------------------------------ |
864 | 873 |
865 scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name, | 874 Histogram* BooleanHistogram::FactoryGet(const std::string& name, Flags flags) { |
866 Flags flags) { | 875 Histogram* histogram(NULL); |
867 scoped_refptr<Histogram> histogram(NULL); | |
868 | 876 |
869 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 877 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
870 BooleanHistogram* boolean_histogram = new BooleanHistogram(name); | 878 // To avoid racy destruction at shutdown, the following will be leaked. |
871 boolean_histogram->InitializeBucketRange(); | 879 BooleanHistogram* tentative_histogram = new BooleanHistogram(name); |
872 histogram = boolean_histogram; | 880 tentative_histogram->InitializeBucketRange(); |
873 histogram->SetFlags(flags); | 881 tentative_histogram->SetFlags(flags); |
874 StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram); | 882 histogram = |
| 883 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
875 } | 884 } |
876 | 885 |
877 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type()); | 886 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type()); |
878 return histogram; | 887 return histogram; |
879 } | 888 } |
880 | 889 |
881 Histogram::ClassType BooleanHistogram::histogram_type() const { | 890 Histogram::ClassType BooleanHistogram::histogram_type() const { |
882 return BOOLEAN_HISTOGRAM; | 891 return BOOLEAN_HISTOGRAM; |
883 } | 892 } |
884 | 893 |
885 void BooleanHistogram::AddBoolean(bool value) { | 894 void BooleanHistogram::AddBoolean(bool value) { |
886 Add(value ? 1 : 0); | 895 Add(value ? 1 : 0); |
887 } | 896 } |
888 | 897 |
889 BooleanHistogram::BooleanHistogram(const std::string& name) | 898 BooleanHistogram::BooleanHistogram(const std::string& name) |
890 : LinearHistogram(name, 1, 2, 3) { | 899 : LinearHistogram(name, 1, 2, 3) { |
891 } | 900 } |
892 | 901 |
893 //------------------------------------------------------------------------------ | 902 //------------------------------------------------------------------------------ |
894 // CustomHistogram: | 903 // CustomHistogram: |
895 //------------------------------------------------------------------------------ | 904 //------------------------------------------------------------------------------ |
896 | 905 |
897 scoped_refptr<Histogram> CustomHistogram::FactoryGet( | 906 Histogram* CustomHistogram::FactoryGet(const std::string& name, |
898 const std::string& name, | 907 const std::vector<Sample>& custom_ranges, |
899 const std::vector<Sample>& custom_ranges, | 908 Flags flags) { |
900 Flags flags) { | 909 Histogram* histogram(NULL); |
901 scoped_refptr<Histogram> histogram(NULL); | |
902 | 910 |
903 // Remove the duplicates in the custom ranges array. | 911 // Remove the duplicates in the custom ranges array. |
904 std::vector<int> ranges = custom_ranges; | 912 std::vector<int> ranges = custom_ranges; |
905 ranges.push_back(0); // Ensure we have a zero value. | 913 ranges.push_back(0); // Ensure we have a zero value. |
906 std::sort(ranges.begin(), ranges.end()); | 914 std::sort(ranges.begin(), ranges.end()); |
907 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | 915 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
908 if (ranges.size() <= 1) { | 916 if (ranges.size() <= 1) { |
909 DCHECK(false); | 917 DCHECK(false); |
910 // Note that we pushed a 0 in above, so for defensive code.... | 918 // Note that we pushed a 0 in above, so for defensive code.... |
911 ranges.push_back(1); // Put in some data so we can index to [1]. | 919 ranges.push_back(1); // Put in some data so we can index to [1]. |
912 } | 920 } |
913 | 921 |
914 DCHECK_LT(ranges.back(), kSampleType_MAX); | 922 DCHECK_LT(ranges.back(), kSampleType_MAX); |
915 | 923 |
916 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 924 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
917 CustomHistogram* custom_histogram = new CustomHistogram(name, ranges); | 925 // To avoid racy destruction at shutdown, the following will be leaked. |
918 custom_histogram->InitializedCustomBucketRange(ranges); | 926 CustomHistogram* tentative_histogram = new CustomHistogram(name, ranges); |
919 histogram = custom_histogram; | 927 tentative_histogram->InitializedCustomBucketRange(ranges); |
920 histogram->SetFlags(flags); | 928 tentative_histogram->SetFlags(flags); |
921 StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram); | 929 histogram = |
| 930 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
922 } | 931 } |
923 | 932 |
924 DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM); | 933 DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM); |
925 DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(), | 934 DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(), |
926 ranges.size())); | 935 ranges.size())); |
927 return histogram; | 936 return histogram; |
928 } | 937 } |
929 | 938 |
930 Histogram::ClassType CustomHistogram::histogram_type() const { | 939 Histogram::ClassType CustomHistogram::histogram_type() const { |
931 return CUSTOM_HISTOGRAM; | 940 return CUSTOM_HISTOGRAM; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 } | 1006 } |
998 | 1007 |
999 // static | 1008 // static |
1000 bool StatisticsRecorder::IsActive() { | 1009 bool StatisticsRecorder::IsActive() { |
1001 if (lock_ == NULL) | 1010 if (lock_ == NULL) |
1002 return false; | 1011 return false; |
1003 base::AutoLock auto_lock(*lock_); | 1012 base::AutoLock auto_lock(*lock_); |
1004 return NULL != histograms_; | 1013 return NULL != histograms_; |
1005 } | 1014 } |
1006 | 1015 |
1007 // Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a | 1016 Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* histogram) { |
1008 // reference, and we are called while in the Histogram constructor. In that | 1017 DCHECK(histogram->HasValidRangeChecksum()); |
1009 // scenario, a ref_ptr would have incremented the ref count when the histogram | |
1010 // was passed to us, decremented it when we returned, and the instance would be | |
1011 // destroyed before assignment (when value was returned by new). | |
1012 // static | |
1013 void StatisticsRecorder::RegisterOrDiscardDuplicate( | |
1014 scoped_refptr<Histogram>* histogram) { | |
1015 DCHECK((*histogram)->HasValidRangeChecksum()); | |
1016 if (lock_ == NULL) | 1018 if (lock_ == NULL) |
1017 return; | 1019 return histogram; |
1018 base::AutoLock auto_lock(*lock_); | 1020 base::AutoLock auto_lock(*lock_); |
1019 if (!histograms_) | 1021 if (!histograms_) |
1020 return; | 1022 return histogram; |
1021 const std::string name = (*histogram)->histogram_name(); | 1023 const std::string name = histogram->histogram_name(); |
1022 HistogramMap::iterator it = histograms_->find(name); | 1024 HistogramMap::iterator it = histograms_->find(name); |
1023 // Avoid overwriting a previous registration. | 1025 // Avoid overwriting a previous registration. |
1024 if (histograms_->end() == it) | 1026 if (histograms_->end() == it) { |
1025 (*histograms_)[name] = *histogram; | 1027 (*histograms_)[name] = histogram; |
1026 else | 1028 } else { |
1027 *histogram = it->second; | 1029 delete histogram; // We already have one by this name. |
| 1030 histogram = it->second; |
| 1031 } |
| 1032 return histogram; |
1028 } | 1033 } |
1029 | 1034 |
1030 // static | 1035 // static |
1031 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, | 1036 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, |
1032 std::string* output) { | 1037 std::string* output) { |
1033 if (!IsActive()) | 1038 if (!IsActive()) |
1034 return; | 1039 return; |
1035 output->append("<html><head><title>About Histograms"); | 1040 output->append("<html><head><title>About Histograms"); |
1036 if (!query.empty()) | 1041 if (!query.empty()) |
1037 output->append(" - " + query); | 1042 output->append(" - " + query); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 return; | 1085 return; |
1081 for (HistogramMap::iterator it = histograms_->begin(); | 1086 for (HistogramMap::iterator it = histograms_->begin(); |
1082 histograms_->end() != it; | 1087 histograms_->end() != it; |
1083 ++it) { | 1088 ++it) { |
1084 DCHECK_EQ(it->first, it->second->histogram_name()); | 1089 DCHECK_EQ(it->first, it->second->histogram_name()); |
1085 output->push_back(it->second); | 1090 output->push_back(it->second); |
1086 } | 1091 } |
1087 } | 1092 } |
1088 | 1093 |
1089 bool StatisticsRecorder::FindHistogram(const std::string& name, | 1094 bool StatisticsRecorder::FindHistogram(const std::string& name, |
1090 scoped_refptr<Histogram>* histogram) { | 1095 Histogram** histogram) { |
1091 if (lock_ == NULL) | 1096 if (lock_ == NULL) |
1092 return false; | 1097 return false; |
1093 base::AutoLock auto_lock(*lock_); | 1098 base::AutoLock auto_lock(*lock_); |
1094 if (!histograms_) | 1099 if (!histograms_) |
1095 return false; | 1100 return false; |
1096 HistogramMap::iterator it = histograms_->find(name); | 1101 HistogramMap::iterator it = histograms_->find(name); |
1097 if (histograms_->end() == it) | 1102 if (histograms_->end() == it) |
1098 return false; | 1103 return false; |
1099 *histogram = it->second; | 1104 *histogram = it->second; |
1100 return true; | 1105 return true; |
(...skipping 16 matching lines...) Expand all Loading... |
1117 } | 1122 } |
1118 | 1123 |
1119 // static | 1124 // static |
1120 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 1125 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
1121 // static | 1126 // static |
1122 base::Lock* StatisticsRecorder::lock_ = NULL; | 1127 base::Lock* StatisticsRecorder::lock_ = NULL; |
1123 // static | 1128 // static |
1124 bool StatisticsRecorder::dump_on_exit_ = false; | 1129 bool StatisticsRecorder::dump_on_exit_ = false; |
1125 | 1130 |
1126 } // namespace base | 1131 } // namespace base |
OLD | NEW |