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 19 matching lines...) Expand all Loading... |
38 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 | 39 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 |
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 = nullptr; |
| 50 bool g_allocator_enabled = false; |
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 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 NOTREACHED(); | 650 NOTREACHED(); |
649 return; | 651 return; |
650 } | 652 } |
651 | 653 |
652 Set(WrapUnique(new GlobalHistogramAllocator( | 654 Set(WrapUnique(new GlobalHistogramAllocator( |
653 WrapUnique(new SharedPersistentMemoryAllocator( | 655 WrapUnique(new SharedPersistentMemoryAllocator( |
654 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); | 656 std::move(shm), 0, StringPiece(), /*readonly=*/false))))); |
655 } | 657 } |
656 | 658 |
657 // static | 659 // static |
| 660 void GlobalHistogramAllocator::Enable() { |
| 661 DCHECK(g_allocator); |
| 662 g_allocator_enabled = true; |
| 663 } |
| 664 |
| 665 // static |
| 666 void GlobalHistogramAllocator::Disable() { |
| 667 DCHECK(g_allocator); |
| 668 g_allocator_enabled = false; |
| 669 } |
| 670 |
| 671 // static |
658 void GlobalHistogramAllocator::Set( | 672 void GlobalHistogramAllocator::Set( |
659 std::unique_ptr<GlobalHistogramAllocator> allocator) { | 673 std::unique_ptr<GlobalHistogramAllocator> allocator) { |
660 // Releasing or changing an allocator is extremely dangerous because it | 674 // Releasing or changing an allocator is extremely dangerous because it |
661 // likely has histograms stored within it. If the backing memory is also | 675 // likely has histograms stored within it. If the backing memory is also |
662 // also released, future accesses to those histograms will seg-fault. | 676 // also released, future accesses to those histograms will seg-fault. |
663 CHECK(!g_allocator); | 677 CHECK(!g_allocator); |
664 g_allocator = allocator.release(); | 678 g_allocator = allocator.release(); |
| 679 g_allocator_enabled = true; |
665 size_t existing = StatisticsRecorder::GetHistogramCount(); | 680 size_t existing = StatisticsRecorder::GetHistogramCount(); |
666 | 681 |
667 DVLOG_IF(1, existing) | 682 DVLOG_IF(1, existing) |
668 << existing << " histograms were created before persistence was enabled."; | 683 << existing << " histograms were created before persistence was enabled."; |
669 } | 684 } |
670 | 685 |
671 // static | 686 // static |
672 GlobalHistogramAllocator* GlobalHistogramAllocator::Get() { | 687 GlobalHistogramAllocator* GlobalHistogramAllocator::Get() { |
| 688 return g_allocator_enabled ? g_allocator : nullptr; |
| 689 } |
| 690 |
| 691 // static |
| 692 GlobalHistogramAllocator* GlobalHistogramAllocator::GetEvenIfDisabled() { |
673 return g_allocator; | 693 return g_allocator; |
674 } | 694 } |
675 | 695 |
676 // static | 696 // static |
677 std::unique_ptr<GlobalHistogramAllocator> | 697 std::unique_ptr<GlobalHistogramAllocator> |
678 GlobalHistogramAllocator::ReleaseForTesting() { | 698 GlobalHistogramAllocator::ReleaseForTesting() { |
679 GlobalHistogramAllocator* histogram_allocator = g_allocator; | 699 GlobalHistogramAllocator* histogram_allocator = g_allocator; |
680 if (!histogram_allocator) | 700 if (!histogram_allocator) |
681 return nullptr; | 701 return nullptr; |
682 PersistentMemoryAllocator* memory_allocator = | 702 PersistentMemoryAllocator* memory_allocator = |
(...skipping 18 matching lines...) Expand all Loading... |
701 // the method GetCreateHistogramResultHistogram() *before* setting | 721 // the method GetCreateHistogramResultHistogram() *before* setting |
702 // the (temporary) memory allocator via SetGlobalAllocator() so that | 722 // the (temporary) memory allocator via SetGlobalAllocator() so that |
703 // histogram is instead allocated from the process heap. | 723 // histogram is instead allocated from the process heap. |
704 DCHECK_NE(kResultHistogram, histogram_data->name); | 724 DCHECK_NE(kResultHistogram, histogram_data->name); |
705 } | 725 } |
706 | 726 |
707 g_allocator = nullptr; | 727 g_allocator = nullptr; |
708 return WrapUnique(histogram_allocator); | 728 return WrapUnique(histogram_allocator); |
709 }; | 729 }; |
710 | 730 |
| 731 void GlobalHistogramAllocator::SetPersistentLocation(const FilePath& location) { |
| 732 persistent_location_ = location; |
| 733 } |
| 734 |
| 735 bool GlobalHistogramAllocator::WriteToPersistentLocation() { |
| 736 DCHECK(g_allocator_enabled); |
| 737 |
| 738 #if defined(OS_NACL) |
| 739 // NACL doesn't support file operations, including ImportantFileWriter. |
| 740 NOTREACHED(); |
| 741 return false; |
| 742 #else |
| 743 // Stop if no destination is set. |
| 744 if (persistent_location_.empty()) { |
| 745 NOTREACHED() << "Could not write \"" << Name() << "\" persistent histograms" |
| 746 << " to file because no location was set."; |
| 747 return false; |
| 748 } |
| 749 |
| 750 StringPiece contents(static_cast<const char*>(data()), used()); |
| 751 if (!ImportantFileWriter::WriteFileAtomically(persistent_location_, |
| 752 contents)) { |
| 753 LOG(ERROR) << "Could not write \"" << Name() << "\" persistent histograms" |
| 754 << " to file: " << persistent_location_.value(); |
| 755 return false; |
| 756 } |
| 757 |
| 758 return true; |
| 759 #endif |
| 760 } |
| 761 |
711 GlobalHistogramAllocator::GlobalHistogramAllocator( | 762 GlobalHistogramAllocator::GlobalHistogramAllocator( |
712 std::unique_ptr<PersistentMemoryAllocator> memory) | 763 std::unique_ptr<PersistentMemoryAllocator> memory) |
713 : PersistentHistogramAllocator(std::move(memory)), | 764 : PersistentHistogramAllocator(std::move(memory)), |
714 import_iterator_(this) {} | 765 import_iterator_(this) {} |
715 | 766 |
716 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { | 767 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { |
717 // Skip the import if it's the histogram that was last created. Should a | 768 // Skip the import if it's the histogram that was last created. Should a |
718 // race condition cause the "last created" to be overwritten before it | 769 // race condition cause the "last created" to be overwritten before it |
719 // is recognized here then the histogram will be created and be ignored | 770 // is recognized here then the histogram will be created and be ignored |
720 // when it is detected as a duplicate by the statistics-recorder. This | 771 // when it is detected as a duplicate by the statistics-recorder. This |
721 // simple check reduces the time of creating persistent histograms by | 772 // simple check reduces the time of creating persistent histograms by |
722 // about 40%. | 773 // about 40%. |
723 Reference record_to_ignore = last_created(); | 774 Reference record_to_ignore = last_created(); |
724 | 775 |
725 // There is no lock on this because the iterator is lock-free while still | 776 // There is no lock on this because the iterator is lock-free while still |
726 // guaranteed to only return each entry only once. The StatisticsRecorder | 777 // guaranteed to only return each entry only once. The StatisticsRecorder |
727 // has its own lock so the Register operation is safe. | 778 // has its own lock so the Register operation is safe. |
728 while (true) { | 779 while (true) { |
729 std::unique_ptr<HistogramBase> histogram = | 780 std::unique_ptr<HistogramBase> histogram = |
730 import_iterator_.GetNextWithIgnore(record_to_ignore); | 781 import_iterator_.GetNextWithIgnore(record_to_ignore); |
731 if (!histogram) | 782 if (!histogram) |
732 break; | 783 break; |
733 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 784 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
734 } | 785 } |
735 } | 786 } |
736 | 787 |
737 } // namespace base | 788 } // namespace base |
OLD | NEW |