bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 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 "base/metrics/persistent_histogram_allocator.h" |
| 6 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 7 | #include "base/files/scoped_temp_dir.h" |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 8 | #include "base/logging.h" |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 9 | #include "base/memory/ptr_util.h" |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 10 | #include "base/metrics/bucket_ranges.h" |
| 11 | #include "base/metrics/histogram_macros.h" |
| 12 | #include "base/metrics/persistent_memory_allocator.h" |
bcwhite | 05dc092 | 2016-06-03 04:59:44 | [diff] [blame] | 13 | #include "base/metrics/statistics_recorder.h" |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 14 | #include "testing/gtest/include/gtest/gtest.h" |
| 15 | |
| 16 | namespace base { |
| 17 | |
| 18 | class PersistentHistogramAllocatorTest : public testing::Test { |
| 19 | protected: |
| 20 | const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB |
| 21 | |
bcwhite | 9e3835cc | 2016-06-03 17:56:35 | [diff] [blame] | 22 | PersistentHistogramAllocatorTest() |
| 23 | : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) { |
| 24 | CreatePersistentHistogramAllocator(); |
| 25 | } |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 26 | ~PersistentHistogramAllocatorTest() override { |
| 27 | DestroyPersistentHistogramAllocator(); |
| 28 | } |
| 29 | |
| 30 | void CreatePersistentHistogramAllocator() { |
| 31 | allocator_memory_.reset(new char[kAllocatorMemorySize]); |
| 32 | |
bcwhite | 5e748c6 | 2016-04-06 02:03:53 | [diff] [blame] | 33 | GlobalHistogramAllocator::ReleaseForTesting(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 34 | memset(allocator_memory_.get(), 0, kAllocatorMemorySize); |
bcwhite | 5e748c6 | 2016-04-06 02:03:53 | [diff] [blame] | 35 | GlobalHistogramAllocator::GetCreateHistogramResultHistogram(); |
| 36 | GlobalHistogramAllocator::CreateWithPersistentMemory( |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 37 | allocator_memory_.get(), kAllocatorMemorySize, 0, 0, |
| 38 | "PersistentHistogramAllocatorTest"); |
bcwhite | 5e748c6 | 2016-04-06 02:03:53 | [diff] [blame] | 39 | allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | void DestroyPersistentHistogramAllocator() { |
| 43 | allocator_ = nullptr; |
bcwhite | 5e748c6 | 2016-04-06 02:03:53 | [diff] [blame] | 44 | GlobalHistogramAllocator::ReleaseForTesting(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 45 | } |
| 46 | |
bcwhite | 9e3835cc | 2016-06-03 17:56:35 | [diff] [blame] | 47 | std::unique_ptr<StatisticsRecorder> statistics_recorder_; |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 48 | std::unique_ptr<char[]> allocator_memory_; |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 49 | PersistentMemoryAllocator* allocator_ = nullptr; |
| 50 | |
| 51 | private: |
| 52 | DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocatorTest); |
| 53 | }; |
| 54 | |
| 55 | TEST_F(PersistentHistogramAllocatorTest, CreateAndIterateTest) { |
| 56 | PersistentMemoryAllocator::MemoryInfo meminfo0; |
| 57 | allocator_->GetMemoryInfo(&meminfo0); |
| 58 | |
| 59 | // Try basic construction |
| 60 | HistogramBase* histogram = Histogram::FactoryGet( |
| 61 | "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent); |
| 62 | EXPECT_TRUE(histogram); |
| 63 | histogram->CheckName("TestHistogram"); |
| 64 | PersistentMemoryAllocator::MemoryInfo meminfo1; |
| 65 | allocator_->GetMemoryInfo(&meminfo1); |
| 66 | EXPECT_GT(meminfo0.free, meminfo1.free); |
| 67 | |
| 68 | HistogramBase* linear_histogram = LinearHistogram::FactoryGet( |
| 69 | "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent); |
| 70 | EXPECT_TRUE(linear_histogram); |
| 71 | linear_histogram->CheckName("TestLinearHistogram"); |
| 72 | PersistentMemoryAllocator::MemoryInfo meminfo2; |
| 73 | allocator_->GetMemoryInfo(&meminfo2); |
| 74 | EXPECT_GT(meminfo1.free, meminfo2.free); |
| 75 | |
| 76 | HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet( |
| 77 | "TestBooleanHistogram", HistogramBase::kIsPersistent); |
| 78 | EXPECT_TRUE(boolean_histogram); |
| 79 | boolean_histogram->CheckName("TestBooleanHistogram"); |
| 80 | PersistentMemoryAllocator::MemoryInfo meminfo3; |
| 81 | allocator_->GetMemoryInfo(&meminfo3); |
| 82 | EXPECT_GT(meminfo2.free, meminfo3.free); |
| 83 | |
| 84 | std::vector<int> custom_ranges; |
| 85 | custom_ranges.push_back(1); |
| 86 | custom_ranges.push_back(5); |
| 87 | HistogramBase* custom_histogram = CustomHistogram::FactoryGet( |
| 88 | "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent); |
| 89 | EXPECT_TRUE(custom_histogram); |
| 90 | custom_histogram->CheckName("TestCustomHistogram"); |
| 91 | PersistentMemoryAllocator::MemoryInfo meminfo4; |
| 92 | allocator_->GetMemoryInfo(&meminfo4); |
| 93 | EXPECT_GT(meminfo3.free, meminfo4.free); |
| 94 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 95 | PersistentMemoryAllocator::Iterator iter(allocator_); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 96 | uint32_t type; |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 97 | EXPECT_NE(0U, iter.GetNext(&type)); // Histogram |
| 98 | EXPECT_NE(0U, iter.GetNext(&type)); // LinearHistogram |
| 99 | EXPECT_NE(0U, iter.GetNext(&type)); // BooleanHistogram |
| 100 | EXPECT_NE(0U, iter.GetNext(&type)); // CustomHistogram |
| 101 | EXPECT_EQ(0U, iter.GetNext(&type)); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 102 | |
| 103 | // Create a second allocator and have it access the memory of the first. |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 104 | std::unique_ptr<HistogramBase> recovered; |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 105 | PersistentHistogramAllocator recovery( |
dcheng | 093de9b | 2016-04-04 21:25:51 | [diff] [blame] | 106 | WrapUnique(new PersistentMemoryAllocator( |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 107 | allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false))); |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 108 | PersistentHistogramAllocator::Iterator histogram_iter(&recovery); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 109 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 110 | recovered = histogram_iter.GetNext(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 111 | ASSERT_TRUE(recovered); |
| 112 | recovered->CheckName("TestHistogram"); |
| 113 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 114 | recovered = histogram_iter.GetNext(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 115 | ASSERT_TRUE(recovered); |
| 116 | recovered->CheckName("TestLinearHistogram"); |
| 117 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 118 | recovered = histogram_iter.GetNext(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 119 | ASSERT_TRUE(recovered); |
| 120 | recovered->CheckName("TestBooleanHistogram"); |
| 121 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 122 | recovered = histogram_iter.GetNext(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 123 | ASSERT_TRUE(recovered); |
| 124 | recovered->CheckName("TestCustomHistogram"); |
| 125 | |
bcwhite | f246202 | 2016-04-06 15:39:01 | [diff] [blame] | 126 | recovered = histogram_iter.GetNext(); |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 127 | EXPECT_FALSE(recovered); |
| 128 | } |
| 129 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 130 | TEST_F(PersistentHistogramAllocatorTest, CreateWithFileTest) { |
| 131 | const char temp_name[] = "CreateWithFileTest"; |
| 132 | ScopedTempDir temp_dir; |
| 133 | ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 134 | FilePath temp_file = temp_dir.path().AppendASCII(temp_name); |
| 135 | const size_t temp_size = 64 << 10; // 64 KiB |
| 136 | |
| 137 | // Test creation of a new file. |
| 138 | GlobalHistogramAllocator::ReleaseForTesting(); |
| 139 | GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name); |
| 140 | EXPECT_EQ(std::string(temp_name), |
| 141 | GlobalHistogramAllocator::Get()->memory_allocator()->Name()); |
| 142 | |
| 143 | // Test re-open of a possibly-existing file. |
| 144 | GlobalHistogramAllocator::ReleaseForTesting(); |
| 145 | GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, ""); |
| 146 | EXPECT_EQ(std::string(temp_name), |
| 147 | GlobalHistogramAllocator::Get()->memory_allocator()->Name()); |
| 148 | |
| 149 | // Test re-open of an known-existing file. |
| 150 | GlobalHistogramAllocator::ReleaseForTesting(); |
| 151 | GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, ""); |
| 152 | EXPECT_EQ(std::string(temp_name), |
| 153 | GlobalHistogramAllocator::Get()->memory_allocator()->Name()); |
| 154 | |
| 155 | // Final release so file and temp-dir can be removed. |
| 156 | GlobalHistogramAllocator::ReleaseForTesting(); |
| 157 | } |
| 158 | |
bcwhite | 05dc092 | 2016-06-03 04:59:44 | [diff] [blame] | 159 | TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderTest) { |
| 160 | size_t starting_sr_count = StatisticsRecorder::GetHistogramCount(); |
| 161 | |
| 162 | // Create a local StatisticsRecorder in which the newly created histogram |
| 163 | // will be recorded. |
| 164 | std::unique_ptr<StatisticsRecorder> local_sr = |
bcwhite | 9e3835cc | 2016-06-03 17:56:35 | [diff] [blame] | 165 | StatisticsRecorder::CreateTemporaryForTesting(); |
bcwhite | 05dc092 | 2016-06-03 04:59:44 | [diff] [blame] | 166 | EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount()); |
| 167 | |
| 168 | HistogramBase* histogram = LinearHistogram::FactoryGet( |
| 169 | "TestHistogram", 1, 10, 10, HistogramBase::kIsPersistent); |
| 170 | EXPECT_TRUE(histogram); |
| 171 | EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount()); |
| 172 | histogram->Add(3); |
| 173 | histogram->Add(1); |
| 174 | histogram->Add(4); |
| 175 | histogram->Add(1); |
| 176 | histogram->Add(6); |
| 177 | |
| 178 | // Destroy the local SR and ensure that we're back to the initial state. |
| 179 | local_sr.reset(); |
| 180 | EXPECT_EQ(starting_sr_count, StatisticsRecorder::GetHistogramCount()); |
| 181 | |
| 182 | // Create a second allocator and have it access the memory of the first. |
| 183 | std::unique_ptr<HistogramBase> recovered; |
| 184 | PersistentHistogramAllocator recovery( |
| 185 | WrapUnique(new PersistentMemoryAllocator( |
| 186 | allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false))); |
| 187 | PersistentHistogramAllocator::Iterator histogram_iter(&recovery); |
| 188 | |
| 189 | recovered = histogram_iter.GetNext(); |
| 190 | ASSERT_TRUE(recovered); |
| 191 | |
| 192 | // Merge the recovered histogram to the SR. It will always be a new object. |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 193 | recovery.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); |
bcwhite | 05dc092 | 2016-06-03 04:59:44 | [diff] [blame] | 194 | EXPECT_EQ(starting_sr_count + 1, StatisticsRecorder::GetHistogramCount()); |
| 195 | HistogramBase* found = |
| 196 | StatisticsRecorder::FindHistogram(recovered->histogram_name()); |
| 197 | ASSERT_TRUE(found); |
| 198 | EXPECT_NE(recovered.get(), found); |
| 199 | |
| 200 | // Ensure that the data got merged, too. |
| 201 | std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples(); |
| 202 | EXPECT_EQ(recovered->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); |
| 203 | EXPECT_EQ(1, snapshot->GetCount(3)); |
| 204 | EXPECT_EQ(2, snapshot->GetCount(1)); |
| 205 | EXPECT_EQ(1, snapshot->GetCount(4)); |
| 206 | EXPECT_EQ(1, snapshot->GetCount(6)); |
| 207 | } |
| 208 | |
bcwhite | 33d95806a | 2016-03-16 02:37:45 | [diff] [blame] | 209 | } // namespace base |