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 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/logging.h" 9 #include "base/memory/ptr_util.h" 10 #include "base/metrics/bucket_ranges.h" 11 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/persistent_memory_allocator.h" 13 #include "base/metrics/statistics_recorder.h" 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 22 PersistentHistogramAllocatorTest() 23 : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) { 24 CreatePersistentHistogramAllocator(); 25 } 26 ~PersistentHistogramAllocatorTest() override { 27 DestroyPersistentHistogramAllocator(); 28 } 29 30 void CreatePersistentHistogramAllocator() { 31 allocator_memory_.reset(new char[kAllocatorMemorySize]); 32 33 GlobalHistogramAllocator::ReleaseForTesting(); 34 memset(allocator_memory_.get(), 0, kAllocatorMemorySize); 35 GlobalHistogramAllocator::GetCreateHistogramResultHistogram(); 36 GlobalHistogramAllocator::CreateWithPersistentMemory( 37 allocator_memory_.get(), kAllocatorMemorySize, 0, 0, 38 "PersistentHistogramAllocatorTest"); 39 allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); 40 } 41 42 void DestroyPersistentHistogramAllocator() { 43 allocator_ = nullptr; 44 GlobalHistogramAllocator::ReleaseForTesting(); 45 } 46 47 std::unique_ptr<StatisticsRecorder> statistics_recorder_; 48 std::unique_ptr<char[]> allocator_memory_; 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 95 PersistentMemoryAllocator::Iterator iter(allocator_); 96 uint32_t type; 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)); 102 103 // Create a second allocator and have it access the memory of the first. 104 std::unique_ptr<HistogramBase> recovered; 105 PersistentHistogramAllocator recovery( 106 WrapUnique(new PersistentMemoryAllocator( 107 allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false))); 108 PersistentHistogramAllocator::Iterator histogram_iter(&recovery); 109 110 recovered = histogram_iter.GetNext(); 111 ASSERT_TRUE(recovered); 112 recovered->CheckName("TestHistogram"); 113 114 recovered = histogram_iter.GetNext(); 115 ASSERT_TRUE(recovered); 116 recovered->CheckName("TestLinearHistogram"); 117 118 recovered = histogram_iter.GetNext(); 119 ASSERT_TRUE(recovered); 120 recovered->CheckName("TestBooleanHistogram"); 121 122 recovered = histogram_iter.GetNext(); 123 ASSERT_TRUE(recovered); 124 recovered->CheckName("TestCustomHistogram"); 125 126 recovered = histogram_iter.GetNext(); 127 EXPECT_FALSE(recovered); 128 } 129 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 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 = 165 StatisticsRecorder::CreateTemporaryForTesting(); 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. 193 recovery.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); 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 209 } // namespace base 210