OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/sparse_histogram.h" | 5 #include "base/metrics/sparse_histogram.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/metrics/histogram_base.h" | 10 #include "base/metrics/histogram_base.h" |
11 #include "base/metrics/histogram_samples.h" | 11 #include "base/metrics/histogram_samples.h" |
| 12 #include "base/metrics/persistent_histogram_allocator.h" |
| 13 #include "base/metrics/persistent_memory_allocator.h" |
12 #include "base/metrics/sample_map.h" | 14 #include "base/metrics/sample_map.h" |
13 #include "base/metrics/statistics_recorder.h" | 15 #include "base/metrics/statistics_recorder.h" |
14 #include "base/pickle.h" | 16 #include "base/pickle.h" |
15 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
17 | 19 |
18 namespace base { | 20 namespace base { |
19 | 21 |
20 class SparseHistogramTest : public testing::Test { | 22 // Test parameter indicates if a persistent memory allocator should be used |
| 23 // for histogram allocation. False will allocate histograms from the process |
| 24 // heap. |
| 25 class SparseHistogramTest : public testing::TestWithParam<bool> { |
21 protected: | 26 protected: |
| 27 const int32_t kAllocatorMemorySize = 8 << 20; // 8 MiB |
| 28 |
| 29 SparseHistogramTest() : use_persistent_histogram_allocator_(GetParam()) {} |
| 30 |
22 void SetUp() override { | 31 void SetUp() override { |
| 32 if (use_persistent_histogram_allocator_) |
| 33 CreatePersistentMemoryAllocator(); |
| 34 |
23 // Each test will have a clean state (no Histogram / BucketRanges | 35 // Each test will have a clean state (no Histogram / BucketRanges |
24 // registered). | 36 // registered). |
25 InitializeStatisticsRecorder(); | 37 InitializeStatisticsRecorder(); |
26 } | 38 } |
27 | 39 |
28 void TearDown() override { UninitializeStatisticsRecorder(); } | 40 void TearDown() override { |
| 41 if (allocator_) { |
| 42 ASSERT_FALSE(allocator_->IsFull()); |
| 43 ASSERT_FALSE(allocator_->IsCorrupt()); |
| 44 } |
| 45 UninitializeStatisticsRecorder(); |
| 46 DestroyPersistentMemoryAllocator(); |
| 47 } |
29 | 48 |
30 void InitializeStatisticsRecorder() { | 49 void InitializeStatisticsRecorder() { |
| 50 StatisticsRecorder::ResetForTesting(); |
31 statistics_recorder_ = new StatisticsRecorder(); | 51 statistics_recorder_ = new StatisticsRecorder(); |
32 } | 52 } |
33 | 53 |
34 void UninitializeStatisticsRecorder() { | 54 void UninitializeStatisticsRecorder() { |
35 delete statistics_recorder_; | 55 delete statistics_recorder_; |
36 statistics_recorder_ = NULL; | 56 statistics_recorder_ = NULL; |
37 } | 57 } |
38 | 58 |
| 59 void CreatePersistentMemoryAllocator() { |
| 60 // By getting the results-histogram before any persistent allocator |
| 61 // is attached, that histogram is guaranteed not to be stored in |
| 62 // any persistent memory segment (which simplifies some tests). |
| 63 PersistentHistogramAllocator::GetCreateHistogramResultHistogram(); |
| 64 |
| 65 PersistentHistogramAllocator::CreateGlobalAllocatorOnLocalMemory( |
| 66 kAllocatorMemorySize, 0, "SparseHistogramAllocatorTest"); |
| 67 allocator_ = |
| 68 PersistentHistogramAllocator::GetGlobalAllocator()->memory_allocator(); |
| 69 } |
| 70 |
| 71 void DestroyPersistentMemoryAllocator() { |
| 72 allocator_ = nullptr; |
| 73 PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting(); |
| 74 } |
| 75 |
39 scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) { | 76 scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) { |
40 return scoped_ptr<SparseHistogram>(new SparseHistogram(name)); | 77 return scoped_ptr<SparseHistogram>(new SparseHistogram(name)); |
41 } | 78 } |
42 | 79 |
| 80 const bool use_persistent_histogram_allocator_; |
| 81 |
43 StatisticsRecorder* statistics_recorder_; | 82 StatisticsRecorder* statistics_recorder_; |
| 83 scoped_ptr<char[]> allocator_memory_; |
| 84 PersistentMemoryAllocator* allocator_ = nullptr; |
| 85 |
| 86 private: |
| 87 DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest); |
44 }; | 88 }; |
45 | 89 |
46 TEST_F(SparseHistogramTest, BasicTest) { | 90 // Run all HistogramTest cases with both heap and persistent memory. |
| 91 INSTANTIATE_TEST_CASE_P(HeapAndPersistent, |
| 92 SparseHistogramTest, |
| 93 testing::Bool()); |
| 94 |
| 95 |
| 96 TEST_P(SparseHistogramTest, BasicTest) { |
47 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 97 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
48 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 98 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
49 EXPECT_EQ(0, snapshot->TotalCount()); | 99 EXPECT_EQ(0, snapshot->TotalCount()); |
50 EXPECT_EQ(0, snapshot->sum()); | 100 EXPECT_EQ(0, snapshot->sum()); |
51 | 101 |
52 histogram->Add(100); | 102 histogram->Add(100); |
53 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 103 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
54 EXPECT_EQ(1, snapshot1->TotalCount()); | 104 EXPECT_EQ(1, snapshot1->TotalCount()); |
55 EXPECT_EQ(1, snapshot1->GetCount(100)); | 105 EXPECT_EQ(1, snapshot1->GetCount(100)); |
56 | 106 |
57 histogram->Add(100); | 107 histogram->Add(100); |
58 histogram->Add(101); | 108 histogram->Add(101); |
59 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 109 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
60 EXPECT_EQ(3, snapshot2->TotalCount()); | 110 EXPECT_EQ(3, snapshot2->TotalCount()); |
61 EXPECT_EQ(2, snapshot2->GetCount(100)); | 111 EXPECT_EQ(2, snapshot2->GetCount(100)); |
62 EXPECT_EQ(1, snapshot2->GetCount(101)); | 112 EXPECT_EQ(1, snapshot2->GetCount(101)); |
63 } | 113 } |
64 | 114 |
65 TEST_F(SparseHistogramTest, BasicTestAddCount) { | 115 TEST_P(SparseHistogramTest, BasicTestAddCount) { |
66 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 116 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
67 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 117 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
68 EXPECT_EQ(0, snapshot->TotalCount()); | 118 EXPECT_EQ(0, snapshot->TotalCount()); |
69 EXPECT_EQ(0, snapshot->sum()); | 119 EXPECT_EQ(0, snapshot->sum()); |
70 | 120 |
71 histogram->AddCount(100, 15); | 121 histogram->AddCount(100, 15); |
72 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 122 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
73 EXPECT_EQ(15, snapshot1->TotalCount()); | 123 EXPECT_EQ(15, snapshot1->TotalCount()); |
74 EXPECT_EQ(15, snapshot1->GetCount(100)); | 124 EXPECT_EQ(15, snapshot1->GetCount(100)); |
75 | 125 |
76 histogram->AddCount(100, 15); | 126 histogram->AddCount(100, 15); |
77 histogram->AddCount(101, 25); | 127 histogram->AddCount(101, 25); |
78 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 128 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
79 EXPECT_EQ(55, snapshot2->TotalCount()); | 129 EXPECT_EQ(55, snapshot2->TotalCount()); |
80 EXPECT_EQ(30, snapshot2->GetCount(100)); | 130 EXPECT_EQ(30, snapshot2->GetCount(100)); |
81 EXPECT_EQ(25, snapshot2->GetCount(101)); | 131 EXPECT_EQ(25, snapshot2->GetCount(101)); |
82 } | 132 } |
83 | 133 |
84 TEST_F(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { | 134 TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { |
85 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 135 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
86 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 136 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
87 EXPECT_EQ(0, snapshot->TotalCount()); | 137 EXPECT_EQ(0, snapshot->TotalCount()); |
88 EXPECT_EQ(0, snapshot->sum()); | 138 EXPECT_EQ(0, snapshot->sum()); |
89 | 139 |
90 histogram->AddCount(1000000000, 15); | 140 histogram->AddCount(1000000000, 15); |
91 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 141 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
92 EXPECT_EQ(15, snapshot1->TotalCount()); | 142 EXPECT_EQ(15, snapshot1->TotalCount()); |
93 EXPECT_EQ(15, snapshot1->GetCount(1000000000)); | 143 EXPECT_EQ(15, snapshot1->GetCount(1000000000)); |
94 | 144 |
95 histogram->AddCount(1000000000, 15); | 145 histogram->AddCount(1000000000, 15); |
96 histogram->AddCount(1010000000, 25); | 146 histogram->AddCount(1010000000, 25); |
97 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 147 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
98 EXPECT_EQ(55, snapshot2->TotalCount()); | 148 EXPECT_EQ(55, snapshot2->TotalCount()); |
99 EXPECT_EQ(30, snapshot2->GetCount(1000000000)); | 149 EXPECT_EQ(30, snapshot2->GetCount(1000000000)); |
100 EXPECT_EQ(25, snapshot2->GetCount(1010000000)); | 150 EXPECT_EQ(25, snapshot2->GetCount(1010000000)); |
101 EXPECT_EQ(55250000000LL, snapshot2->sum()); | 151 EXPECT_EQ(55250000000LL, snapshot2->sum()); |
102 } | 152 } |
103 | 153 |
104 TEST_F(SparseHistogramTest, MacroBasicTest) { | 154 TEST_P(SparseHistogramTest, MacroBasicTest) { |
105 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); | 155 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); |
106 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200); | 156 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200); |
107 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); | 157 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); |
108 | 158 |
109 StatisticsRecorder::Histograms histograms; | 159 StatisticsRecorder::Histograms histograms; |
110 StatisticsRecorder::GetHistograms(&histograms); | 160 StatisticsRecorder::GetHistograms(&histograms); |
111 | 161 |
112 ASSERT_EQ(1U, histograms.size()); | 162 ASSERT_EQ(1U, histograms.size()); |
113 HistogramBase* sparse_histogram = histograms[0]; | 163 HistogramBase* sparse_histogram = histograms[0]; |
114 | 164 |
115 EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); | 165 EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); |
116 EXPECT_EQ("Sparse", sparse_histogram->histogram_name()); | 166 EXPECT_EQ("Sparse", sparse_histogram->histogram_name()); |
117 EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, | 167 EXPECT_EQ( |
118 sparse_histogram->flags()); | 168 HistogramBase::kUmaTargetedHistogramFlag | |
| 169 (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent |
| 170 : 0), |
| 171 sparse_histogram->flags()); |
119 | 172 |
120 scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples(); | 173 scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples(); |
121 EXPECT_EQ(3, samples->TotalCount()); | 174 EXPECT_EQ(3, samples->TotalCount()); |
122 EXPECT_EQ(2, samples->GetCount(100)); | 175 EXPECT_EQ(2, samples->GetCount(100)); |
123 EXPECT_EQ(1, samples->GetCount(200)); | 176 EXPECT_EQ(1, samples->GetCount(200)); |
124 } | 177 } |
125 | 178 |
126 TEST_F(SparseHistogramTest, MacroInLoopTest) { | 179 TEST_P(SparseHistogramTest, MacroInLoopTest) { |
127 // Unlike the macros in histogram.h, SparseHistogram macros can have a | 180 // Unlike the macros in histogram.h, SparseHistogram macros can have a |
128 // variable as histogram name. | 181 // variable as histogram name. |
129 for (int i = 0; i < 2; i++) { | 182 for (int i = 0; i < 2; i++) { |
130 std::string name = StringPrintf("Sparse%d", i + 1); | 183 std::string name = StringPrintf("Sparse%d", i + 1); |
131 UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100); | 184 UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100); |
132 } | 185 } |
133 | 186 |
134 StatisticsRecorder::Histograms histograms; | 187 StatisticsRecorder::Histograms histograms; |
135 StatisticsRecorder::GetHistograms(&histograms); | 188 StatisticsRecorder::GetHistograms(&histograms); |
136 ASSERT_EQ(2U, histograms.size()); | 189 ASSERT_EQ(2U, histograms.size()); |
137 | 190 |
138 std::string name1 = histograms[0]->histogram_name(); | 191 std::string name1 = histograms[0]->histogram_name(); |
139 std::string name2 = histograms[1]->histogram_name(); | 192 std::string name2 = histograms[1]->histogram_name(); |
140 EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) || | 193 EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) || |
141 ("Sparse2" == name1 && "Sparse1" == name2)); | 194 ("Sparse2" == name1 && "Sparse1" == name2)); |
142 } | 195 } |
143 | 196 |
144 TEST_F(SparseHistogramTest, Serialize) { | 197 TEST_P(SparseHistogramTest, Serialize) { |
145 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 198 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
146 histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); | 199 histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); |
147 | 200 |
148 Pickle pickle; | 201 Pickle pickle; |
149 histogram->SerializeInfo(&pickle); | 202 histogram->SerializeInfo(&pickle); |
150 | 203 |
151 PickleIterator iter(pickle); | 204 PickleIterator iter(pickle); |
152 | 205 |
153 int type; | 206 int type; |
154 EXPECT_TRUE(iter.ReadInt(&type)); | 207 EXPECT_TRUE(iter.ReadInt(&type)); |
155 EXPECT_EQ(SPARSE_HISTOGRAM, type); | 208 EXPECT_EQ(SPARSE_HISTOGRAM, type); |
156 | 209 |
157 std::string name; | 210 std::string name; |
158 EXPECT_TRUE(iter.ReadString(&name)); | 211 EXPECT_TRUE(iter.ReadString(&name)); |
159 EXPECT_EQ("Sparse", name); | 212 EXPECT_EQ("Sparse", name); |
160 | 213 |
161 int flag; | 214 int flag; |
162 EXPECT_TRUE(iter.ReadInt(&flag)); | 215 EXPECT_TRUE(iter.ReadInt(&flag)); |
163 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); | 216 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); |
164 | 217 |
165 // No more data in the pickle. | 218 // No more data in the pickle. |
166 EXPECT_FALSE(iter.SkipBytes(1)); | 219 EXPECT_FALSE(iter.SkipBytes(1)); |
167 } | 220 } |
168 | 221 |
| 222 TEST_P(SparseHistogramTest, FactoryTime) { |
| 223 const int kTestCreateCount = 1 << 10; // Must be power-of-2. |
| 224 const int kTestLookupCount = 100000; |
| 225 const int kTestAddCount = 100000; |
| 226 |
| 227 // Create all histogram names in advance for accurate timing below. |
| 228 std::vector<std::string> histogram_names; |
| 229 for (int i = 0; i < kTestCreateCount; ++i) { |
| 230 histogram_names.push_back( |
| 231 StringPrintf("TestHistogram.%d", i % kTestCreateCount)); |
| 232 } |
| 233 |
| 234 // Calculate cost of creating histograms. |
| 235 TimeTicks create_start = TimeTicks::Now(); |
| 236 for (int i = 0; i < kTestCreateCount; ++i) |
| 237 SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags); |
| 238 TimeDelta create_ticks = TimeTicks::Now() - create_start; |
| 239 int64_t create_ms = create_ticks.InMilliseconds(); |
| 240 |
| 241 VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms |
| 242 << "ms or about " |
| 243 << (create_ms * 1000000) / kTestCreateCount |
| 244 << "ns each."; |
| 245 |
| 246 // Calculate cost of looking up existing histograms. |
| 247 TimeTicks lookup_start = TimeTicks::Now(); |
| 248 for (int i = 0; i < kTestLookupCount; ++i) { |
| 249 // 6007 is co-prime with kTestCreateCount and so will do lookups in an |
| 250 // order less likely to be cacheable (but still hit them all) should the |
| 251 // underlying storage use the exact histogram name as the key. |
| 252 const int i_mult = 6007; |
| 253 static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); |
| 254 int index = (i * i_mult) & (kTestCreateCount - 1); |
| 255 SparseHistogram::FactoryGet(histogram_names[index], |
| 256 HistogramBase::kNoFlags); |
| 257 } |
| 258 TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; |
| 259 int64_t lookup_ms = lookup_ticks.InMilliseconds(); |
| 260 |
| 261 VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms |
| 262 << "ms or about " |
| 263 << (lookup_ms * 1000000) / kTestLookupCount |
| 264 << "ns each."; |
| 265 |
| 266 // Calculate cost of accessing histograms. |
| 267 HistogramBase* histogram = |
| 268 SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags); |
| 269 ASSERT_TRUE(histogram); |
| 270 TimeTicks add_start = TimeTicks::Now(); |
| 271 for (int i = 0; i < kTestAddCount; ++i) |
| 272 histogram->Add(i & 127); |
| 273 TimeDelta add_ticks = TimeTicks::Now() - add_start; |
| 274 int64_t add_ms = add_ticks.InMilliseconds(); |
| 275 |
| 276 VLOG(1) << kTestAddCount << " histogram adds took " << add_ms |
| 277 << "ms or about " |
| 278 << (add_ms * 1000000) / kTestAddCount |
| 279 << "ns each."; |
| 280 } |
| 281 |
169 } // namespace base | 282 } // namespace base |
OLD | NEW |