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/memory/persistent_memory_allocator.h" | |
20 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
21 #include "base/metrics/metrics_hashes.h" | 22 #include "base/metrics/metrics_hashes.h" |
22 #include "base/metrics/sample_vector.h" | 23 #include "base/metrics/sample_vector.h" |
23 #include "base/metrics/statistics_recorder.h" | 24 #include "base/metrics/statistics_recorder.h" |
24 #include "base/pickle.h" | 25 #include "base/pickle.h" |
25 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
26 #include "base/strings/stringprintf.h" | 27 #include "base/strings/stringprintf.h" |
27 #include "base/synchronization/lock.h" | 28 #include "base/synchronization/lock.h" |
28 #include "base/values.h" | 29 #include "base/values.h" |
29 | 30 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
84 const size_t Histogram::kBucketCount_MAX = 16384u; | 85 const size_t Histogram::kBucketCount_MAX = 16384u; |
85 | 86 |
86 HistogramBase* Histogram::FactoryGet(const std::string& name, | 87 HistogramBase* Histogram::FactoryGet(const std::string& name, |
87 Sample minimum, | 88 Sample minimum, |
88 Sample maximum, | 89 Sample maximum, |
89 size_t bucket_count, | 90 size_t bucket_count, |
90 int32 flags) { | 91 int32 flags) { |
91 bool valid_arguments = | 92 bool valid_arguments = |
92 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
93 DCHECK(valid_arguments); | 94 DCHECK(valid_arguments); |
95 ImportPersistentHistograms(); | |
94 | 96 |
95 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 97 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
96 if (!histogram) { | 98 if (!histogram) { |
97 // To avoid racy destruction at shutdown, the following will be leaked. | 99 // To avoid racy destruction at shutdown, the following will be leaked. |
98 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 100 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
99 InitializeBucketRanges(minimum, maximum, ranges); | 101 InitializeBucketRanges(minimum, maximum, ranges); |
100 const BucketRanges* registered_ranges = | 102 const BucketRanges* registered_ranges = |
101 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 103 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
102 | 104 |
103 Histogram* tentative_histogram = | 105 PersistentMemoryAllocator::Reference histogram_ref = 0; |
104 new Histogram(name, minimum, maximum, registered_ranges); | 106 HistogramBase* tentative_histogram = nullptr; |
107 if (allocator_) { | |
108 flags |= kIsPersistent; | |
109 tentative_histogram = AllocatePersistentHistogram( | |
110 GetDefaultPersistentMemoryAllocator(), | |
111 HISTOGRAM, | |
112 name, | |
113 minimum, | |
114 maximum, | |
115 registered_ranges, | |
116 flags, | |
117 &histogram_ref); | |
118 } | |
119 if (!tentative_histogram) { | |
120 flags &= ~kIsPersistent; | |
121 tentative_histogram = new Histogram( | |
122 name, minimum, maximum, registered_ranges); | |
123 } | |
105 | 124 |
106 tentative_histogram->SetFlags(flags); | 125 tentative_histogram->SetFlags(flags); |
107 histogram = | 126 histogram = |
108 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 127 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
128 | |
129 // Persistent histograms need some follow-up processing. | |
130 if (histogram_ref) { | |
131 // If the created persistent histogram is canonical then it needs to be | |
132 // marked as "iterable" in order to be found by other processes. | |
133 if (histogram == tentative_histogram) | |
134 GetDefaultPersistentMemoryAllocator()->MakeIterable(histogram_ref); | |
135 // If it's not the canonical one then a race condition must have caused | |
136 // two to be created. The allocator does not support releasing the | |
137 // acquired memory so just change the type to be empty. | |
138 else | |
139 GetDefaultPersistentMemoryAllocator()->SetType(histogram_ref, 0); | |
140 } | |
109 } | 141 } |
110 | 142 |
111 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | 143 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); |
112 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | 144 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { |
113 // The construction arguments do not match the existing histogram. This can | 145 // 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 | 146 // 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 | 147 // 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 | 148 // 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 | 149 // on dereference, but extension/Pepper APIs will guard against NULL and not |
118 // crash. | 150 // crash. |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 Sample maximum, | 369 Sample maximum, |
338 const BucketRanges* ranges) | 370 const BucketRanges* ranges) |
339 : HistogramBase(name), | 371 : HistogramBase(name), |
340 bucket_ranges_(ranges), | 372 bucket_ranges_(ranges), |
341 declared_min_(minimum), | 373 declared_min_(minimum), |
342 declared_max_(maximum) { | 374 declared_max_(maximum) { |
343 if (ranges) | 375 if (ranges) |
344 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 376 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
345 } | 377 } |
346 | 378 |
379 Histogram::Histogram(const std::string& name, | |
380 Sample minimum, | |
381 Sample maximum, | |
382 const BucketRanges* ranges, | |
383 HistogramBase::AtomicCount* counts, | |
384 size_t counts_size, | |
385 HistogramSamples::Metadata* meta) | |
386 : HistogramBase(name), | |
387 bucket_ranges_(ranges), | |
388 declared_min_(minimum), | |
389 declared_max_(maximum) { | |
390 if (ranges) | |
391 samples_.reset(new SampleVector(HashMetricName(name), | |
392 counts, counts_size, meta, ranges)); | |
393 } | |
394 | |
347 Histogram::~Histogram() { | 395 Histogram::~Histogram() { |
348 } | 396 } |
349 | 397 |
350 bool Histogram::PrintEmptyBucket(size_t index) const { | 398 bool Histogram::PrintEmptyBucket(size_t index) const { |
351 return true; | 399 return true; |
352 } | 400 } |
353 | 401 |
354 // Use the actual bucket widths (like a linear histogram) until the widths get | 402 // 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 | 403 // 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 | 404 // get so big so fast (and we don't expect to see a lot of entries in the large |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 | 440 |
393 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 441 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
394 // The serialized histogram might be corrupted. | 442 // The serialized histogram might be corrupted. |
395 return NULL; | 443 return NULL; |
396 } | 444 } |
397 return histogram; | 445 return histogram; |
398 } | 446 } |
399 | 447 |
400 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { | 448 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { |
401 scoped_ptr<SampleVector> samples( | 449 scoped_ptr<SampleVector> samples( |
402 new SampleVector(HashMetricName(histogram_name()), bucket_ranges())); | 450 new SampleVector(HashMetricName(histogram_name()), |
451 bucket_ranges())); | |
403 samples->Add(*samples_); | 452 samples->Add(*samples_); |
404 return samples; | 453 return samples; |
405 } | 454 } |
406 | 455 |
407 void Histogram::WriteAsciiImpl(bool graph_it, | 456 void Histogram::WriteAsciiImpl(bool graph_it, |
408 const std::string& newline, | 457 const std::string& newline, |
409 std::string* output) const { | 458 std::string* output) const { |
410 // Get local (stack) copies of all effectively volatile class data so that we | 459 // Get local (stack) copies of all effectively volatile class data so that we |
411 // are consistent across our output activities. | 460 // are consistent across our output activities. |
412 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 461 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
586 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( | 635 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( |
587 const std::string& name, | 636 const std::string& name, |
588 Sample minimum, | 637 Sample minimum, |
589 Sample maximum, | 638 Sample maximum, |
590 size_t bucket_count, | 639 size_t bucket_count, |
591 int32 flags, | 640 int32 flags, |
592 const DescriptionPair descriptions[]) { | 641 const DescriptionPair descriptions[]) { |
593 bool valid_arguments = Histogram::InspectConstructionArguments( | 642 bool valid_arguments = Histogram::InspectConstructionArguments( |
594 name, &minimum, &maximum, &bucket_count); | 643 name, &minimum, &maximum, &bucket_count); |
595 DCHECK(valid_arguments); | 644 DCHECK(valid_arguments); |
645 ImportPersistentHistograms(); | |
596 | 646 |
597 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 647 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
598 if (!histogram) { | 648 if (!histogram) { |
599 // To avoid racy destruction at shutdown, the following will be leaked. | 649 // To avoid racy destruction at shutdown, the following will be leaked. |
600 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 650 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
601 InitializeBucketRanges(minimum, maximum, ranges); | 651 InitializeBucketRanges(minimum, maximum, ranges); |
602 const BucketRanges* registered_ranges = | 652 const BucketRanges* registered_ranges = |
603 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 653 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
604 | 654 |
605 LinearHistogram* tentative_histogram = | 655 PersistentMemoryAllocator::Reference histogram_ref = 0; |
606 new LinearHistogram(name, minimum, maximum, registered_ranges); | 656 LinearHistogram* tentative_histogram = nullptr; |
657 if (allocator_) { | |
658 flags |= kIsPersistent; | |
659 tentative_histogram = static_cast<LinearHistogram*>( | |
660 AllocatePersistentHistogram( | |
661 GetDefaultPersistentMemoryAllocator(), | |
662 LINEAR_HISTOGRAM, | |
663 name, | |
664 minimum, | |
665 maximum, | |
666 registered_ranges, | |
667 flags, | |
668 &histogram_ref)); | |
669 } | |
670 if (!tentative_histogram) { | |
671 flags &= ~kIsPersistent; | |
672 tentative_histogram = new LinearHistogram( | |
673 name, minimum, maximum, registered_ranges); | |
674 } | |
607 | 675 |
608 // Set range descriptions. | 676 // Set range descriptions. |
609 if (descriptions) { | 677 if (descriptions) { |
610 for (int i = 0; descriptions[i].description; ++i) { | 678 for (int i = 0; descriptions[i].description; ++i) { |
611 tentative_histogram->bucket_description_[descriptions[i].sample] = | 679 tentative_histogram->bucket_description_[descriptions[i].sample] = |
612 descriptions[i].description; | 680 descriptions[i].description; |
613 } | 681 } |
614 } | 682 } |
615 | 683 |
616 tentative_histogram->SetFlags(flags); | 684 tentative_histogram->SetFlags(flags); |
617 histogram = | 685 histogram = |
618 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 686 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
687 | |
688 // Persistent histograms need some follow-up processing. | |
689 if (histogram_ref) { | |
690 // If the created persistent histogram is canonical then it needs to be | |
691 // marked as "iterable" in order to be found by other processes. | |
692 if (histogram == tentative_histogram) | |
693 GetDefaultPersistentMemoryAllocator()->MakeIterable(histogram_ref); | |
694 // If it's not the canonical one then a race condition must have caused | |
695 // two to be created. The allocator does not support releasing the | |
696 // acquired memory so just change the type to be empty. | |
697 else | |
698 GetDefaultPersistentMemoryAllocator()->SetType(histogram_ref, 0); | |
699 } | |
619 } | 700 } |
620 | 701 |
621 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | 702 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); |
622 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | 703 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { |
623 // The construction arguments do not match the existing histogram. This can | 704 // 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 | 705 // 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 | 706 // 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 | 707 // 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 | 708 // on dereference, but extension/Pepper APIs will guard against NULL and not |
628 // crash. | 709 // crash. |
629 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | 710 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; |
630 return NULL; | 711 return NULL; |
631 } | 712 } |
632 return histogram; | 713 return histogram; |
633 } | 714 } |
634 | 715 |
635 HistogramType LinearHistogram::GetHistogramType() const { | 716 HistogramType LinearHistogram::GetHistogramType() const { |
636 return LINEAR_HISTOGRAM; | 717 return LINEAR_HISTOGRAM; |
637 } | 718 } |
638 | 719 |
639 LinearHistogram::LinearHistogram(const std::string& name, | 720 LinearHistogram::LinearHistogram(const std::string& name, |
640 Sample minimum, | 721 Sample minimum, |
641 Sample maximum, | 722 Sample maximum, |
642 const BucketRanges* ranges) | 723 const BucketRanges* ranges) |
643 : Histogram(name, minimum, maximum, ranges) { | 724 : Histogram(name, minimum, maximum, ranges) { |
644 } | 725 } |
645 | 726 |
727 LinearHistogram::LinearHistogram(const std::string& name, | |
728 Sample minimum, | |
729 Sample maximum, | |
730 const BucketRanges* ranges, | |
731 HistogramBase::AtomicCount* counts, | |
732 size_t counts_size, | |
733 HistogramSamples::Metadata* meta) | |
734 : Histogram(name, | |
735 minimum, | |
736 maximum, | |
737 ranges, | |
738 counts, | |
739 counts_size, | |
740 meta) {} | |
741 | |
646 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 742 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
647 DCHECK_GT(ranges(i + 1), ranges(i)); | 743 DCHECK_GT(ranges(i + 1), ranges(i)); |
648 // Adjacent buckets with different widths would have "surprisingly" many (few) | 744 // Adjacent buckets with different widths would have "surprisingly" many (few) |
649 // samples in a histogram if we didn't normalize this way. | 745 // samples in a histogram if we didn't normalize this way. |
650 double denominator = ranges(i + 1) - ranges(i); | 746 double denominator = ranges(i + 1) - ranges(i); |
651 return current/denominator; | 747 return current/denominator; |
652 } | 748 } |
653 | 749 |
654 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 750 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
655 int range = ranges(i); | 751 int range = ranges(i); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 } | 797 } |
702 return histogram; | 798 return histogram; |
703 } | 799 } |
704 | 800 |
705 //------------------------------------------------------------------------------ | 801 //------------------------------------------------------------------------------ |
706 // This section provides implementation for BooleanHistogram. | 802 // This section provides implementation for BooleanHistogram. |
707 //------------------------------------------------------------------------------ | 803 //------------------------------------------------------------------------------ |
708 | 804 |
709 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, | 805 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
710 int32 flags) { | 806 int32 flags) { |
807 ImportPersistentHistograms(); | |
808 | |
711 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 809 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
712 if (!histogram) { | 810 if (!histogram) { |
713 // To avoid racy destruction at shutdown, the following will be leaked. | 811 // To avoid racy destruction at shutdown, the following will be leaked. |
714 BucketRanges* ranges = new BucketRanges(4); | 812 BucketRanges* ranges = new BucketRanges(4); |
715 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | 813 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
716 const BucketRanges* registered_ranges = | 814 const BucketRanges* registered_ranges = |
717 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 815 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
718 | 816 |
719 BooleanHistogram* tentative_histogram = | 817 PersistentMemoryAllocator::Reference histogram_ref = 0; |
720 new BooleanHistogram(name, registered_ranges); | 818 HistogramBase* tentative_histogram = nullptr; |
819 if (allocator_) { | |
820 flags |= kIsPersistent; | |
821 tentative_histogram = AllocatePersistentHistogram( | |
822 GetDefaultPersistentMemoryAllocator(), | |
823 BOOLEAN_HISTOGRAM, | |
824 name, | |
825 1, 2, | |
826 registered_ranges, | |
827 flags, | |
828 &histogram_ref); | |
829 } | |
830 if (!tentative_histogram) { | |
831 flags &= ~kIsPersistent; | |
832 tentative_histogram = new BooleanHistogram(name, registered_ranges); | |
833 } | |
721 | 834 |
722 tentative_histogram->SetFlags(flags); | 835 tentative_histogram->SetFlags(flags); |
723 histogram = | 836 histogram = |
724 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 837 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
838 | |
839 // Persistent histograms need some follow-up processing. | |
840 if (histogram_ref) { | |
841 // If the created persistent histogram is canonical then it needs to be | |
842 // marked as "iterable" in order to be found by other processes. | |
843 if (histogram == tentative_histogram) | |
844 GetDefaultPersistentMemoryAllocator()->MakeIterable(histogram_ref); | |
845 // If it's not the canonical one then a race condition must have caused | |
846 // two to be created. The allocator does not support releasing the | |
847 // acquired memory so just change the type to be empty. | |
848 else | |
849 GetDefaultPersistentMemoryAllocator()->SetType(histogram_ref, 0); | |
850 } | |
Alexei Svitkine (slow)
2015/12/04 18:27:36
The code from 817 to 850 is repeated in several pl
bcwhite
2015/12/07 23:27:19
Done.
| |
725 } | 851 } |
726 | 852 |
727 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | 853 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
728 return histogram; | 854 return histogram; |
729 } | 855 } |
730 | 856 |
731 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { | 857 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { |
732 return FactoryGet(std::string(name), flags); | 858 return FactoryGet(std::string(name), flags); |
733 } | 859 } |
734 | 860 |
735 HistogramType BooleanHistogram::GetHistogramType() const { | 861 HistogramType BooleanHistogram::GetHistogramType() const { |
736 return BOOLEAN_HISTOGRAM; | 862 return BOOLEAN_HISTOGRAM; |
737 } | 863 } |
738 | 864 |
739 BooleanHistogram::BooleanHistogram(const std::string& name, | 865 BooleanHistogram::BooleanHistogram(const std::string& name, |
740 const BucketRanges* ranges) | 866 const BucketRanges* ranges) |
741 : LinearHistogram(name, 1, 2, ranges) {} | 867 : LinearHistogram(name, 1, 2, ranges) {} |
742 | 868 |
869 BooleanHistogram::BooleanHistogram(const std::string& name, | |
870 const BucketRanges* ranges, | |
871 HistogramBase::AtomicCount* counts, | |
872 HistogramSamples::Metadata* meta) | |
873 : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {} | |
874 | |
743 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 875 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
744 std::string histogram_name; | 876 std::string histogram_name; |
745 int flags; | 877 int flags; |
746 int declared_min; | 878 int declared_min; |
747 int declared_max; | 879 int declared_max; |
748 size_t bucket_count; | 880 size_t bucket_count; |
749 uint32 range_checksum; | 881 uint32 range_checksum; |
750 | 882 |
751 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 883 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
752 &declared_max, &bucket_count, &range_checksum)) { | 884 &declared_max, &bucket_count, &range_checksum)) { |
(...skipping 11 matching lines...) Expand all Loading... | |
764 | 896 |
765 //------------------------------------------------------------------------------ | 897 //------------------------------------------------------------------------------ |
766 // CustomHistogram: | 898 // CustomHistogram: |
767 //------------------------------------------------------------------------------ | 899 //------------------------------------------------------------------------------ |
768 | 900 |
769 HistogramBase* CustomHistogram::FactoryGet( | 901 HistogramBase* CustomHistogram::FactoryGet( |
770 const std::string& name, | 902 const std::string& name, |
771 const std::vector<Sample>& custom_ranges, | 903 const std::vector<Sample>& custom_ranges, |
772 int32 flags) { | 904 int32 flags) { |
773 CHECK(ValidateCustomRanges(custom_ranges)); | 905 CHECK(ValidateCustomRanges(custom_ranges)); |
906 ImportPersistentHistograms(); | |
774 | 907 |
775 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 908 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
776 if (!histogram) { | 909 if (!histogram) { |
910 // To avoid racy destruction at shutdown, the following will be leaked. | |
777 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | 911 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); |
778 const BucketRanges* registered_ranges = | 912 const BucketRanges* registered_ranges = |
779 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 913 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
780 | 914 |
781 // To avoid racy destruction at shutdown, the following will be leaked. | 915 PersistentMemoryAllocator::Reference histogram_ref = 0; |
782 CustomHistogram* tentative_histogram = | 916 HistogramBase* tentative_histogram = nullptr; |
783 new CustomHistogram(name, registered_ranges); | 917 if (allocator_) { |
918 flags |= kIsPersistent; | |
919 tentative_histogram = AllocatePersistentHistogram( | |
920 GetDefaultPersistentMemoryAllocator(), | |
921 CUSTOM_HISTOGRAM, | |
922 name, | |
923 registered_ranges->range(1), | |
924 registered_ranges->range(registered_ranges->bucket_count() - 1), | |
925 registered_ranges, | |
926 flags, | |
927 &histogram_ref); | |
928 } | |
929 if (!tentative_histogram) { | |
930 flags &= ~kIsPersistent; | |
931 tentative_histogram = new CustomHistogram(name, registered_ranges); | |
932 } | |
784 | 933 |
785 tentative_histogram->SetFlags(flags); | 934 tentative_histogram->SetFlags(flags); |
786 | |
787 histogram = | 935 histogram = |
788 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 936 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
937 | |
938 // Persistent histograms need some follow-up processing. | |
939 if (histogram_ref) { | |
940 // If the created persistent histogram is canonical then it needs to be | |
941 // marked as "iterable" in order to be found by other processes. | |
942 if (histogram == tentative_histogram) | |
943 GetDefaultPersistentMemoryAllocator()->MakeIterable(histogram_ref); | |
944 // If it's not the canonical one then a race condition must have caused | |
945 // two to be created. The allocator does not support releasing the | |
946 // acquired memory so just change the type to be empty. | |
947 else | |
948 GetDefaultPersistentMemoryAllocator()->SetType(histogram_ref, 0); | |
949 } | |
789 } | 950 } |
790 | 951 |
791 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | 952 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); |
792 return histogram; | 953 return histogram; |
793 } | 954 } |
794 | 955 |
795 HistogramBase* CustomHistogram::FactoryGet( | 956 HistogramBase* CustomHistogram::FactoryGet( |
796 const char* name, | 957 const char* name, |
797 const std::vector<Sample>& custom_ranges, | 958 const std::vector<Sample>& custom_ranges, |
798 int32 flags) { | 959 int32 flags) { |
(...skipping 19 matching lines...) Expand all Loading... | |
818 return all_values; | 979 return all_values; |
819 } | 980 } |
820 | 981 |
821 CustomHistogram::CustomHistogram(const std::string& name, | 982 CustomHistogram::CustomHistogram(const std::string& name, |
822 const BucketRanges* ranges) | 983 const BucketRanges* ranges) |
823 : Histogram(name, | 984 : Histogram(name, |
824 ranges->range(1), | 985 ranges->range(1), |
825 ranges->range(ranges->bucket_count() - 1), | 986 ranges->range(ranges->bucket_count() - 1), |
826 ranges) {} | 987 ranges) {} |
827 | 988 |
989 CustomHistogram::CustomHistogram(const std::string& name, | |
990 const BucketRanges* ranges, | |
991 HistogramBase::AtomicCount* counts, | |
992 size_t counts_size, | |
993 HistogramSamples::Metadata* meta) | |
994 : Histogram(name, | |
995 ranges->range(1), | |
996 ranges->range(ranges->bucket_count() - 1), | |
997 ranges, | |
998 counts, | |
999 counts_size, | |
1000 meta) {} | |
1001 | |
828 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 1002 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
829 if (!Histogram::SerializeInfoImpl(pickle)) | 1003 if (!Histogram::SerializeInfoImpl(pickle)) |
830 return false; | 1004 return false; |
831 | 1005 |
832 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 1006 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
833 // write them. | 1007 // write them. |
834 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 1008 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
835 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 1009 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
836 return false; | 1010 return false; |
837 } | 1011 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
899 | 1073 |
900 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | 1074 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
901 for (size_t i = 0; i < ranges.size(); i++) { | 1075 for (size_t i = 0; i < ranges.size(); i++) { |
902 bucket_ranges->set_range(i, ranges[i]); | 1076 bucket_ranges->set_range(i, ranges[i]); |
903 } | 1077 } |
904 bucket_ranges->ResetChecksum(); | 1078 bucket_ranges->ResetChecksum(); |
905 return bucket_ranges; | 1079 return bucket_ranges; |
906 } | 1080 } |
907 | 1081 |
908 } // namespace base | 1082 } // namespace base |
OLD | NEW |