OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/metrics/subprocess_metrics_provider.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/metrics/histogram.h" |
| 11 #include "base/metrics/histogram_flattener.h" |
| 12 #include "base/metrics/histogram_snapshot_manager.h" |
| 13 #include "base/metrics/persistent_histogram_allocator.h" |
| 14 #include "base/metrics/persistent_memory_allocator.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 namespace { |
| 18 |
| 19 const uint32_t TEST_MEMORY_SIZE = 64 << 10; // 64 KiB |
| 20 |
| 21 class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener { |
| 22 public: |
| 23 HistogramFlattenerDeltaRecorder() {} |
| 24 |
| 25 void RecordDelta(const base::HistogramBase& histogram, |
| 26 const base::HistogramSamples& snapshot) override { |
| 27 recorded_delta_histogram_names_.push_back(histogram.histogram_name()); |
| 28 } |
| 29 |
| 30 void InconsistencyDetected( |
| 31 base::HistogramBase::Inconsistency problem) override { |
| 32 ASSERT_TRUE(false); |
| 33 } |
| 34 |
| 35 void UniqueInconsistencyDetected( |
| 36 base::HistogramBase::Inconsistency problem) override { |
| 37 ASSERT_TRUE(false); |
| 38 } |
| 39 |
| 40 void InconsistencyDetectedInLoggedCount(int amount) override { |
| 41 ASSERT_TRUE(false); |
| 42 } |
| 43 |
| 44 std::vector<std::string> GetRecordedDeltaHistogramNames() { |
| 45 return recorded_delta_histogram_names_; |
| 46 } |
| 47 |
| 48 private: |
| 49 std::vector<std::string> recorded_delta_histogram_names_; |
| 50 |
| 51 DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder); |
| 52 }; |
| 53 |
| 54 } // namespace |
| 55 |
| 56 class SubprocessMetricsProviderTest : public testing::Test { |
| 57 protected: |
| 58 SubprocessMetricsProviderTest() { |
| 59 // Get this first so it isn't created inside a persistent allocator. |
| 60 base::PersistentHistogramAllocator::GetCreateHistogramResultHistogram(); |
| 61 |
| 62 // RecordHistogramSnapshots needs to be called beause it uses a histogram |
| 63 // macro which caches a pointer to a histogram. If not done before setting |
| 64 // a persistent global allocator, then it would point into memory that |
| 65 // will go away. The easiest way to call it is through an existing utility |
| 66 // method. |
| 67 GetSnapshotHistogramCount(); |
| 68 |
| 69 // Create a global allocator using a block of memory from the heap. |
| 70 base::GlobalHistogramAllocator::CreateWithLocalMemory(TEST_MEMORY_SIZE, |
| 71 0, ""); |
| 72 |
| 73 // Enable metrics reporting by default. |
| 74 provider_.OnRecordingEnabled(); |
| 75 } |
| 76 |
| 77 ~SubprocessMetricsProviderTest() override { |
| 78 base::GlobalHistogramAllocator::ReleaseForTesting(); |
| 79 } |
| 80 |
| 81 SubprocessMetricsProvider* provider() { return &provider_; } |
| 82 |
| 83 std::unique_ptr<base::PersistentHistogramAllocator> GetDuplicateAllocator() { |
| 84 base::GlobalHistogramAllocator* global_allocator = |
| 85 base::GlobalHistogramAllocator::Get(); |
| 86 |
| 87 // Just wrap around the data segment in-use by the global allocator. |
| 88 return WrapUnique(new base::PersistentHistogramAllocator( |
| 89 WrapUnique(new base::PersistentMemoryAllocator( |
| 90 const_cast<void*>(global_allocator->data()), |
| 91 global_allocator->length(), 0, 0, "", false)))); |
| 92 } |
| 93 |
| 94 size_t GetSnapshotHistogramCount() { |
| 95 HistogramFlattenerDeltaRecorder flattener; |
| 96 base::HistogramSnapshotManager snapshot_manager(&flattener); |
| 97 snapshot_manager.StartDeltas(); |
| 98 provider_.RecordHistogramSnapshots(&snapshot_manager); |
| 99 snapshot_manager.FinishDeltas(); |
| 100 return flattener.GetRecordedDeltaHistogramNames().size(); |
| 101 } |
| 102 |
| 103 void EnableRecording() { provider_.OnRecordingEnabled(); } |
| 104 void DisableRecording() { provider_.OnRecordingDisabled(); } |
| 105 |
| 106 void RegisterSubprocessAllocator( |
| 107 int id, |
| 108 std::unique_ptr<base::PersistentHistogramAllocator> allocator) { |
| 109 provider_.RegisterSubprocessAllocator(id, std::move(allocator)); |
| 110 } |
| 111 |
| 112 void DeregisterSubprocessAllocator(int id) { |
| 113 provider_.DeregisterSubprocessAllocator(id); |
| 114 } |
| 115 |
| 116 private: |
| 117 SubprocessMetricsProvider provider_; |
| 118 |
| 119 DISALLOW_COPY_AND_ASSIGN(SubprocessMetricsProviderTest); |
| 120 }; |
| 121 |
| 122 TEST_F(SubprocessMetricsProviderTest, SnapshotMetrics) { |
| 123 base::HistogramBase* foo = base::Histogram::FactoryGet("foo", 1, 100, 10, 0); |
| 124 base::HistogramBase* bar = base::Histogram::FactoryGet("bar", 1, 100, 10, 0); |
| 125 foo->Add(42); |
| 126 bar->Add(84); |
| 127 |
| 128 // Register an allocator that duplicates the global allocator. |
| 129 RegisterSubprocessAllocator(123, GetDuplicateAllocator()); |
| 130 |
| 131 // Recording should find the two histograms created in persistent memory. |
| 132 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 133 |
| 134 // A second run should have nothing to produce. |
| 135 EXPECT_EQ(0U, GetSnapshotHistogramCount()); |
| 136 |
| 137 // Create a new histogram and update existing ones. Should now report 3 items. |
| 138 base::HistogramBase* baz = base::Histogram::FactoryGet("baz", 1, 100, 10, 0); |
| 139 baz->Add(1969); |
| 140 foo->Add(10); |
| 141 bar->Add(20); |
| 142 EXPECT_EQ(3U, GetSnapshotHistogramCount()); |
| 143 |
| 144 // Ensure that deregistering still keeps allocator around for final report. |
| 145 foo->Add(10); |
| 146 bar->Add(20); |
| 147 DeregisterSubprocessAllocator(123); |
| 148 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 149 |
| 150 // Further snapshots should be empty even if things have changed. |
| 151 foo->Add(10); |
| 152 bar->Add(20); |
| 153 EXPECT_EQ(0U, GetSnapshotHistogramCount()); |
| 154 } |
| 155 |
| 156 TEST_F(SubprocessMetricsProviderTest, EnableDisable) { |
| 157 base::HistogramBase* foo = base::Histogram::FactoryGet("foo", 1, 100, 10, 0); |
| 158 base::HistogramBase* bar = base::Histogram::FactoryGet("bar", 1, 100, 10, 0); |
| 159 |
| 160 // Simulate some "normal" operation... |
| 161 RegisterSubprocessAllocator(123, GetDuplicateAllocator()); |
| 162 foo->Add(42); |
| 163 bar->Add(84); |
| 164 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 165 foo->Add(42); |
| 166 bar->Add(84); |
| 167 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 168 |
| 169 // Ensure that disable/enable reporting won't affect "live" allocators. |
| 170 DisableRecording(); |
| 171 EnableRecording(); |
| 172 foo->Add(42); |
| 173 bar->Add(84); |
| 174 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 175 |
| 176 // Ensure that allocators are released when reporting is disabled. |
| 177 DisableRecording(); |
| 178 DeregisterSubprocessAllocator(123); |
| 179 EnableRecording(); |
| 180 foo->Add(42); |
| 181 bar->Add(84); |
| 182 EXPECT_EQ(0U, GetSnapshotHistogramCount()); |
| 183 |
| 184 // Ensure that allocators added when reporting disabled will work if enabled. |
| 185 DisableRecording(); |
| 186 RegisterSubprocessAllocator(123, GetDuplicateAllocator()); |
| 187 EnableRecording(); |
| 188 foo->Add(42); |
| 189 bar->Add(84); |
| 190 EXPECT_EQ(2U, GetSnapshotHistogramCount()); |
| 191 |
| 192 // Ensure that last-chance allocators are released if reporting is disabled. |
| 193 DeregisterSubprocessAllocator(123); |
| 194 DisableRecording(); |
| 195 EnableRecording(); |
| 196 foo->Add(42); |
| 197 bar->Add(84); |
| 198 EXPECT_EQ(0U, GetSnapshotHistogramCount()); |
| 199 } |
OLD | NEW |