OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 #include "base/metrics/persistent_histogram_allocator.h" | 5 #include "base/metrics/persistent_histogram_allocator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/files/important_file_writer.h" | |
9 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
12 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
13 #include "base/metrics/histogram_base.h" | 14 #include "base/metrics/histogram_base.h" |
14 #include "base/metrics/histogram_samples.h" | 15 #include "base/metrics/histogram_samples.h" |
15 #include "base/metrics/persistent_sample_map.h" | 16 #include "base/metrics/persistent_sample_map.h" |
16 #include "base/metrics/sparse_histogram.h" | 17 #include "base/metrics/sparse_histogram.h" |
17 #include "base/metrics/statistics_recorder.h" | 18 #include "base/metrics/statistics_recorder.h" |
18 #include "base/synchronization/lock.h" | 19 #include "base/synchronization/lock.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
39 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 | 40 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 |
40 }; | 41 }; |
41 | 42 |
42 // The current globally-active persistent allocator for all new histograms. | 43 // The current globally-active persistent allocator for all new histograms. |
43 // The object held here will obviously not be destructed at process exit | 44 // The object held here will obviously not be destructed at process exit |
44 // but that's best since PersistentMemoryAllocator objects (that underlie | 45 // but that's best since PersistentMemoryAllocator objects (that underlie |
45 // GlobalHistogramAllocator objects) are explicitly forbidden from doing | 46 // GlobalHistogramAllocator objects) are explicitly forbidden from doing |
46 // anything essential at exit anyway due to the fact that they depend on data | 47 // anything essential at exit anyway due to the fact that they depend on data |
47 // managed elsewhere and which could be destructed first. | 48 // managed elsewhere and which could be destructed first. |
48 GlobalHistogramAllocator* g_allocator; | 49 GlobalHistogramAllocator* g_allocator; |
50 GlobalHistogramAllocator* g_allocator_disabled; | |
Ilya Sherman
2016/04/26 20:01:24
Please use a boolean for enabled/disabled state, r
bcwhite
2016/04/26 21:04:26
Done.
| |
49 | 51 |
50 // Take an array of range boundaries and create a proper BucketRanges object | 52 // Take an array of range boundaries and create a proper BucketRanges object |
51 // which is returned to the caller. A return of nullptr indicates that the | 53 // which is returned to the caller. A return of nullptr indicates that the |
52 // passed boundaries are invalid. | 54 // passed boundaries are invalid. |
53 std::unique_ptr<BucketRanges> CreateRangesFromData( | 55 std::unique_ptr<BucketRanges> CreateRangesFromData( |
54 HistogramBase::Sample* ranges_data, | 56 HistogramBase::Sample* ranges_data, |
55 uint32_t ranges_checksum, | 57 uint32_t ranges_checksum, |
56 size_t count) { | 58 size_t count) { |
57 // To avoid racy destruction at shutdown, the following may be leaked. | 59 // To avoid racy destruction at shutdown, the following may be leaked. |
58 std::unique_ptr<BucketRanges> ranges(new BucketRanges(count)); | 60 std::unique_ptr<BucketRanges> ranges(new BucketRanges(count)); |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
644 NOTREACHED(); | 646 NOTREACHED(); |
645 return; | 647 return; |
646 } | 648 } |
647 | 649 |
648 Set(WrapUnique(new GlobalHistogramAllocator( | 650 Set(WrapUnique(new GlobalHistogramAllocator( |
649 WrapUnique(new SharedPersistentMemoryAllocator( | 651 WrapUnique(new SharedPersistentMemoryAllocator( |
650 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); | 652 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); |
651 } | 653 } |
652 | 654 |
653 // static | 655 // static |
656 void GlobalHistogramAllocator::Enable() { | |
657 if (g_allocator) { | |
658 // Already enabled. | |
659 DCHECK(!g_allocator_disabled); | |
660 return; | |
661 } | |
662 | |
663 DCHECK(g_allocator_disabled); | |
664 std::swap(g_allocator, g_allocator_disabled); | |
665 } | |
666 | |
667 // static | |
668 void GlobalHistogramAllocator::Disable() { | |
669 if (g_allocator_disabled) { | |
670 // Already disabled. | |
671 DCHECK(!g_allocator); | |
672 return; | |
673 } | |
674 | |
675 DCHECK(g_allocator); | |
676 std::swap(g_allocator, g_allocator_disabled); | |
677 } | |
678 | |
679 // static | |
654 void GlobalHistogramAllocator::Set( | 680 void GlobalHistogramAllocator::Set( |
655 std::unique_ptr<GlobalHistogramAllocator> allocator) { | 681 std::unique_ptr<GlobalHistogramAllocator> allocator) { |
656 // Releasing or changing an allocator is extremely dangerous because it | 682 // Releasing or changing an allocator is extremely dangerous because it |
657 // likely has histograms stored within it. If the backing memory is also | 683 // likely has histograms stored within it. If the backing memory is also |
658 // also released, future accesses to those histograms will seg-fault. | 684 // also released, future accesses to those histograms will seg-fault. |
659 CHECK(!g_allocator); | 685 CHECK(!g_allocator && !g_allocator_disabled); |
660 g_allocator = allocator.release(); | 686 g_allocator = allocator.release(); |
661 size_t existing = StatisticsRecorder::GetHistogramCount(); | 687 size_t existing = StatisticsRecorder::GetHistogramCount(); |
662 | 688 |
663 DLOG_IF(WARNING, existing) | 689 DLOG_IF(WARNING, existing) |
664 << existing << " histograms were created before persistence was enabled."; | 690 << existing << " histograms were created before persistence was enabled."; |
665 } | 691 } |
666 | 692 |
667 // static | 693 // static |
668 GlobalHistogramAllocator* GlobalHistogramAllocator::Get() { | 694 GlobalHistogramAllocator* GlobalHistogramAllocator::Get() { |
669 return g_allocator; | 695 return g_allocator; |
670 } | 696 } |
671 | 697 |
672 // static | 698 // static |
699 GlobalHistogramAllocator* GlobalHistogramAllocator::GetEvenIfDisabled() { | |
700 return g_allocator ? g_allocator : g_allocator_disabled; | |
701 } | |
702 | |
703 // static | |
673 std::unique_ptr<GlobalHistogramAllocator> | 704 std::unique_ptr<GlobalHistogramAllocator> |
674 GlobalHistogramAllocator::ReleaseForTesting() { | 705 GlobalHistogramAllocator::ReleaseForTesting() { |
675 GlobalHistogramAllocator* histogram_allocator = g_allocator; | 706 GlobalHistogramAllocator* histogram_allocator = GetEvenIfDisabled(); |
676 if (!histogram_allocator) | 707 if (!histogram_allocator) |
677 return nullptr; | 708 return nullptr; |
678 PersistentMemoryAllocator* memory_allocator = | 709 PersistentMemoryAllocator* memory_allocator = |
679 histogram_allocator->memory_allocator(); | 710 histogram_allocator->memory_allocator(); |
680 | 711 |
681 // Before releasing the memory, it's necessary to have the Statistics- | 712 // Before releasing the memory, it's necessary to have the Statistics- |
682 // Recorder forget about the histograms contained therein; otherwise, | 713 // Recorder forget about the histograms contained therein; otherwise, |
683 // some operations will try to access them and the released memory. | 714 // some operations will try to access them and the released memory. |
684 PersistentMemoryAllocator::Iterator iter(memory_allocator); | 715 PersistentMemoryAllocator::Iterator iter(memory_allocator); |
685 PersistentMemoryAllocator::Reference ref; | 716 PersistentMemoryAllocator::Reference ref; |
686 while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) { | 717 while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) { |
687 PersistentHistogramData* histogram_data = | 718 PersistentHistogramData* histogram_data = |
688 memory_allocator->GetAsObject<PersistentHistogramData>( | 719 memory_allocator->GetAsObject<PersistentHistogramData>( |
689 ref, kTypeIdHistogram); | 720 ref, kTypeIdHistogram); |
690 DCHECK(histogram_data); | 721 DCHECK(histogram_data); |
691 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); | 722 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); |
692 | 723 |
693 // If a test breaks here then a memory region containing a histogram | 724 // If a test breaks here then a memory region containing a histogram |
694 // actively used by this code is being released back to the test. | 725 // actively used by this code is being released back to the test. |
695 // If that memory segment were to be deleted, future calls to create | 726 // If that memory segment were to be deleted, future calls to create |
696 // persistent histograms would crash. To avoid this, have the test call | 727 // persistent histograms would crash. To avoid this, have the test call |
697 // the method GetCreateHistogramResultHistogram() *before* setting | 728 // the method GetCreateHistogramResultHistogram() *before* setting |
698 // the (temporary) memory allocator via SetGlobalAllocator() so that | 729 // the (temporary) memory allocator via SetGlobalAllocator() so that |
699 // histogram is instead allocated from the process heap. | 730 // histogram is instead allocated from the process heap. |
700 DCHECK_NE(kResultHistogram, histogram_data->name); | 731 DCHECK_NE(kResultHistogram, histogram_data->name); |
701 } | 732 } |
702 | 733 |
734 DCHECK_NE(g_allocator != nullptr, g_allocator_disabled != nullptr); | |
703 g_allocator = nullptr; | 735 g_allocator = nullptr; |
736 g_allocator_disabled = nullptr; | |
704 return WrapUnique(histogram_allocator); | 737 return WrapUnique(histogram_allocator); |
705 }; | 738 }; |
706 | 739 |
740 void GlobalHistogramAllocator::SetPersistentLocation(const FilePath& location) { | |
741 persistent_location_ = location; | |
742 } | |
743 | |
744 bool GlobalHistogramAllocator::WriteToPersistentLocation() { | |
745 #if defined(OS_NACL) | |
746 // NACL doesn't support file operations, including ImportantFileWriter. | |
747 NOTREACHED(); | |
748 return false; | |
749 #else | |
750 // Stop if no destination is set, perhaps because it has not been enabled. | |
751 if (persistent_location_.empty()) { | |
752 NOTREACHED() << "Could not write \"" << Name() << "\" persistent histograms" | |
753 << " to file because no location was set."; | |
754 return false; | |
755 } | |
756 | |
757 StringPiece contents(static_cast<const char*>(data()), used()); | |
758 if (!ImportantFileWriter::WriteFileAtomically(persistent_location_, | |
759 contents)) { | |
760 LOG(ERROR) << "Could not write \"" << Name() << "\" persistent histograms" | |
761 << " to file: " << persistent_location_.value(); | |
762 return false; | |
763 } | |
764 | |
765 return true; | |
766 #endif | |
767 } | |
768 | |
707 GlobalHistogramAllocator::GlobalHistogramAllocator( | 769 GlobalHistogramAllocator::GlobalHistogramAllocator( |
708 std::unique_ptr<PersistentMemoryAllocator> memory) | 770 std::unique_ptr<PersistentMemoryAllocator> memory) |
709 : PersistentHistogramAllocator(std::move(memory)), | 771 : PersistentHistogramAllocator(std::move(memory)), |
710 import_iterator_(this) {} | 772 import_iterator_(this) {} |
711 | 773 |
712 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { | 774 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { |
713 // Skip the import if it's the histogram that was last created. Should a | 775 // Skip the import if it's the histogram that was last created. Should a |
714 // race condition cause the "last created" to be overwritten before it | 776 // race condition cause the "last created" to be overwritten before it |
715 // is recognized here then the histogram will be created and be ignored | 777 // is recognized here then the histogram will be created and be ignored |
716 // when it is detected as a duplicate by the statistics-recorder. This | 778 // when it is detected as a duplicate by the statistics-recorder. This |
717 // simple check reduces the time of creating persistent histograms by | 779 // simple check reduces the time of creating persistent histograms by |
718 // about 40%. | 780 // about 40%. |
719 Reference record_to_ignore = last_created(); | 781 Reference record_to_ignore = last_created(); |
720 | 782 |
721 // There is no lock on this because the iterator is lock-free while still | 783 // There is no lock on this because the iterator is lock-free while still |
722 // guaranteed to only return each entry only once. The StatisticsRecorder | 784 // guaranteed to only return each entry only once. The StatisticsRecorder |
723 // has its own lock so the Register operation is safe. | 785 // has its own lock so the Register operation is safe. |
724 while (true) { | 786 while (true) { |
725 std::unique_ptr<HistogramBase> histogram = | 787 std::unique_ptr<HistogramBase> histogram = |
726 import_iterator_.GetNextWithIgnore(record_to_ignore); | 788 import_iterator_.GetNextWithIgnore(record_to_ignore); |
727 if (!histogram) | 789 if (!histogram) |
728 break; | 790 break; |
729 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 791 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
730 } | 792 } |
731 } | 793 } |
732 | 794 |
733 } // namespace base | 795 } // namespace base |
OLD | NEW |