• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PersistentHistogramAllocatorTest()22   PersistentHistogramAllocatorTest()
23       : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) {
24     CreatePersistentHistogramAllocator();
25   }
~PersistentHistogramAllocatorTest()26   ~PersistentHistogramAllocatorTest() override {
27     DestroyPersistentHistogramAllocator();
28   }
29 
CreatePersistentHistogramAllocator()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 
DestroyPersistentHistogramAllocator()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 
TEST_F(PersistentHistogramAllocatorTest,CreateAndIterateTest)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 
TEST_F(PersistentHistogramAllocatorTest,CreateWithFileTest)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 
TEST_F(PersistentHistogramAllocatorTest,StatisticsRecorderTest)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