persistent_histogram_allocator_unittest.cc revision 0601274935e7f632eb0d6ce0fd223b744349d20b
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 16namespace base { 17 18class 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 55TEST_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(MakeUnique<PersistentMemoryAllocator>( 106 allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false)); 107 PersistentHistogramAllocator::Iterator histogram_iter(&recovery); 108 109 recovered = histogram_iter.GetNext(); 110 ASSERT_TRUE(recovered); 111 recovered->CheckName("TestHistogram"); 112 113 recovered = histogram_iter.GetNext(); 114 ASSERT_TRUE(recovered); 115 recovered->CheckName("TestLinearHistogram"); 116 117 recovered = histogram_iter.GetNext(); 118 ASSERT_TRUE(recovered); 119 recovered->CheckName("TestBooleanHistogram"); 120 121 recovered = histogram_iter.GetNext(); 122 ASSERT_TRUE(recovered); 123 recovered->CheckName("TestCustomHistogram"); 124 125 recovered = histogram_iter.GetNext(); 126 EXPECT_FALSE(recovered); 127} 128 129TEST_F(PersistentHistogramAllocatorTest, CreateWithFileTest) { 130 const char temp_name[] = "CreateWithFileTest"; 131 ScopedTempDir temp_dir; 132 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 133 FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name); 134 const size_t temp_size = 64 << 10; // 64 KiB 135 136 // Test creation of a new file. 137 GlobalHistogramAllocator::ReleaseForTesting(); 138 GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name); 139 EXPECT_EQ(std::string(temp_name), 140 GlobalHistogramAllocator::Get()->memory_allocator()->Name()); 141 142 // Test re-open of a possibly-existing file. 143 GlobalHistogramAllocator::ReleaseForTesting(); 144 GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, ""); 145 EXPECT_EQ(std::string(temp_name), 146 GlobalHistogramAllocator::Get()->memory_allocator()->Name()); 147 148 // Test re-open of an known-existing file. 149 GlobalHistogramAllocator::ReleaseForTesting(); 150 GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, ""); 151 EXPECT_EQ(std::string(temp_name), 152 GlobalHistogramAllocator::Get()->memory_allocator()->Name()); 153 154 // Final release so file and temp-dir can be removed. 155 GlobalHistogramAllocator::ReleaseForTesting(); 156} 157 158TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderMergeTest) { 159 const char LinearHistogramName[] = "SRTLinearHistogram"; 160 const char SparseHistogramName[] = "SRTSparseHistogram"; 161 const size_t starting_sr_count = StatisticsRecorder::GetHistogramCount(); 162 163 // Create a local StatisticsRecorder in which the newly created histogram 164 // will be recorded. The global allocator must be replaced after because the 165 // act of releasing will cause the active SR to forget about all histograms 166 // in the relased memory. 167 std::unique_ptr<StatisticsRecorder> local_sr = 168 StatisticsRecorder::CreateTemporaryForTesting(); 169 EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount()); 170 std::unique_ptr<GlobalHistogramAllocator> old_allocator = 171 GlobalHistogramAllocator::ReleaseForTesting(); 172 GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, ""); 173 ASSERT_TRUE(GlobalHistogramAllocator::Get()); 174 175 // Create a linear histogram for merge testing. 176 HistogramBase* histogram1 = 177 LinearHistogram::FactoryGet(LinearHistogramName, 1, 10, 10, 0); 178 ASSERT_TRUE(histogram1); 179 EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount()); 180 histogram1->Add(3); 181 histogram1->Add(1); 182 histogram1->Add(4); 183 histogram1->AddCount(1, 4); 184 histogram1->Add(6); 185 186 // Create a sparse histogram for merge testing. 187 HistogramBase* histogram2 = 188 SparseHistogram::FactoryGet(SparseHistogramName, 0); 189 ASSERT_TRUE(histogram2); 190 EXPECT_EQ(2U, StatisticsRecorder::GetHistogramCount()); 191 histogram2->Add(3); 192 histogram2->Add(1); 193 histogram2->Add(4); 194 histogram2->AddCount(1, 4); 195 histogram2->Add(6); 196 197 // Destroy the local SR and ensure that we're back to the initial state and 198 // restore the global allocator. Histograms created in the local SR will 199 // become unmanaged. 200 std::unique_ptr<GlobalHistogramAllocator> new_allocator = 201 GlobalHistogramAllocator::ReleaseForTesting(); 202 local_sr.reset(); 203 EXPECT_EQ(starting_sr_count, StatisticsRecorder::GetHistogramCount()); 204 GlobalHistogramAllocator::Set(std::move(old_allocator)); 205 206 // Create a "recovery" allocator using the same memory as the local one. 207 PersistentHistogramAllocator recovery1(MakeUnique<PersistentMemoryAllocator>( 208 const_cast<void*>(new_allocator->memory_allocator()->data()), 209 new_allocator->memory_allocator()->size(), 0, 0, "", false)); 210 PersistentHistogramAllocator::Iterator histogram_iter1(&recovery1); 211 212 // Get the histograms that were created locally (and forgotten) and merge 213 // them into the global SR. New objects will be created. 214 std::unique_ptr<HistogramBase> recovered; 215 while (true) { 216 recovered = histogram_iter1.GetNext(); 217 if (!recovered) 218 break; 219 220 recovery1.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); 221 HistogramBase* found = 222 StatisticsRecorder::FindHistogram(recovered->histogram_name()); 223 EXPECT_NE(recovered.get(), found); 224 }; 225 EXPECT_EQ(starting_sr_count + 2, StatisticsRecorder::GetHistogramCount()); 226 227 // Check the merged histograms for accuracy. 228 HistogramBase* found = StatisticsRecorder::FindHistogram(LinearHistogramName); 229 ASSERT_TRUE(found); 230 std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples(); 231 EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); 232 EXPECT_EQ(1, snapshot->GetCount(3)); 233 EXPECT_EQ(5, snapshot->GetCount(1)); 234 EXPECT_EQ(1, snapshot->GetCount(4)); 235 EXPECT_EQ(1, snapshot->GetCount(6)); 236 237 found = StatisticsRecorder::FindHistogram(SparseHistogramName); 238 ASSERT_TRUE(found); 239 snapshot = found->SnapshotSamples(); 240 EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); 241 EXPECT_EQ(1, snapshot->GetCount(3)); 242 EXPECT_EQ(5, snapshot->GetCount(1)); 243 EXPECT_EQ(1, snapshot->GetCount(4)); 244 EXPECT_EQ(1, snapshot->GetCount(6)); 245 246 // Perform additional histogram increments. 247 histogram1->AddCount(1, 3); 248 histogram1->Add(6); 249 histogram2->AddCount(1, 3); 250 histogram2->Add(7); 251 252 // Do another merge. 253 PersistentHistogramAllocator recovery2(MakeUnique<PersistentMemoryAllocator>( 254 const_cast<void*>(new_allocator->memory_allocator()->data()), 255 new_allocator->memory_allocator()->size(), 0, 0, "", false)); 256 PersistentHistogramAllocator::Iterator histogram_iter2(&recovery2); 257 while (true) { 258 recovered = histogram_iter2.GetNext(); 259 if (!recovered) 260 break; 261 recovery2.MergeHistogramDeltaToStatisticsRecorder(recovered.get()); 262 }; 263 EXPECT_EQ(starting_sr_count + 2, StatisticsRecorder::GetHistogramCount()); 264 265 // And verify. 266 found = StatisticsRecorder::FindHistogram(LinearHistogramName); 267 snapshot = found->SnapshotSamples(); 268 EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); 269 EXPECT_EQ(1, snapshot->GetCount(3)); 270 EXPECT_EQ(8, snapshot->GetCount(1)); 271 EXPECT_EQ(1, snapshot->GetCount(4)); 272 EXPECT_EQ(2, snapshot->GetCount(6)); 273 274 found = StatisticsRecorder::FindHistogram(SparseHistogramName); 275 snapshot = found->SnapshotSamples(); 276 EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount()); 277 EXPECT_EQ(1, snapshot->GetCount(3)); 278 EXPECT_EQ(8, snapshot->GetCount(1)); 279 EXPECT_EQ(1, snapshot->GetCount(4)); 280 EXPECT_EQ(1, snapshot->GetCount(6)); 281 EXPECT_EQ(1, snapshot->GetCount(7)); 282} 283 284} // namespace base 285