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 <limits.h> | 12 #include <limits.h> |
13 #include <math.h> | 13 #include <math.h> |
14 | 14 |
15 #include <algorithm> | 15 #include <algorithm> |
16 #include <string> | 16 #include <string> |
17 | 17 |
18 #include "base/compiler_specific.h" | 18 #include "base/compiler_specific.h" |
19 #include "base/debug/alias.h" | 19 #include "base/debug/alias.h" |
20 #include "base/logging.h" | 20 #include "base/logging.h" |
21 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
| 22 #include "base/metrics/histogram_persistence.h" |
22 #include "base/metrics/metrics_hashes.h" | 23 #include "base/metrics/metrics_hashes.h" |
| 24 #include "base/metrics/persistent_memory_allocator.h" |
23 #include "base/metrics/sample_vector.h" | 25 #include "base/metrics/sample_vector.h" |
24 #include "base/metrics/statistics_recorder.h" | 26 #include "base/metrics/statistics_recorder.h" |
25 #include "base/pickle.h" | 27 #include "base/pickle.h" |
26 #include "base/strings/string_util.h" | 28 #include "base/strings/string_util.h" |
27 #include "base/strings/stringprintf.h" | 29 #include "base/strings/stringprintf.h" |
28 #include "base/synchronization/lock.h" | 30 #include "base/synchronization/lock.h" |
29 #include "base/values.h" | 31 #include "base/values.h" |
30 | 32 |
31 namespace base { | 33 namespace base { |
32 | 34 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 } | 79 } |
78 | 80 |
79 } // namespace | 81 } // namespace |
80 | 82 |
81 typedef HistogramBase::Count Count; | 83 typedef HistogramBase::Count Count; |
82 typedef HistogramBase::Sample Sample; | 84 typedef HistogramBase::Sample Sample; |
83 | 85 |
84 // static | 86 // static |
85 const size_t Histogram::kBucketCount_MAX = 16384u; | 87 const size_t Histogram::kBucketCount_MAX = 16384u; |
86 | 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_t flags) |
| 96 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {} |
| 97 |
| 98 // Create histogram based on construction parameters. Caller takes |
| 99 // ownership of the returned object. |
| 100 HistogramBase* Build(); |
| 101 |
| 102 protected: |
| 103 Factory(const std::string& name, |
| 104 HistogramType histogram_type, |
| 105 HistogramBase::Sample minimum, |
| 106 HistogramBase::Sample maximum, |
| 107 size_t bucket_count, |
| 108 int32_t flags) |
| 109 : name_(name), |
| 110 histogram_type_(histogram_type), |
| 111 minimum_(minimum), |
| 112 maximum_(maximum), |
| 113 bucket_count_(bucket_count), |
| 114 flags_(flags) {} |
| 115 |
| 116 // Create a BucketRanges structure appropriate for this histogram. |
| 117 virtual BucketRanges* CreateRanges() { |
| 118 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); |
| 119 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges); |
| 120 return ranges; |
| 121 } |
| 122 |
| 123 // Allocate the correct Histogram object off the heap (in case persistent |
| 124 // memory is not available). |
| 125 virtual HistogramBase* HeapAlloc(const BucketRanges* ranges) { |
| 126 return new Histogram(name_, minimum_, maximum_, ranges); |
| 127 } |
| 128 |
| 129 // Perform any required datafill on the just-created histogram. If |
| 130 // overridden, be sure to call the "super" version. |
| 131 virtual void FillHistogram(HistogramBase* histogram) { |
| 132 histogram->SetFlags(flags_); |
| 133 } |
| 134 |
| 135 // These values are protected (instead of private) because they need to |
| 136 // be accessible to methods of sub-classes in order to avoid passing |
| 137 // unnecessary parameters everywhere. |
| 138 const std::string& name_; |
| 139 const HistogramType histogram_type_; |
| 140 HistogramBase::Sample minimum_; |
| 141 HistogramBase::Sample maximum_; |
| 142 size_t bucket_count_; |
| 143 int32_t flags_; |
| 144 |
| 145 private: |
| 146 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 147 }; |
| 148 |
| 149 HistogramBase* Histogram::Factory::Build() { |
| 150 // Import histograms from known persistent storage. Histograms could have |
| 151 // been added by other processes and they must be fetched and recognized |
| 152 // locally in order to be found by FindHistograms() below. If the persistent |
| 153 // memory segment is not shared between processes, this call does nothing. |
| 154 ImportPersistentHistograms(); |
| 155 |
| 156 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); |
| 157 if (!histogram) { |
| 158 // To avoid racy destruction at shutdown, the following will be leaked. |
| 159 const BucketRanges* created_ranges = CreateRanges(); |
| 160 const BucketRanges* registered_ranges = |
| 161 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
| 162 |
| 163 // In most cases, the bucket-count, minimum, and maximum values are known |
| 164 // when the code is written and so are passed in explicitly. In other |
| 165 // cases (such as with a CustomHistogram), they are calculated dynamically |
| 166 // at run-time. In the latter case, those ctor parameters are zero and |
| 167 // the results extracted from the result of CreateRanges(). |
| 168 if (bucket_count_ == 0) { |
| 169 bucket_count_ = registered_ranges->bucket_count(); |
| 170 minimum_ = registered_ranges->range(1); |
| 171 maximum_ = registered_ranges->range(bucket_count_ - 1); |
| 172 } |
| 173 |
| 174 // Try to create the histogram using a "persistent" allocator. As of |
| 175 // 2015-01-14, the availability of such is controlled by a base::Feature |
| 176 // that is off by default. If the allocator doesn't exist or if |
| 177 // allocating from it fails, code below will allocate the histogram from |
| 178 // the process heap. |
| 179 PersistentMemoryAllocator::Reference histogram_ref = 0; |
| 180 HistogramBase* tentative_histogram = nullptr; |
| 181 PersistentMemoryAllocator* allocator = |
| 182 GetPersistentHistogramMemoryAllocator(); |
| 183 if (allocator) { |
| 184 flags_ |= HistogramBase::kIsPersistent; |
| 185 tentative_histogram = AllocatePersistentHistogram( |
| 186 allocator, |
| 187 histogram_type_, |
| 188 name_, |
| 189 minimum_, |
| 190 maximum_, |
| 191 registered_ranges, |
| 192 flags_, |
| 193 &histogram_ref); |
| 194 } |
| 195 |
| 196 // Handle the case where no persistent allocator is present or the |
| 197 // persistent allocation fails (perhaps because it is full). |
| 198 if (!tentative_histogram) { |
| 199 DCHECK(!histogram_ref); // Should never have been set. |
| 200 DCHECK(!allocator); // Shouldn't have failed. |
| 201 flags_ &= ~HistogramBase::kIsPersistent; |
| 202 tentative_histogram = HeapAlloc(registered_ranges); |
| 203 } |
| 204 |
| 205 FillHistogram(tentative_histogram); |
| 206 histogram = |
| 207 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 208 |
| 209 // Persistent histograms need some follow-up processing. |
| 210 if (histogram_ref) { |
| 211 FinalizePersistentHistogram(histogram_ref, |
| 212 histogram == tentative_histogram); |
| 213 } |
| 214 } |
| 215 |
| 216 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); |
| 217 if (bucket_count_ != 0 && |
| 218 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { |
| 219 // The construction arguments do not match the existing histogram. This can |
| 220 // come about if an extension updates in the middle of a chrome run and has |
| 221 // changed one of them, or simply by bad code within Chrome itself. We |
| 222 // return NULL here with the expectation that bad code in Chrome will crash |
| 223 // on dereference, but extension/Pepper APIs will guard against NULL and not |
| 224 // crash. |
| 225 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; |
| 226 return nullptr; |
| 227 } |
| 228 return histogram; |
| 229 } |
| 230 |
87 HistogramBase* Histogram::FactoryGet(const std::string& name, | 231 HistogramBase* Histogram::FactoryGet(const std::string& name, |
88 Sample minimum, | 232 Sample minimum, |
89 Sample maximum, | 233 Sample maximum, |
90 size_t bucket_count, | 234 size_t bucket_count, |
91 int32_t flags) { | 235 int32_t flags) { |
92 bool valid_arguments = | 236 bool valid_arguments = |
93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 237 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
94 DCHECK(valid_arguments); | 238 DCHECK(valid_arguments); |
95 | 239 |
96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 240 return Factory(name, minimum, maximum, bucket_count, flags).Build(); |
97 if (!histogram) { | |
98 // To avoid racy destruction at shutdown, the following will be leaked. | |
99 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
100 InitializeBucketRanges(minimum, maximum, ranges); | |
101 const BucketRanges* registered_ranges = | |
102 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
103 | |
104 Histogram* tentative_histogram = | |
105 new Histogram(name, minimum, maximum, registered_ranges); | |
106 | |
107 tentative_histogram->SetFlags(flags); | |
108 histogram = | |
109 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
110 } | |
111 | |
112 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | |
113 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
114 // The construction arguments do not match the existing histogram. This can | |
115 // come about if an extension updates in the middle of a chrome run and has | |
116 // changed one of them, or simply by bad code within Chrome itself. We | |
117 // return NULL here with the expectation that bad code in Chrome will crash | |
118 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
119 // crash. | |
120 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
121 return NULL; | |
122 } | |
123 return histogram; | |
124 } | 241 } |
125 | 242 |
126 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, | 243 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
127 TimeDelta minimum, | 244 TimeDelta minimum, |
128 TimeDelta maximum, | 245 TimeDelta maximum, |
129 size_t bucket_count, | 246 size_t bucket_count, |
130 int32_t flags) { | 247 int32_t flags) { |
131 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 248 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
132 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 249 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
133 flags); | 250 flags); |
134 } | 251 } |
135 | 252 |
136 HistogramBase* Histogram::FactoryGet(const char* name, | 253 HistogramBase* Histogram::FactoryGet(const char* name, |
137 Sample minimum, | 254 Sample minimum, |
138 Sample maximum, | 255 Sample maximum, |
139 size_t bucket_count, | 256 size_t bucket_count, |
140 int32_t flags) { | 257 int32_t flags) { |
141 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags); | 258 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags); |
142 } | 259 } |
143 | 260 |
144 HistogramBase* Histogram::FactoryTimeGet(const char* name, | 261 HistogramBase* Histogram::FactoryTimeGet(const char* name, |
145 TimeDelta minimum, | 262 TimeDelta minimum, |
146 TimeDelta maximum, | 263 TimeDelta maximum, |
147 size_t bucket_count, | 264 size_t bucket_count, |
148 int32_t flags) { | 265 int32_t flags) { |
149 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count, | 266 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count, |
150 flags); | 267 flags); |
151 } | 268 } |
152 | 269 |
| 270 HistogramBase* Histogram::PersistentGet(const std::string& name, |
| 271 Sample minimum, |
| 272 Sample maximum, |
| 273 const BucketRanges* ranges, |
| 274 HistogramBase::AtomicCount* counts, |
| 275 size_t counts_size, |
| 276 HistogramSamples::Metadata* meta) { |
| 277 return new Histogram(name, minimum, maximum, ranges, counts, counts_size, |
| 278 meta); |
| 279 } |
| 280 |
153 // Calculate what range of values are held in each bucket. | 281 // Calculate what range of values are held in each bucket. |
154 // We have to be careful that we don't pick a ratio between starting points in | 282 // We have to be careful that we don't pick a ratio between starting points in |
155 // consecutive buckets that is sooo small, that the integer bounds are the same | 283 // consecutive buckets that is sooo small, that the integer bounds are the same |
156 // (effectively making one bucket get no values). We need to avoid: | 284 // (effectively making one bucket get no values). We need to avoid: |
157 // ranges(i) == ranges(i + 1) | 285 // ranges(i) == ranges(i + 1) |
158 // To avoid that, we just do a fine-grained bucket width as far as we need to | 286 // To avoid that, we just do a fine-grained bucket width as far as we need to |
159 // until we get a ratio that moves us along at least 2 units at a time. From | 287 // until we get a ratio that moves us along at least 2 units at a time. From |
160 // that bucket onward we do use the exponential growth of buckets. | 288 // that bucket onward we do use the exponential growth of buckets. |
161 // | 289 // |
162 // static | 290 // static |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 Sample maximum, | 465 Sample maximum, |
338 const BucketRanges* ranges) | 466 const BucketRanges* ranges) |
339 : HistogramBase(name), | 467 : HistogramBase(name), |
340 bucket_ranges_(ranges), | 468 bucket_ranges_(ranges), |
341 declared_min_(minimum), | 469 declared_min_(minimum), |
342 declared_max_(maximum) { | 470 declared_max_(maximum) { |
343 if (ranges) | 471 if (ranges) |
344 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 472 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
345 } | 473 } |
346 | 474 |
| 475 Histogram::Histogram(const std::string& name, |
| 476 Sample minimum, |
| 477 Sample maximum, |
| 478 const BucketRanges* ranges, |
| 479 HistogramBase::AtomicCount* counts, |
| 480 size_t counts_size, |
| 481 HistogramSamples::Metadata* meta) |
| 482 : HistogramBase(name), |
| 483 bucket_ranges_(ranges), |
| 484 declared_min_(minimum), |
| 485 declared_max_(maximum) { |
| 486 if (ranges) { |
| 487 samples_.reset(new SampleVector(HashMetricName(name), |
| 488 counts, counts_size, meta, ranges)); |
| 489 } |
| 490 } |
| 491 |
347 Histogram::~Histogram() { | 492 Histogram::~Histogram() { |
348 } | 493 } |
349 | 494 |
350 bool Histogram::PrintEmptyBucket(size_t index) const { | 495 bool Histogram::PrintEmptyBucket(size_t index) const { |
351 return true; | 496 return true; |
352 } | 497 } |
353 | 498 |
354 // Use the actual bucket widths (like a linear histogram) until the widths get | 499 // Use the actual bucket widths (like a linear histogram) until the widths get |
355 // over some transition value, and then use that transition width. Exponentials | 500 // over some transition value, and then use that transition width. Exponentials |
356 // get so big so fast (and we don't expect to see a lot of entries in the large | 501 // 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... |
538 ++index; | 683 ++index; |
539 } | 684 } |
540 } | 685 } |
541 } | 686 } |
542 | 687 |
543 //------------------------------------------------------------------------------ | 688 //------------------------------------------------------------------------------ |
544 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 689 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
545 // buckets. | 690 // buckets. |
546 //------------------------------------------------------------------------------ | 691 //------------------------------------------------------------------------------ |
547 | 692 |
| 693 class LinearHistogram::Factory : public Histogram::Factory { |
| 694 public: |
| 695 Factory(const std::string& name, |
| 696 HistogramBase::Sample minimum, |
| 697 HistogramBase::Sample maximum, |
| 698 size_t bucket_count, |
| 699 int32_t flags, |
| 700 const DescriptionPair* descriptions) |
| 701 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum, |
| 702 bucket_count, flags) { |
| 703 descriptions_ = descriptions; |
| 704 } |
| 705 |
| 706 protected: |
| 707 BucketRanges* CreateRanges() override { |
| 708 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); |
| 709 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges); |
| 710 return ranges; |
| 711 } |
| 712 |
| 713 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 714 return new LinearHistogram(name_, minimum_, maximum_, ranges); |
| 715 } |
| 716 |
| 717 void FillHistogram(HistogramBase* base_histogram) override { |
| 718 Histogram::Factory::FillHistogram(base_histogram); |
| 719 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram); |
| 720 // Set range descriptions. |
| 721 if (descriptions_) { |
| 722 for (int i = 0; descriptions_[i].description; ++i) { |
| 723 histogram->bucket_description_[descriptions_[i].sample] = |
| 724 descriptions_[i].description; |
| 725 } |
| 726 } |
| 727 } |
| 728 |
| 729 private: |
| 730 const DescriptionPair* descriptions_; |
| 731 |
| 732 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 733 }; |
| 734 |
548 LinearHistogram::~LinearHistogram() {} | 735 LinearHistogram::~LinearHistogram() {} |
549 | 736 |
550 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, | 737 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, |
551 Sample minimum, | 738 Sample minimum, |
552 Sample maximum, | 739 Sample maximum, |
553 size_t bucket_count, | 740 size_t bucket_count, |
554 int32_t flags) { | 741 int32_t flags) { |
555 return FactoryGetWithRangeDescription( | 742 return FactoryGetWithRangeDescription( |
556 name, minimum, maximum, bucket_count, flags, NULL); | 743 name, minimum, maximum, bucket_count, flags, NULL); |
557 } | 744 } |
(...skipping 18 matching lines...) Expand all Loading... |
576 | 763 |
577 HistogramBase* LinearHistogram::FactoryTimeGet(const char* name, | 764 HistogramBase* LinearHistogram::FactoryTimeGet(const char* name, |
578 TimeDelta minimum, | 765 TimeDelta minimum, |
579 TimeDelta maximum, | 766 TimeDelta maximum, |
580 size_t bucket_count, | 767 size_t bucket_count, |
581 int32_t flags) { | 768 int32_t flags) { |
582 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count, | 769 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count, |
583 flags); | 770 flags); |
584 } | 771 } |
585 | 772 |
| 773 HistogramBase* LinearHistogram::PersistentGet( |
| 774 const std::string& name, |
| 775 Sample minimum, |
| 776 Sample maximum, |
| 777 const BucketRanges* ranges, |
| 778 HistogramBase::AtomicCount* counts, |
| 779 size_t counts_size, |
| 780 HistogramSamples::Metadata* meta) { |
| 781 return new LinearHistogram(name, minimum, maximum, ranges, counts, |
| 782 counts_size, meta); |
| 783 } |
| 784 |
586 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( | 785 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( |
587 const std::string& name, | 786 const std::string& name, |
588 Sample minimum, | 787 Sample minimum, |
589 Sample maximum, | 788 Sample maximum, |
590 size_t bucket_count, | 789 size_t bucket_count, |
591 int32_t flags, | 790 int32_t flags, |
592 const DescriptionPair descriptions[]) { | 791 const DescriptionPair descriptions[]) { |
593 bool valid_arguments = Histogram::InspectConstructionArguments( | 792 bool valid_arguments = Histogram::InspectConstructionArguments( |
594 name, &minimum, &maximum, &bucket_count); | 793 name, &minimum, &maximum, &bucket_count); |
595 DCHECK(valid_arguments); | 794 DCHECK(valid_arguments); |
596 | 795 |
597 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 796 return Factory(name, minimum, maximum, bucket_count, flags, descriptions) |
598 if (!histogram) { | 797 .Build(); |
599 // To avoid racy destruction at shutdown, the following will be leaked. | |
600 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
601 InitializeBucketRanges(minimum, maximum, ranges); | |
602 const BucketRanges* registered_ranges = | |
603 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
604 | |
605 LinearHistogram* tentative_histogram = | |
606 new LinearHistogram(name, minimum, maximum, registered_ranges); | |
607 | |
608 // Set range descriptions. | |
609 if (descriptions) { | |
610 for (int i = 0; descriptions[i].description; ++i) { | |
611 tentative_histogram->bucket_description_[descriptions[i].sample] = | |
612 descriptions[i].description; | |
613 } | |
614 } | |
615 | |
616 tentative_histogram->SetFlags(flags); | |
617 histogram = | |
618 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
619 } | |
620 | |
621 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | |
622 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
623 // The construction arguments do not match the existing histogram. This can | |
624 // come about if an extension updates in the middle of a chrome run and has | |
625 // changed one of them, or simply by bad code within Chrome itself. We | |
626 // return NULL here with the expectation that bad code in Chrome will crash | |
627 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
628 // crash. | |
629 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
630 return NULL; | |
631 } | |
632 return histogram; | |
633 } | 798 } |
634 | 799 |
635 HistogramType LinearHistogram::GetHistogramType() const { | 800 HistogramType LinearHistogram::GetHistogramType() const { |
636 return LINEAR_HISTOGRAM; | 801 return LINEAR_HISTOGRAM; |
637 } | 802 } |
638 | 803 |
639 LinearHistogram::LinearHistogram(const std::string& name, | 804 LinearHistogram::LinearHistogram(const std::string& name, |
640 Sample minimum, | 805 Sample minimum, |
641 Sample maximum, | 806 Sample maximum, |
642 const BucketRanges* ranges) | 807 const BucketRanges* ranges) |
643 : Histogram(name, minimum, maximum, ranges) { | 808 : Histogram(name, minimum, maximum, ranges) { |
644 } | 809 } |
645 | 810 |
| 811 LinearHistogram::LinearHistogram(const std::string& name, |
| 812 Sample minimum, |
| 813 Sample maximum, |
| 814 const BucketRanges* ranges, |
| 815 HistogramBase::AtomicCount* counts, |
| 816 size_t counts_size, |
| 817 HistogramSamples::Metadata* meta) |
| 818 : Histogram(name, |
| 819 minimum, |
| 820 maximum, |
| 821 ranges, |
| 822 counts, |
| 823 counts_size, |
| 824 meta) {} |
| 825 |
646 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 826 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
647 DCHECK_GT(ranges(i + 1), ranges(i)); | 827 DCHECK_GT(ranges(i + 1), ranges(i)); |
648 // Adjacent buckets with different widths would have "surprisingly" many (few) | 828 // Adjacent buckets with different widths would have "surprisingly" many (few) |
649 // samples in a histogram if we didn't normalize this way. | 829 // samples in a histogram if we didn't normalize this way. |
650 double denominator = ranges(i + 1) - ranges(i); | 830 double denominator = ranges(i + 1) - ranges(i); |
651 return current/denominator; | 831 return current/denominator; |
652 } | 832 } |
653 | 833 |
654 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 834 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
655 int range = ranges(i); | 835 int range = ranges(i); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 // The serialized histogram might be corrupted. | 879 // The serialized histogram might be corrupted. |
700 return NULL; | 880 return NULL; |
701 } | 881 } |
702 return histogram; | 882 return histogram; |
703 } | 883 } |
704 | 884 |
705 //------------------------------------------------------------------------------ | 885 //------------------------------------------------------------------------------ |
706 // This section provides implementation for BooleanHistogram. | 886 // This section provides implementation for BooleanHistogram. |
707 //------------------------------------------------------------------------------ | 887 //------------------------------------------------------------------------------ |
708 | 888 |
| 889 class BooleanHistogram::Factory : public Histogram::Factory { |
| 890 public: |
| 891 Factory(const std::string& name, int32_t flags) |
| 892 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {} |
| 893 |
| 894 protected: |
| 895 BucketRanges* CreateRanges() override { |
| 896 BucketRanges* ranges = new BucketRanges(3 + 1); |
| 897 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
| 898 return ranges; |
| 899 } |
| 900 |
| 901 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 902 return new BooleanHistogram(name_, ranges); |
| 903 } |
| 904 |
| 905 private: |
| 906 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 907 }; |
| 908 |
709 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, | 909 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
710 int32_t flags) { | 910 int32_t flags) { |
711 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 911 return Factory(name, flags).Build(); |
712 if (!histogram) { | |
713 // To avoid racy destruction at shutdown, the following will be leaked. | |
714 BucketRanges* ranges = new BucketRanges(4); | |
715 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | |
716 const BucketRanges* registered_ranges = | |
717 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
718 | |
719 BooleanHistogram* tentative_histogram = | |
720 new BooleanHistogram(name, registered_ranges); | |
721 | |
722 tentative_histogram->SetFlags(flags); | |
723 histogram = | |
724 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
725 } | |
726 | |
727 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | |
728 return histogram; | |
729 } | 912 } |
730 | 913 |
731 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) { | 914 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) { |
732 return FactoryGet(std::string(name), flags); | 915 return FactoryGet(std::string(name), flags); |
733 } | 916 } |
734 | 917 |
| 918 HistogramBase* BooleanHistogram::PersistentGet( |
| 919 const std::string& name, |
| 920 const BucketRanges* ranges, |
| 921 HistogramBase::AtomicCount* counts, |
| 922 HistogramSamples::Metadata* meta) { |
| 923 return new BooleanHistogram(name, ranges, counts, meta); |
| 924 } |
| 925 |
735 HistogramType BooleanHistogram::GetHistogramType() const { | 926 HistogramType BooleanHistogram::GetHistogramType() const { |
736 return BOOLEAN_HISTOGRAM; | 927 return BOOLEAN_HISTOGRAM; |
737 } | 928 } |
738 | 929 |
739 BooleanHistogram::BooleanHistogram(const std::string& name, | 930 BooleanHistogram::BooleanHistogram(const std::string& name, |
740 const BucketRanges* ranges) | 931 const BucketRanges* ranges) |
741 : LinearHistogram(name, 1, 2, ranges) {} | 932 : LinearHistogram(name, 1, 2, ranges) {} |
742 | 933 |
| 934 BooleanHistogram::BooleanHistogram(const std::string& name, |
| 935 const BucketRanges* ranges, |
| 936 HistogramBase::AtomicCount* counts, |
| 937 HistogramSamples::Metadata* meta) |
| 938 : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {} |
| 939 |
743 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 940 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
744 std::string histogram_name; | 941 std::string histogram_name; |
745 int flags; | 942 int flags; |
746 int declared_min; | 943 int declared_min; |
747 int declared_max; | 944 int declared_max; |
748 size_t bucket_count; | 945 size_t bucket_count; |
749 uint32_t range_checksum; | 946 uint32_t range_checksum; |
750 | 947 |
751 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 948 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
752 &declared_max, &bucket_count, &range_checksum)) { | 949 &declared_max, &bucket_count, &range_checksum)) { |
753 return NULL; | 950 return NULL; |
754 } | 951 } |
755 | 952 |
756 HistogramBase* histogram = BooleanHistogram::FactoryGet( | 953 HistogramBase* histogram = BooleanHistogram::FactoryGet( |
757 histogram_name, flags); | 954 histogram_name, flags); |
758 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 955 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
759 // The serialized histogram might be corrupted. | 956 // The serialized histogram might be corrupted. |
760 return NULL; | 957 return NULL; |
761 } | 958 } |
762 return histogram; | 959 return histogram; |
763 } | 960 } |
764 | 961 |
765 //------------------------------------------------------------------------------ | 962 //------------------------------------------------------------------------------ |
766 // CustomHistogram: | 963 // CustomHistogram: |
767 //------------------------------------------------------------------------------ | 964 //------------------------------------------------------------------------------ |
768 | 965 |
| 966 class CustomHistogram::Factory : public Histogram::Factory { |
| 967 public: |
| 968 Factory(const std::string& name, |
| 969 const std::vector<Sample>* custom_ranges, |
| 970 int32_t flags) |
| 971 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) { |
| 972 custom_ranges_ = custom_ranges; |
| 973 } |
| 974 |
| 975 protected: |
| 976 BucketRanges* CreateRanges() override { |
| 977 // Remove the duplicates in the custom ranges array. |
| 978 std::vector<int> ranges = *custom_ranges_; |
| 979 ranges.push_back(0); // Ensure we have a zero value. |
| 980 ranges.push_back(HistogramBase::kSampleType_MAX); |
| 981 std::sort(ranges.begin(), ranges.end()); |
| 982 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
| 983 |
| 984 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
| 985 for (size_t i = 0; i < ranges.size(); i++) { |
| 986 bucket_ranges->set_range(i, ranges[i]); |
| 987 } |
| 988 bucket_ranges->ResetChecksum(); |
| 989 return bucket_ranges; |
| 990 } |
| 991 |
| 992 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 993 return new CustomHistogram(name_, ranges); |
| 994 } |
| 995 |
| 996 private: |
| 997 const std::vector<Sample>* custom_ranges_; |
| 998 |
| 999 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 1000 }; |
| 1001 |
769 HistogramBase* CustomHistogram::FactoryGet( | 1002 HistogramBase* CustomHistogram::FactoryGet( |
770 const std::string& name, | 1003 const std::string& name, |
771 const std::vector<Sample>& custom_ranges, | 1004 const std::vector<Sample>& custom_ranges, |
772 int32_t flags) { | 1005 int32_t flags) { |
773 CHECK(ValidateCustomRanges(custom_ranges)); | 1006 CHECK(ValidateCustomRanges(custom_ranges)); |
774 | 1007 |
775 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 1008 return Factory(name, &custom_ranges, flags).Build(); |
776 if (!histogram) { | |
777 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | |
778 const BucketRanges* registered_ranges = | |
779 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
780 | |
781 // To avoid racy destruction at shutdown, the following will be leaked. | |
782 CustomHistogram* tentative_histogram = | |
783 new CustomHistogram(name, registered_ranges); | |
784 | |
785 tentative_histogram->SetFlags(flags); | |
786 | |
787 histogram = | |
788 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
789 } | |
790 | |
791 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | |
792 return histogram; | |
793 } | 1009 } |
794 | 1010 |
795 HistogramBase* CustomHistogram::FactoryGet( | 1011 HistogramBase* CustomHistogram::FactoryGet( |
796 const char* name, | 1012 const char* name, |
797 const std::vector<Sample>& custom_ranges, | 1013 const std::vector<Sample>& custom_ranges, |
798 int32_t flags) { | 1014 int32_t flags) { |
799 return FactoryGet(std::string(name), custom_ranges, flags); | 1015 return FactoryGet(std::string(name), custom_ranges, flags); |
800 } | 1016 } |
801 | 1017 |
| 1018 HistogramBase* CustomHistogram::PersistentGet( |
| 1019 const std::string& name, |
| 1020 const BucketRanges* ranges, |
| 1021 HistogramBase::AtomicCount* counts, |
| 1022 size_t counts_size, |
| 1023 HistogramSamples::Metadata* meta) { |
| 1024 return new CustomHistogram(name, ranges, counts, counts_size, meta); |
| 1025 } |
| 1026 |
802 HistogramType CustomHistogram::GetHistogramType() const { | 1027 HistogramType CustomHistogram::GetHistogramType() const { |
803 return CUSTOM_HISTOGRAM; | 1028 return CUSTOM_HISTOGRAM; |
804 } | 1029 } |
805 | 1030 |
806 // static | 1031 // static |
807 std::vector<Sample> CustomHistogram::ArrayToCustomRanges( | 1032 std::vector<Sample> CustomHistogram::ArrayToCustomRanges( |
808 const Sample* values, size_t num_values) { | 1033 const Sample* values, size_t num_values) { |
809 std::vector<Sample> all_values; | 1034 std::vector<Sample> all_values; |
810 for (size_t i = 0; i < num_values; ++i) { | 1035 for (size_t i = 0; i < num_values; ++i) { |
811 Sample value = values[i]; | 1036 Sample value = values[i]; |
812 all_values.push_back(value); | 1037 all_values.push_back(value); |
813 | 1038 |
814 // Ensure that a guard bucket is added. If we end up with duplicate | 1039 // Ensure that a guard bucket is added. If we end up with duplicate |
815 // values, FactoryGet will take care of removing them. | 1040 // values, FactoryGet will take care of removing them. |
816 all_values.push_back(value + 1); | 1041 all_values.push_back(value + 1); |
817 } | 1042 } |
818 return all_values; | 1043 return all_values; |
819 } | 1044 } |
820 | 1045 |
821 CustomHistogram::CustomHistogram(const std::string& name, | 1046 CustomHistogram::CustomHistogram(const std::string& name, |
822 const BucketRanges* ranges) | 1047 const BucketRanges* ranges) |
823 : Histogram(name, | 1048 : Histogram(name, |
824 ranges->range(1), | 1049 ranges->range(1), |
825 ranges->range(ranges->bucket_count() - 1), | 1050 ranges->range(ranges->bucket_count() - 1), |
826 ranges) {} | 1051 ranges) {} |
827 | 1052 |
| 1053 CustomHistogram::CustomHistogram(const std::string& name, |
| 1054 const BucketRanges* ranges, |
| 1055 HistogramBase::AtomicCount* counts, |
| 1056 size_t counts_size, |
| 1057 HistogramSamples::Metadata* meta) |
| 1058 : Histogram(name, |
| 1059 ranges->range(1), |
| 1060 ranges->range(ranges->bucket_count() - 1), |
| 1061 ranges, |
| 1062 counts, |
| 1063 counts_size, |
| 1064 meta) {} |
| 1065 |
828 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 1066 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
829 if (!Histogram::SerializeInfoImpl(pickle)) | 1067 if (!Histogram::SerializeInfoImpl(pickle)) |
830 return false; | 1068 return false; |
831 | 1069 |
832 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 1070 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
833 // write them. | 1071 // write them. |
834 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 1072 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
835 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 1073 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
836 return false; | 1074 return false; |
837 } | 1075 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
880 for (size_t i = 0; i < custom_ranges.size(); i++) { | 1118 for (size_t i = 0; i < custom_ranges.size(); i++) { |
881 Sample sample = custom_ranges[i]; | 1119 Sample sample = custom_ranges[i]; |
882 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1120 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
883 return false; | 1121 return false; |
884 if (sample != 0) | 1122 if (sample != 0) |
885 has_valid_range = true; | 1123 has_valid_range = true; |
886 } | 1124 } |
887 return has_valid_range; | 1125 return has_valid_range; |
888 } | 1126 } |
889 | 1127 |
890 // static | |
891 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( | |
892 const std::vector<Sample>& custom_ranges) { | |
893 // Remove the duplicates in the custom ranges array. | |
894 std::vector<int> ranges = custom_ranges; | |
895 ranges.push_back(0); // Ensure we have a zero value. | |
896 ranges.push_back(HistogramBase::kSampleType_MAX); | |
897 std::sort(ranges.begin(), ranges.end()); | |
898 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | |
899 | |
900 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | |
901 for (size_t i = 0; i < ranges.size(); i++) { | |
902 bucket_ranges->set_range(i, ranges[i]); | |
903 } | |
904 bucket_ranges->ResetChecksum(); | |
905 return bucket_ranges; | |
906 } | |
907 | |
908 } // namespace base | 1128 } // namespace base |
OLD | NEW |