Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1569)

Side by Side Diff: base/metrics/histogram.cc

Issue 6780035: Use lock-free lazy initialization for static histogram references (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698