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" |
11 | 11 |
12 #include <math.h> | 12 #include <math.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 #include <string> | 15 #include <string> |
16 | 16 |
17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
18 #include "base/debug/alias.h" | 18 #include "base/debug/alias.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/metrics/histogram_macros.h" | 20 #include "base/metrics/histogram_macros.h" |
21 #include "base/metrics/histogram_persistence.h" | |
21 #include "base/metrics/metrics_hashes.h" | 22 #include "base/metrics/metrics_hashes.h" |
23 #include "base/metrics/persistent_memory_allocator.h" | |
22 #include "base/metrics/sample_vector.h" | 24 #include "base/metrics/sample_vector.h" |
23 #include "base/metrics/statistics_recorder.h" | 25 #include "base/metrics/statistics_recorder.h" |
24 #include "base/pickle.h" | 26 #include "base/pickle.h" |
25 #include "base/strings/string_util.h" | 27 #include "base/strings/string_util.h" |
26 #include "base/strings/stringprintf.h" | 28 #include "base/strings/stringprintf.h" |
27 #include "base/synchronization/lock.h" | 29 #include "base/synchronization/lock.h" |
28 #include "base/values.h" | 30 #include "base/values.h" |
29 | 31 |
30 namespace base { | 32 namespace base { |
31 | 33 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 } | 78 } |
77 | 79 |
78 } // namespace | 80 } // namespace |
79 | 81 |
80 typedef HistogramBase::Count Count; | 82 typedef HistogramBase::Count Count; |
81 typedef HistogramBase::Sample Sample; | 83 typedef HistogramBase::Sample Sample; |
82 | 84 |
83 // static | 85 // static |
84 const size_t Histogram::kBucketCount_MAX = 16384u; | 86 const size_t Histogram::kBucketCount_MAX = 16384u; |
85 | 87 |
88 | |
89 class Histogram::Factory { | |
90 public: | |
91 Factory(const std::string& name, | |
92 HistogramBase::Sample minimum, | |
93 HistogramBase::Sample maximum, | |
94 size_t bucket_count, | |
95 int32 flags) | |
96 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {} | |
97 | |
98 HistogramBase* Build(); | |
99 | |
100 protected: | |
101 Factory(const std::string& name, | |
102 HistogramType histogram_type, | |
103 HistogramBase::Sample minimum, | |
104 HistogramBase::Sample maximum, | |
105 size_t bucket_count, | |
106 int32 flags) | |
107 : name_(name), | |
108 histogram_type_(histogram_type), | |
109 minimum_(minimum), | |
110 maximum_(maximum), | |
111 bucket_count_(bucket_count), | |
112 flags_(flags) {} | |
113 | |
114 virtual BucketRanges* CreateRanges() { | |
115 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); | |
116 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges); | |
117 return ranges; | |
118 } | |
119 | |
120 virtual HistogramBase* HeapAlloc(const BucketRanges* ranges) { | |
121 return new Histogram(name_, minimum_, maximum_, ranges); | |
122 } | |
123 | |
124 virtual void FillHistogram(HistogramBase* histogram) {} | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Please document these methods and the class.
bcwhite
2015/12/22 20:50:38
Done.
| |
125 | |
126 const std::string& name_; | |
127 const HistogramType histogram_type_; | |
128 HistogramBase::Sample minimum_; | |
129 HistogramBase::Sample maximum_; | |
130 size_t bucket_count_; | |
131 int32 flags_; | |
132 }; | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Add a private: section and DISALLOW_COPY_AND_ASSIG
bcwhite
2015/12/22 20:50:37
Done.
| |
133 | |
134 HistogramBase* Histogram::Factory::Build() { | |
135 ImportPersistentHistograms(); | |
136 | |
137 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); | |
138 if (!histogram) { | |
139 // To avoid racy destruction at shutdown, the following will be leaked. | |
140 const BucketRanges* created_ranges = CreateRanges(); | |
141 const BucketRanges* registered_ranges = | |
142 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); | |
143 | |
144 // Sometimes the bucket info is dynamically determined in create_ranges(). | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Nit: create_ranges() -> CreateRanges().
bcwhite
2015/12/22 20:50:37
Done.
| |
145 if (bucket_count_ == 0) { | |
146 bucket_count_ = registered_ranges->bucket_count(); | |
147 minimum_ = registered_ranges->range(1); | |
148 maximum_ = registered_ranges->range(bucket_count_ - 1); | |
149 } | |
150 | |
151 PersistentMemoryAllocator::Reference histogram_ref = 0; | |
152 HistogramBase* tentative_histogram = nullptr; | |
153 PersistentMemoryAllocator* allocator = | |
154 GetPersistentHistogramMemoryAllocator(); | |
155 if (allocator) { | |
156 flags_ |= HistogramBase::kIsPersistent; | |
157 tentative_histogram = AllocatePersistentHistogram( | |
158 allocator, | |
159 histogram_type_, | |
160 name_, | |
161 minimum_, | |
162 maximum_, | |
163 registered_ranges, | |
164 flags_, | |
165 &histogram_ref); | |
166 } | |
167 if (!tentative_histogram) { | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Either make this an else or mention in what legit
bcwhite
2015/12/22 20:50:38
Done.
| |
168 flags_ &= ~HistogramBase::kIsPersistent; | |
169 tentative_histogram = HeapAlloc(registered_ranges); | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Should this also clear histogram_ref?
Or is the e
bcwhite
2015/12/22 20:50:37
Done.
| |
170 } | |
171 | |
172 FillHistogram(tentative_histogram); | |
173 | |
174 tentative_histogram->SetFlags(flags_); | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Nit: Move this about FillHistogram() and don't sep
bcwhite
2015/12/22 20:50:37
That will require that any overriden FillHistogram
| |
175 histogram = | |
176 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
177 | |
178 // Persistent histograms need some follow-up processing. | |
179 if (histogram_ref) { | |
180 // If the created persistent histogram is canonical then it needs to be | |
181 // marked as "iterable" in order to be found by other processes. | |
182 if (histogram == tentative_histogram) | |
183 GetPersistentHistogramMemoryAllocator()->MakeIterable(histogram_ref); | |
184 // If it's not the canonical one then a race condition must have caused | |
185 // two to be created. The allocator does not support releasing the | |
186 // acquired memory so just change the type to be empty. | |
187 else | |
188 GetPersistentHistogramMemoryAllocator()->SetType(histogram_ref, 0); | |
Alexei Svitkine (slow)
2015/12/21 19:32:11
Can this logic be contained in the allocator? i.e.
bcwhite
2015/12/22 20:50:38
Done.
| |
189 } | |
190 } | |
191 | |
192 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); | |
193 if (bucket_count_ != 0 && | |
194 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { | |
195 // The construction arguments do not match the existing histogram. This can | |
196 // come about if an extension updates in the middle of a chrome run and has | |
197 // changed one of them, or simply by bad code within Chrome itself. We | |
198 // return NULL here with the expectation that bad code in Chrome will crash | |
199 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
200 // crash. | |
201 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; | |
202 return nullptr; | |
203 } | |
204 return histogram; | |
205 } | |
206 | |
207 | |
86 HistogramBase* Histogram::FactoryGet(const std::string& name, | 208 HistogramBase* Histogram::FactoryGet(const std::string& name, |
87 Sample minimum, | 209 Sample minimum, |
88 Sample maximum, | 210 Sample maximum, |
89 size_t bucket_count, | 211 size_t bucket_count, |
90 int32 flags) { | 212 int32 flags) { |
91 bool valid_arguments = | 213 bool valid_arguments = |
92 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 214 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
93 DCHECK(valid_arguments); | 215 DCHECK(valid_arguments); |
94 | 216 |
95 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 217 return Factory(name, minimum, maximum, bucket_count, flags).Build(); |
96 if (!histogram) { | |
97 // To avoid racy destruction at shutdown, the following will be leaked. | |
98 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
99 InitializeBucketRanges(minimum, maximum, ranges); | |
100 const BucketRanges* registered_ranges = | |
101 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
102 | |
103 Histogram* tentative_histogram = | |
104 new Histogram(name, minimum, maximum, registered_ranges); | |
105 | |
106 tentative_histogram->SetFlags(flags); | |
107 histogram = | |
108 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
109 } | |
110 | |
111 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | |
112 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
113 // The construction arguments do not match the existing histogram. This can | |
114 // come about if an extension updates in the middle of a chrome run and has | |
115 // changed one of them, or simply by bad code within Chrome itself. We | |
116 // return NULL here with the expectation that bad code in Chrome will crash | |
117 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
118 // crash. | |
119 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
120 return NULL; | |
121 } | |
122 return histogram; | |
123 } | 218 } |
124 | 219 |
125 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, | 220 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
126 TimeDelta minimum, | 221 TimeDelta minimum, |
127 TimeDelta maximum, | 222 TimeDelta maximum, |
128 size_t bucket_count, | 223 size_t bucket_count, |
129 int32 flags) { | 224 int32 flags) { |
130 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 225 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
131 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 226 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
132 flags); | 227 flags); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 Sample maximum, | 431 Sample maximum, |
337 const BucketRanges* ranges) | 432 const BucketRanges* ranges) |
338 : HistogramBase(name), | 433 : HistogramBase(name), |
339 bucket_ranges_(ranges), | 434 bucket_ranges_(ranges), |
340 declared_min_(minimum), | 435 declared_min_(minimum), |
341 declared_max_(maximum) { | 436 declared_max_(maximum) { |
342 if (ranges) | 437 if (ranges) |
343 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 438 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
344 } | 439 } |
345 | 440 |
441 Histogram::Histogram(const std::string& name, | |
442 Sample minimum, | |
443 Sample maximum, | |
444 const BucketRanges* ranges, | |
445 HistogramBase::AtomicCount* counts, | |
446 size_t counts_size, | |
447 HistogramSamples::Metadata* meta) | |
448 : HistogramBase(name), | |
449 bucket_ranges_(ranges), | |
450 declared_min_(minimum), | |
451 declared_max_(maximum) { | |
452 if (ranges) | |
453 samples_.reset(new SampleVector(HashMetricName(name), | |
454 counts, counts_size, meta, ranges)); | |
455 } | |
456 | |
346 Histogram::~Histogram() { | 457 Histogram::~Histogram() { |
347 } | 458 } |
348 | 459 |
349 bool Histogram::PrintEmptyBucket(size_t index) const { | 460 bool Histogram::PrintEmptyBucket(size_t index) const { |
350 return true; | 461 return true; |
351 } | 462 } |
352 | 463 |
353 // Use the actual bucket widths (like a linear histogram) until the widths get | 464 // Use the actual bucket widths (like a linear histogram) until the widths get |
354 // over some transition value, and then use that transition width. Exponentials | 465 // over some transition value, and then use that transition width. Exponentials |
355 // get so big so fast (and we don't expect to see a lot of entries in the large | 466 // get so big so fast (and we don't expect to see a lot of entries in the large |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
537 ++index; | 648 ++index; |
538 } | 649 } |
539 } | 650 } |
540 } | 651 } |
541 | 652 |
542 //------------------------------------------------------------------------------ | 653 //------------------------------------------------------------------------------ |
543 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 654 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
544 // buckets. | 655 // buckets. |
545 //------------------------------------------------------------------------------ | 656 //------------------------------------------------------------------------------ |
546 | 657 |
547 LinearHistogram::~LinearHistogram() {} | 658 class LinearHistogram::Factory : public Histogram::Factory { |
659 public: | |
660 Factory(const std::string& name, | |
661 HistogramBase::Sample minimum, | |
662 HistogramBase::Sample maximum, | |
663 size_t bucket_count, | |
664 int32 flags, | |
665 const DescriptionPair* descriptions) | |
666 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum, | |
667 bucket_count, flags) { | |
668 descriptions_ = descriptions; | |
669 } | |
670 | |
671 protected: | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Nit: private:
and add DISALLOW_COPY_AND_ASSIGN()
bcwhite
2015/12/22 20:50:37
Done.
| |
672 BucketRanges* CreateRanges() override { | |
673 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); | |
674 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges); | |
675 return ranges; | |
676 } | |
677 | |
678 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { | |
679 return new LinearHistogram(name_, minimum_, maximum_, ranges); | |
680 } | |
681 | |
682 void FillHistogram(HistogramBase* base_histogram) override { | |
683 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram); | |
684 // Set range descriptions. | |
685 if (descriptions_) { | |
686 for (int i = 0; descriptions_[i].description; ++i) { | |
687 histogram->bucket_description_[descriptions_[i].sample] = | |
688 descriptions_[i].description; | |
689 } | |
690 } | |
691 } | |
692 | |
693 const DescriptionPair* descriptions_; | |
694 }; | |
548 | 695 |
549 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, | 696 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, |
550 Sample minimum, | 697 Sample minimum, |
551 Sample maximum, | 698 Sample maximum, |
552 size_t bucket_count, | 699 size_t bucket_count, |
553 int32 flags) { | 700 int32 flags) { |
554 return FactoryGetWithRangeDescription( | 701 return FactoryGetWithRangeDescription( |
555 name, minimum, maximum, bucket_count, flags, NULL); | 702 name, minimum, maximum, bucket_count, flags, NULL); |
556 } | 703 } |
557 | 704 |
(...skipping 28 matching lines...) Expand all Loading... | |
586 const std::string& name, | 733 const std::string& name, |
587 Sample minimum, | 734 Sample minimum, |
588 Sample maximum, | 735 Sample maximum, |
589 size_t bucket_count, | 736 size_t bucket_count, |
590 int32 flags, | 737 int32 flags, |
591 const DescriptionPair descriptions[]) { | 738 const DescriptionPair descriptions[]) { |
592 bool valid_arguments = Histogram::InspectConstructionArguments( | 739 bool valid_arguments = Histogram::InspectConstructionArguments( |
593 name, &minimum, &maximum, &bucket_count); | 740 name, &minimum, &maximum, &bucket_count); |
594 DCHECK(valid_arguments); | 741 DCHECK(valid_arguments); |
595 | 742 |
596 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 743 return Factory(name, minimum, maximum, bucket_count, flags, descriptions) |
597 if (!histogram) { | 744 .Build(); |
598 // To avoid racy destruction at shutdown, the following will be leaked. | |
599 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
600 InitializeBucketRanges(minimum, maximum, ranges); | |
601 const BucketRanges* registered_ranges = | |
602 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
603 | |
604 LinearHistogram* tentative_histogram = | |
605 new LinearHistogram(name, minimum, maximum, registered_ranges); | |
606 | |
607 // Set range descriptions. | |
608 if (descriptions) { | |
609 for (int i = 0; descriptions[i].description; ++i) { | |
610 tentative_histogram->bucket_description_[descriptions[i].sample] = | |
611 descriptions[i].description; | |
612 } | |
613 } | |
614 | |
615 tentative_histogram->SetFlags(flags); | |
616 histogram = | |
617 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
618 } | |
619 | |
620 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | |
621 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
622 // The construction arguments do not match the existing histogram. This can | |
623 // come about if an extension updates in the middle of a chrome run and has | |
624 // changed one of them, or simply by bad code within Chrome itself. We | |
625 // return NULL here with the expectation that bad code in Chrome will crash | |
626 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
627 // crash. | |
628 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
629 return NULL; | |
630 } | |
631 return histogram; | |
632 } | 745 } |
633 | 746 |
634 HistogramType LinearHistogram::GetHistogramType() const { | 747 HistogramType LinearHistogram::GetHistogramType() const { |
635 return LINEAR_HISTOGRAM; | 748 return LINEAR_HISTOGRAM; |
636 } | 749 } |
637 | 750 |
638 LinearHistogram::LinearHistogram(const std::string& name, | 751 LinearHistogram::LinearHistogram(const std::string& name, |
639 Sample minimum, | 752 Sample minimum, |
640 Sample maximum, | 753 Sample maximum, |
641 const BucketRanges* ranges) | 754 const BucketRanges* ranges) |
642 : Histogram(name, minimum, maximum, ranges) { | 755 : Histogram(name, minimum, maximum, ranges) { |
643 } | 756 } |
644 | 757 |
758 LinearHistogram::LinearHistogram(const std::string& name, | |
759 Sample minimum, | |
760 Sample maximum, | |
761 const BucketRanges* ranges, | |
762 HistogramBase::AtomicCount* counts, | |
763 size_t counts_size, | |
764 HistogramSamples::Metadata* meta) | |
765 : Histogram(name, | |
766 minimum, | |
767 maximum, | |
768 ranges, | |
769 counts, | |
770 counts_size, | |
771 meta) {} | |
772 | |
645 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 773 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
646 DCHECK_GT(ranges(i + 1), ranges(i)); | 774 DCHECK_GT(ranges(i + 1), ranges(i)); |
647 // Adjacent buckets with different widths would have "surprisingly" many (few) | 775 // Adjacent buckets with different widths would have "surprisingly" many (few) |
648 // samples in a histogram if we didn't normalize this way. | 776 // samples in a histogram if we didn't normalize this way. |
649 double denominator = ranges(i + 1) - ranges(i); | 777 double denominator = ranges(i + 1) - ranges(i); |
650 return current/denominator; | 778 return current/denominator; |
651 } | 779 } |
652 | 780 |
653 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 781 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
654 int range = ranges(i); | 782 int range = ranges(i); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
698 // The serialized histogram might be corrupted. | 826 // The serialized histogram might be corrupted. |
699 return NULL; | 827 return NULL; |
700 } | 828 } |
701 return histogram; | 829 return histogram; |
702 } | 830 } |
703 | 831 |
704 //------------------------------------------------------------------------------ | 832 //------------------------------------------------------------------------------ |
705 // This section provides implementation for BooleanHistogram. | 833 // This section provides implementation for BooleanHistogram. |
706 //------------------------------------------------------------------------------ | 834 //------------------------------------------------------------------------------ |
707 | 835 |
836 class BooleanHistogram::Factory : public Histogram::Factory { | |
837 public: | |
838 Factory(const std::string& name, int32 flags) | |
839 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {} | |
840 | |
841 protected: | |
842 BucketRanges* CreateRanges() { | |
Alexei Svitkine (slow)
2015/12/21 19:32:10
Can this class just extend LinearHistogram and avo
bcwhite
2015/12/22 20:50:37
Yes but it would involve changing the LinearHistog
| |
843 BucketRanges* ranges = new BucketRanges(3 + 1); | |
844 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | |
845 return ranges; | |
846 } | |
847 | |
848 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { | |
849 return new BooleanHistogram(name_, ranges); | |
850 } | |
851 }; | |
852 | |
708 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, | 853 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
709 int32 flags) { | 854 int32 flags) { |
710 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 855 return Factory(name, flags).Build(); |
711 if (!histogram) { | |
712 // To avoid racy destruction at shutdown, the following will be leaked. | |
713 BucketRanges* ranges = new BucketRanges(4); | |
714 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | |
715 const BucketRanges* registered_ranges = | |
716 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
717 | |
718 BooleanHistogram* tentative_histogram = | |
719 new BooleanHistogram(name, registered_ranges); | |
720 | |
721 tentative_histogram->SetFlags(flags); | |
722 histogram = | |
723 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
724 } | |
725 | |
726 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | |
727 return histogram; | |
728 } | 856 } |
729 | 857 |
730 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { | 858 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { |
731 return FactoryGet(std::string(name), flags); | 859 return FactoryGet(std::string(name), flags); |
732 } | 860 } |
733 | 861 |
734 HistogramType BooleanHistogram::GetHistogramType() const { | 862 HistogramType BooleanHistogram::GetHistogramType() const { |
735 return BOOLEAN_HISTOGRAM; | 863 return BOOLEAN_HISTOGRAM; |
736 } | 864 } |
737 | 865 |
738 BooleanHistogram::BooleanHistogram(const std::string& name, | 866 BooleanHistogram::BooleanHistogram(const std::string& name, |
739 const BucketRanges* ranges) | 867 const BucketRanges* ranges) |
740 : LinearHistogram(name, 1, 2, ranges) {} | 868 : LinearHistogram(name, 1, 2, ranges) {} |
741 | 869 |
870 BooleanHistogram::BooleanHistogram(const std::string& name, | |
871 const BucketRanges* ranges, | |
872 HistogramBase::AtomicCount* counts, | |
873 HistogramSamples::Metadata* meta) | |
874 : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {} | |
875 | |
742 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 876 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
743 std::string histogram_name; | 877 std::string histogram_name; |
744 int flags; | 878 int flags; |
745 int declared_min; | 879 int declared_min; |
746 int declared_max; | 880 int declared_max; |
747 size_t bucket_count; | 881 size_t bucket_count; |
748 uint32 range_checksum; | 882 uint32 range_checksum; |
749 | 883 |
750 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 884 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
751 &declared_max, &bucket_count, &range_checksum)) { | 885 &declared_max, &bucket_count, &range_checksum)) { |
752 return NULL; | 886 return NULL; |
753 } | 887 } |
754 | 888 |
755 HistogramBase* histogram = BooleanHistogram::FactoryGet( | 889 HistogramBase* histogram = BooleanHistogram::FactoryGet( |
756 histogram_name, flags); | 890 histogram_name, flags); |
757 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 891 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
758 // The serialized histogram might be corrupted. | 892 // The serialized histogram might be corrupted. |
759 return NULL; | 893 return NULL; |
760 } | 894 } |
761 return histogram; | 895 return histogram; |
762 } | 896 } |
763 | 897 |
764 //------------------------------------------------------------------------------ | 898 //------------------------------------------------------------------------------ |
765 // CustomHistogram: | 899 // CustomHistogram: |
766 //------------------------------------------------------------------------------ | 900 //------------------------------------------------------------------------------ |
767 | 901 |
902 class CustomHistogram::Factory : public Histogram::Factory { | |
903 public: | |
904 Factory(const std::string& name, | |
905 const std::vector<Sample>* custom_ranges, | |
906 int32 flags) | |
907 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) { | |
908 custom_ranges_ = custom_ranges; | |
909 } | |
910 | |
911 protected: | |
912 BucketRanges* CreateRanges() { | |
913 // Remove the duplicates in the custom ranges array. | |
914 std::vector<int> ranges = *custom_ranges_; | |
915 ranges.push_back(0); // Ensure we have a zero value. | |
916 ranges.push_back(HistogramBase::kSampleType_MAX); | |
917 std::sort(ranges.begin(), ranges.end()); | |
918 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | |
919 | |
920 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | |
921 for (size_t i = 0; i < ranges.size(); i++) { | |
922 bucket_ranges->set_range(i, ranges[i]); | |
923 } | |
924 bucket_ranges->ResetChecksum(); | |
925 return bucket_ranges; | |
926 } | |
927 | |
928 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { | |
929 return new CustomHistogram(name_, ranges); | |
930 } | |
931 | |
932 const std::vector<Sample>* custom_ranges_; | |
933 }; | |
934 | |
768 HistogramBase* CustomHistogram::FactoryGet( | 935 HistogramBase* CustomHistogram::FactoryGet( |
769 const std::string& name, | 936 const std::string& name, |
770 const std::vector<Sample>& custom_ranges, | 937 const std::vector<Sample>& custom_ranges, |
771 int32 flags) { | 938 int32 flags) { |
772 CHECK(ValidateCustomRanges(custom_ranges)); | 939 CHECK(ValidateCustomRanges(custom_ranges)); |
773 | 940 |
774 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 941 return Factory(name, &custom_ranges, flags).Build(); |
775 if (!histogram) { | |
776 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | |
777 const BucketRanges* registered_ranges = | |
778 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
779 | |
780 // To avoid racy destruction at shutdown, the following will be leaked. | |
781 CustomHistogram* tentative_histogram = | |
782 new CustomHistogram(name, registered_ranges); | |
783 | |
784 tentative_histogram->SetFlags(flags); | |
785 | |
786 histogram = | |
787 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
788 } | |
789 | |
790 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | |
791 return histogram; | |
792 } | 942 } |
793 | 943 |
794 HistogramBase* CustomHistogram::FactoryGet( | 944 HistogramBase* CustomHistogram::FactoryGet( |
795 const char* name, | 945 const char* name, |
796 const std::vector<Sample>& custom_ranges, | 946 const std::vector<Sample>& custom_ranges, |
797 int32 flags) { | 947 int32 flags) { |
798 return FactoryGet(std::string(name), custom_ranges, flags); | 948 return FactoryGet(std::string(name), custom_ranges, flags); |
799 } | 949 } |
800 | 950 |
801 HistogramType CustomHistogram::GetHistogramType() const { | 951 HistogramType CustomHistogram::GetHistogramType() const { |
(...skipping 15 matching lines...) Expand all Loading... | |
817 return all_values; | 967 return all_values; |
818 } | 968 } |
819 | 969 |
820 CustomHistogram::CustomHistogram(const std::string& name, | 970 CustomHistogram::CustomHistogram(const std::string& name, |
821 const BucketRanges* ranges) | 971 const BucketRanges* ranges) |
822 : Histogram(name, | 972 : Histogram(name, |
823 ranges->range(1), | 973 ranges->range(1), |
824 ranges->range(ranges->bucket_count() - 1), | 974 ranges->range(ranges->bucket_count() - 1), |
825 ranges) {} | 975 ranges) {} |
826 | 976 |
977 CustomHistogram::CustomHistogram(const std::string& name, | |
978 const BucketRanges* ranges, | |
979 HistogramBase::AtomicCount* counts, | |
980 size_t counts_size, | |
981 HistogramSamples::Metadata* meta) | |
982 : Histogram(name, | |
983 ranges->range(1), | |
984 ranges->range(ranges->bucket_count() - 1), | |
985 ranges, | |
986 counts, | |
987 counts_size, | |
988 meta) {} | |
989 | |
827 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 990 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
828 if (!Histogram::SerializeInfoImpl(pickle)) | 991 if (!Histogram::SerializeInfoImpl(pickle)) |
829 return false; | 992 return false; |
830 | 993 |
831 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 994 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
832 // write them. | 995 // write them. |
833 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 996 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
834 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 997 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
835 return false; | 998 return false; |
836 } | 999 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
879 for (size_t i = 0; i < custom_ranges.size(); i++) { | 1042 for (size_t i = 0; i < custom_ranges.size(); i++) { |
880 Sample sample = custom_ranges[i]; | 1043 Sample sample = custom_ranges[i]; |
881 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1044 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
882 return false; | 1045 return false; |
883 if (sample != 0) | 1046 if (sample != 0) |
884 has_valid_range = true; | 1047 has_valid_range = true; |
885 } | 1048 } |
886 return has_valid_range; | 1049 return has_valid_range; |
887 } | 1050 } |
888 | 1051 |
889 // static | |
890 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( | |
891 const std::vector<Sample>& custom_ranges) { | |
892 // Remove the duplicates in the custom ranges array. | |
893 std::vector<int> ranges = custom_ranges; | |
894 ranges.push_back(0); // Ensure we have a zero value. | |
895 ranges.push_back(HistogramBase::kSampleType_MAX); | |
896 std::sort(ranges.begin(), ranges.end()); | |
897 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | |
898 | |
899 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | |
900 for (size_t i = 0; i < ranges.size(); i++) { | |
901 bucket_ranges->set_range(i, ranges[i]); | |
902 } | |
903 bucket_ranges->ResetChecksum(); | |
904 return bucket_ranges; | |
905 } | |
906 | |
907 } // namespace base | 1052 } // namespace base |
OLD | NEW |