| 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 |
| 90 class Histogram::Factory { |
| 91 public: |
| 92 Factory(const std::string& name, |
| 93 HistogramBase::Sample minimum, |
| 94 HistogramBase::Sample maximum, |
| 95 size_t bucket_count, |
| 96 int32_t flags) |
| 97 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {} |
| 98 |
| 99 HistogramBase* Build(); |
| 100 |
| 101 protected: |
| 102 Factory(const std::string& name, |
| 103 HistogramType histogram_type, |
| 104 HistogramBase::Sample minimum, |
| 105 HistogramBase::Sample maximum, |
| 106 size_t bucket_count, |
| 107 int32_t flags) |
| 108 : name_(name), |
| 109 histogram_type_(histogram_type), |
| 110 minimum_(minimum), |
| 111 maximum_(maximum), |
| 112 bucket_count_(bucket_count), |
| 113 flags_(flags) {} |
| 114 |
| 115 // Create a BucketRanges structure appropriate for this histogram. |
| 116 virtual BucketRanges* CreateRanges() { |
| 117 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); |
| 118 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges); |
| 119 return ranges; |
| 120 } |
| 121 |
| 122 // Allocate the correct Histogram object off the heap (in case persistent |
| 123 // memory is not available). |
| 124 virtual HistogramBase* HeapAlloc(const BucketRanges* ranges) { |
| 125 return new Histogram(name_, minimum_, maximum_, ranges); |
| 126 } |
| 127 |
| 128 // Perform any required datafill on the just-created histogram. If |
| 129 // overridden, be sure to call the "super" version. |
| 130 virtual void FillHistogram(HistogramBase* histogram) { |
| 131 histogram->SetFlags(flags_); |
| 132 } |
| 133 |
| 134 // These values are protected (instead of private) because they need to |
| 135 // be accessible to methods of sub-classes in order to avoid passing |
| 136 // unnecessary parameters everywhere. |
| 137 const std::string& name_; |
| 138 const HistogramType histogram_type_; |
| 139 HistogramBase::Sample minimum_; |
| 140 HistogramBase::Sample maximum_; |
| 141 size_t bucket_count_; |
| 142 int32_t flags_; |
| 143 |
| 144 private: |
| 145 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 146 }; |
| 147 |
| 148 HistogramBase* Histogram::Factory::Build() { |
| 149 ImportPersistentHistograms(); |
| 150 |
| 151 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); |
| 152 if (!histogram) { |
| 153 // To avoid racy destruction at shutdown, the following will be leaked. |
| 154 const BucketRanges* created_ranges = CreateRanges(); |
| 155 const BucketRanges* registered_ranges = |
| 156 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
| 157 |
| 158 // Sometimes the bucket info is dynamically determined in CreateRanges(). |
| 159 if (bucket_count_ == 0) { |
| 160 bucket_count_ = registered_ranges->bucket_count(); |
| 161 minimum_ = registered_ranges->range(1); |
| 162 maximum_ = registered_ranges->range(bucket_count_ - 1); |
| 163 } |
| 164 |
| 165 PersistentMemoryAllocator::Reference histogram_ref = 0; |
| 166 HistogramBase* tentative_histogram = nullptr; |
| 167 PersistentMemoryAllocator* allocator = |
| 168 GetPersistentHistogramMemoryAllocator(); |
| 169 if (allocator) { |
| 170 flags_ |= HistogramBase::kIsPersistent; |
| 171 tentative_histogram = AllocatePersistentHistogram( |
| 172 allocator, |
| 173 histogram_type_, |
| 174 name_, |
| 175 minimum_, |
| 176 maximum_, |
| 177 registered_ranges, |
| 178 flags_, |
| 179 &histogram_ref); |
| 180 } |
| 181 |
| 182 // Handle the case where no persistent allocator is present or the |
| 183 // persistent allocation fails (perhaps because it is full). |
| 184 if (!tentative_histogram) { |
| 185 DCHECK(!histogram_ref); // Should never have been set. |
| 186 DCHECK(!allocator); // Shouldn't have failed. |
| 187 flags_ &= ~HistogramBase::kIsPersistent; |
| 188 tentative_histogram = HeapAlloc(registered_ranges); |
| 189 } |
| 190 |
| 191 FillHistogram(tentative_histogram); |
| 192 histogram = |
| 193 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 194 |
| 195 // Persistent histograms need some follow-up processing. |
| 196 if (histogram_ref) { |
| 197 FinalizePersistentHistogram(histogram_ref, |
| 198 histogram == tentative_histogram); |
| 199 } |
| 200 } |
| 201 |
| 202 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); |
| 203 if (bucket_count_ != 0 && |
| 204 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { |
| 205 // The construction arguments do not match the existing histogram. This can |
| 206 // come about if an extension updates in the middle of a chrome run and has |
| 207 // changed one of them, or simply by bad code within Chrome itself. We |
| 208 // return NULL here with the expectation that bad code in Chrome will crash |
| 209 // on dereference, but extension/Pepper APIs will guard against NULL and not |
| 210 // crash. |
| 211 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; |
| 212 return nullptr; |
| 213 } |
| 214 return histogram; |
| 215 } |
| 216 |
| 217 |
| 87 HistogramBase* Histogram::FactoryGet(const std::string& name, | 218 HistogramBase* Histogram::FactoryGet(const std::string& name, |
| 88 Sample minimum, | 219 Sample minimum, |
| 89 Sample maximum, | 220 Sample maximum, |
| 90 size_t bucket_count, | 221 size_t bucket_count, |
| 91 int32_t flags) { | 222 int32_t flags) { |
| 92 bool valid_arguments = | 223 bool valid_arguments = |
| 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 224 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
| 94 DCHECK(valid_arguments); | 225 DCHECK(valid_arguments); |
| 95 | 226 |
| 96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 227 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 } | 228 } |
| 125 | 229 |
| 126 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, | 230 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
| 127 TimeDelta minimum, | 231 TimeDelta minimum, |
| 128 TimeDelta maximum, | 232 TimeDelta maximum, |
| 129 size_t bucket_count, | 233 size_t bucket_count, |
| 130 int32_t flags) { | 234 int32_t flags) { |
| 131 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 235 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
| 132 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 236 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
| 133 flags); | 237 flags); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 Sample maximum, | 441 Sample maximum, |
| 338 const BucketRanges* ranges) | 442 const BucketRanges* ranges) |
| 339 : HistogramBase(name), | 443 : HistogramBase(name), |
| 340 bucket_ranges_(ranges), | 444 bucket_ranges_(ranges), |
| 341 declared_min_(minimum), | 445 declared_min_(minimum), |
| 342 declared_max_(maximum) { | 446 declared_max_(maximum) { |
| 343 if (ranges) | 447 if (ranges) |
| 344 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 448 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
| 345 } | 449 } |
| 346 | 450 |
| 451 Histogram::Histogram(const std::string& name, |
| 452 Sample minimum, |
| 453 Sample maximum, |
| 454 const BucketRanges* ranges, |
| 455 HistogramBase::AtomicCount* counts, |
| 456 size_t counts_size, |
| 457 HistogramSamples::Metadata* meta) |
| 458 : HistogramBase(name), |
| 459 bucket_ranges_(ranges), |
| 460 declared_min_(minimum), |
| 461 declared_max_(maximum) { |
| 462 if (ranges) |
| 463 samples_.reset(new SampleVector(HashMetricName(name), |
| 464 counts, counts_size, meta, ranges)); |
| 465 } |
| 466 |
| 347 Histogram::~Histogram() { | 467 Histogram::~Histogram() { |
| 348 } | 468 } |
| 349 | 469 |
| 350 bool Histogram::PrintEmptyBucket(size_t index) const { | 470 bool Histogram::PrintEmptyBucket(size_t index) const { |
| 351 return true; | 471 return true; |
| 352 } | 472 } |
| 353 | 473 |
| 354 // Use the actual bucket widths (like a linear histogram) until the widths get | 474 // 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 | 475 // 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 | 476 // 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; | 658 ++index; |
| 539 } | 659 } |
| 540 } | 660 } |
| 541 } | 661 } |
| 542 | 662 |
| 543 //------------------------------------------------------------------------------ | 663 //------------------------------------------------------------------------------ |
| 544 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 664 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
| 545 // buckets. | 665 // buckets. |
| 546 //------------------------------------------------------------------------------ | 666 //------------------------------------------------------------------------------ |
| 547 | 667 |
| 668 class LinearHistogram::Factory : public Histogram::Factory { |
| 669 public: |
| 670 Factory(const std::string& name, |
| 671 HistogramBase::Sample minimum, |
| 672 HistogramBase::Sample maximum, |
| 673 size_t bucket_count, |
| 674 int32_t flags, |
| 675 const DescriptionPair* descriptions) |
| 676 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum, |
| 677 bucket_count, flags) { |
| 678 descriptions_ = descriptions; |
| 679 } |
| 680 |
| 681 protected: |
| 682 BucketRanges* CreateRanges() override { |
| 683 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); |
| 684 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges); |
| 685 return ranges; |
| 686 } |
| 687 |
| 688 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 689 return new LinearHistogram(name_, minimum_, maximum_, ranges); |
| 690 } |
| 691 |
| 692 void FillHistogram(HistogramBase* base_histogram) override { |
| 693 Histogram::Factory::FillHistogram(base_histogram); |
| 694 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram); |
| 695 // Set range descriptions. |
| 696 if (descriptions_) { |
| 697 for (int i = 0; descriptions_[i].description; ++i) { |
| 698 histogram->bucket_description_[descriptions_[i].sample] = |
| 699 descriptions_[i].description; |
| 700 } |
| 701 } |
| 702 } |
| 703 |
| 704 private: |
| 705 const DescriptionPair* descriptions_; |
| 706 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 707 }; |
| 708 |
| 548 LinearHistogram::~LinearHistogram() {} | 709 LinearHistogram::~LinearHistogram() {} |
| 549 | 710 |
| 550 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, | 711 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, |
| 551 Sample minimum, | 712 Sample minimum, |
| 552 Sample maximum, | 713 Sample maximum, |
| 553 size_t bucket_count, | 714 size_t bucket_count, |
| 554 int32_t flags) { | 715 int32_t flags) { |
| 555 return FactoryGetWithRangeDescription( | 716 return FactoryGetWithRangeDescription( |
| 556 name, minimum, maximum, bucket_count, flags, NULL); | 717 name, minimum, maximum, bucket_count, flags, NULL); |
| 557 } | 718 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 587 const std::string& name, | 748 const std::string& name, |
| 588 Sample minimum, | 749 Sample minimum, |
| 589 Sample maximum, | 750 Sample maximum, |
| 590 size_t bucket_count, | 751 size_t bucket_count, |
| 591 int32_t flags, | 752 int32_t flags, |
| 592 const DescriptionPair descriptions[]) { | 753 const DescriptionPair descriptions[]) { |
| 593 bool valid_arguments = Histogram::InspectConstructionArguments( | 754 bool valid_arguments = Histogram::InspectConstructionArguments( |
| 594 name, &minimum, &maximum, &bucket_count); | 755 name, &minimum, &maximum, &bucket_count); |
| 595 DCHECK(valid_arguments); | 756 DCHECK(valid_arguments); |
| 596 | 757 |
| 597 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 758 return Factory(name, minimum, maximum, bucket_count, flags, descriptions) |
| 598 if (!histogram) { | 759 .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 } | 760 } |
| 634 | 761 |
| 635 HistogramType LinearHistogram::GetHistogramType() const { | 762 HistogramType LinearHistogram::GetHistogramType() const { |
| 636 return LINEAR_HISTOGRAM; | 763 return LINEAR_HISTOGRAM; |
| 637 } | 764 } |
| 638 | 765 |
| 639 LinearHistogram::LinearHistogram(const std::string& name, | 766 LinearHistogram::LinearHistogram(const std::string& name, |
| 640 Sample minimum, | 767 Sample minimum, |
| 641 Sample maximum, | 768 Sample maximum, |
| 642 const BucketRanges* ranges) | 769 const BucketRanges* ranges) |
| 643 : Histogram(name, minimum, maximum, ranges) { | 770 : Histogram(name, minimum, maximum, ranges) { |
| 644 } | 771 } |
| 645 | 772 |
| 773 LinearHistogram::LinearHistogram(const std::string& name, |
| 774 Sample minimum, |
| 775 Sample maximum, |
| 776 const BucketRanges* ranges, |
| 777 HistogramBase::AtomicCount* counts, |
| 778 size_t counts_size, |
| 779 HistogramSamples::Metadata* meta) |
| 780 : Histogram(name, |
| 781 minimum, |
| 782 maximum, |
| 783 ranges, |
| 784 counts, |
| 785 counts_size, |
| 786 meta) {} |
| 787 |
| 646 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 788 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
| 647 DCHECK_GT(ranges(i + 1), ranges(i)); | 789 DCHECK_GT(ranges(i + 1), ranges(i)); |
| 648 // Adjacent buckets with different widths would have "surprisingly" many (few) | 790 // Adjacent buckets with different widths would have "surprisingly" many (few) |
| 649 // samples in a histogram if we didn't normalize this way. | 791 // samples in a histogram if we didn't normalize this way. |
| 650 double denominator = ranges(i + 1) - ranges(i); | 792 double denominator = ranges(i + 1) - ranges(i); |
| 651 return current/denominator; | 793 return current/denominator; |
| 652 } | 794 } |
| 653 | 795 |
| 654 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 796 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
| 655 int range = ranges(i); | 797 int range = ranges(i); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 // The serialized histogram might be corrupted. | 841 // The serialized histogram might be corrupted. |
| 700 return NULL; | 842 return NULL; |
| 701 } | 843 } |
| 702 return histogram; | 844 return histogram; |
| 703 } | 845 } |
| 704 | 846 |
| 705 //------------------------------------------------------------------------------ | 847 //------------------------------------------------------------------------------ |
| 706 // This section provides implementation for BooleanHistogram. | 848 // This section provides implementation for BooleanHistogram. |
| 707 //------------------------------------------------------------------------------ | 849 //------------------------------------------------------------------------------ |
| 708 | 850 |
| 851 class BooleanHistogram::Factory : public Histogram::Factory { |
| 852 public: |
| 853 Factory(const std::string& name, int32_t flags) |
| 854 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {} |
| 855 |
| 856 protected: |
| 857 BucketRanges* CreateRanges() { |
| 858 BucketRanges* ranges = new BucketRanges(3 + 1); |
| 859 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
| 860 return ranges; |
| 861 } |
| 862 |
| 863 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 864 return new BooleanHistogram(name_, ranges); |
| 865 } |
| 866 |
| 867 private: |
| 868 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 869 }; |
| 870 |
| 709 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, | 871 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
| 710 int32_t flags) { | 872 int32_t flags) { |
| 711 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 873 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 } | 874 } |
| 730 | 875 |
| 731 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) { | 876 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) { |
| 732 return FactoryGet(std::string(name), flags); | 877 return FactoryGet(std::string(name), flags); |
| 733 } | 878 } |
| 734 | 879 |
| 735 HistogramType BooleanHistogram::GetHistogramType() const { | 880 HistogramType BooleanHistogram::GetHistogramType() const { |
| 736 return BOOLEAN_HISTOGRAM; | 881 return BOOLEAN_HISTOGRAM; |
| 737 } | 882 } |
| 738 | 883 |
| 739 BooleanHistogram::BooleanHistogram(const std::string& name, | 884 BooleanHistogram::BooleanHistogram(const std::string& name, |
| 740 const BucketRanges* ranges) | 885 const BucketRanges* ranges) |
| 741 : LinearHistogram(name, 1, 2, ranges) {} | 886 : LinearHistogram(name, 1, 2, ranges) {} |
| 742 | 887 |
| 888 BooleanHistogram::BooleanHistogram(const std::string& name, |
| 889 const BucketRanges* ranges, |
| 890 HistogramBase::AtomicCount* counts, |
| 891 HistogramSamples::Metadata* meta) |
| 892 : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {} |
| 893 |
| 743 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 894 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 744 std::string histogram_name; | 895 std::string histogram_name; |
| 745 int flags; | 896 int flags; |
| 746 int declared_min; | 897 int declared_min; |
| 747 int declared_max; | 898 int declared_max; |
| 748 size_t bucket_count; | 899 size_t bucket_count; |
| 749 uint32_t range_checksum; | 900 uint32_t range_checksum; |
| 750 | 901 |
| 751 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 902 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 752 &declared_max, &bucket_count, &range_checksum)) { | 903 &declared_max, &bucket_count, &range_checksum)) { |
| 753 return NULL; | 904 return NULL; |
| 754 } | 905 } |
| 755 | 906 |
| 756 HistogramBase* histogram = BooleanHistogram::FactoryGet( | 907 HistogramBase* histogram = BooleanHistogram::FactoryGet( |
| 757 histogram_name, flags); | 908 histogram_name, flags); |
| 758 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 909 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 759 // The serialized histogram might be corrupted. | 910 // The serialized histogram might be corrupted. |
| 760 return NULL; | 911 return NULL; |
| 761 } | 912 } |
| 762 return histogram; | 913 return histogram; |
| 763 } | 914 } |
| 764 | 915 |
| 765 //------------------------------------------------------------------------------ | 916 //------------------------------------------------------------------------------ |
| 766 // CustomHistogram: | 917 // CustomHistogram: |
| 767 //------------------------------------------------------------------------------ | 918 //------------------------------------------------------------------------------ |
| 768 | 919 |
| 920 class CustomHistogram::Factory : public Histogram::Factory { |
| 921 public: |
| 922 Factory(const std::string& name, |
| 923 const std::vector<Sample>* custom_ranges, |
| 924 int32_t flags) |
| 925 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) { |
| 926 custom_ranges_ = custom_ranges; |
| 927 } |
| 928 |
| 929 protected: |
| 930 BucketRanges* CreateRanges() { |
| 931 // Remove the duplicates in the custom ranges array. |
| 932 std::vector<int> ranges = *custom_ranges_; |
| 933 ranges.push_back(0); // Ensure we have a zero value. |
| 934 ranges.push_back(HistogramBase::kSampleType_MAX); |
| 935 std::sort(ranges.begin(), ranges.end()); |
| 936 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
| 937 |
| 938 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
| 939 for (size_t i = 0; i < ranges.size(); i++) { |
| 940 bucket_ranges->set_range(i, ranges[i]); |
| 941 } |
| 942 bucket_ranges->ResetChecksum(); |
| 943 return bucket_ranges; |
| 944 } |
| 945 |
| 946 HistogramBase* HeapAlloc(const BucketRanges* ranges) override { |
| 947 return new CustomHistogram(name_, ranges); |
| 948 } |
| 949 |
| 950 private: |
| 951 const std::vector<Sample>* custom_ranges_; |
| 952 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 953 }; |
| 954 |
| 769 HistogramBase* CustomHistogram::FactoryGet( | 955 HistogramBase* CustomHistogram::FactoryGet( |
| 770 const std::string& name, | 956 const std::string& name, |
| 771 const std::vector<Sample>& custom_ranges, | 957 const std::vector<Sample>& custom_ranges, |
| 772 int32_t flags) { | 958 int32_t flags) { |
| 773 CHECK(ValidateCustomRanges(custom_ranges)); | 959 CHECK(ValidateCustomRanges(custom_ranges)); |
| 774 | 960 |
| 775 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 961 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 } | 962 } |
| 794 | 963 |
| 795 HistogramBase* CustomHistogram::FactoryGet( | 964 HistogramBase* CustomHistogram::FactoryGet( |
| 796 const char* name, | 965 const char* name, |
| 797 const std::vector<Sample>& custom_ranges, | 966 const std::vector<Sample>& custom_ranges, |
| 798 int32_t flags) { | 967 int32_t flags) { |
| 799 return FactoryGet(std::string(name), custom_ranges, flags); | 968 return FactoryGet(std::string(name), custom_ranges, flags); |
| 800 } | 969 } |
| 801 | 970 |
| 802 HistogramType CustomHistogram::GetHistogramType() const { | 971 HistogramType CustomHistogram::GetHistogramType() const { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 818 return all_values; | 987 return all_values; |
| 819 } | 988 } |
| 820 | 989 |
| 821 CustomHistogram::CustomHistogram(const std::string& name, | 990 CustomHistogram::CustomHistogram(const std::string& name, |
| 822 const BucketRanges* ranges) | 991 const BucketRanges* ranges) |
| 823 : Histogram(name, | 992 : Histogram(name, |
| 824 ranges->range(1), | 993 ranges->range(1), |
| 825 ranges->range(ranges->bucket_count() - 1), | 994 ranges->range(ranges->bucket_count() - 1), |
| 826 ranges) {} | 995 ranges) {} |
| 827 | 996 |
| 997 CustomHistogram::CustomHistogram(const std::string& name, |
| 998 const BucketRanges* ranges, |
| 999 HistogramBase::AtomicCount* counts, |
| 1000 size_t counts_size, |
| 1001 HistogramSamples::Metadata* meta) |
| 1002 : Histogram(name, |
| 1003 ranges->range(1), |
| 1004 ranges->range(ranges->bucket_count() - 1), |
| 1005 ranges, |
| 1006 counts, |
| 1007 counts_size, |
| 1008 meta) {} |
| 1009 |
| 828 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 1010 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
| 829 if (!Histogram::SerializeInfoImpl(pickle)) | 1011 if (!Histogram::SerializeInfoImpl(pickle)) |
| 830 return false; | 1012 return false; |
| 831 | 1013 |
| 832 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 1014 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
| 833 // write them. | 1015 // write them. |
| 834 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 1016 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
| 835 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 1017 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
| 836 return false; | 1018 return false; |
| 837 } | 1019 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 880 for (size_t i = 0; i < custom_ranges.size(); i++) { | 1062 for (size_t i = 0; i < custom_ranges.size(); i++) { |
| 881 Sample sample = custom_ranges[i]; | 1063 Sample sample = custom_ranges[i]; |
| 882 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1064 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
| 883 return false; | 1065 return false; |
| 884 if (sample != 0) | 1066 if (sample != 0) |
| 885 has_valid_range = true; | 1067 has_valid_range = true; |
| 886 } | 1068 } |
| 887 return has_valid_range; | 1069 return has_valid_range; |
| 888 } | 1070 } |
| 889 | 1071 |
| 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 | 1072 } // namespace base |
| OLD | NEW |