| 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_persistence.h" |
| 11 #include "base/metrics/histogram_samples.h" | 12 #include "base/metrics/histogram_samples.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 if (!allocator_memory_) |
| 61 allocator_memory_.reset(new char[kAllocatorMemorySize]); |
| 62 |
| 63 delete ReleasePersistentHistogramMemoryAllocatorForTesting(); |
| 64 memset(allocator_memory_.get(), 0, kAllocatorMemorySize); |
| 65 GetCreateHistogramResultHistogram(); |
| 66 SetPersistentHistogramMemoryAllocator( |
| 67 new PersistentMemoryAllocator( |
| 68 allocator_memory_.get(), kAllocatorMemorySize, 0, |
| 69 0, "SparseHistogramTestAllocator", false)); |
| 70 allocator_ = GetPersistentHistogramMemoryAllocator(); |
| 71 } |
| 72 |
| 73 void DestroyPersistentMemoryAllocator() { |
| 74 allocator_ = nullptr; |
| 75 delete ReleasePersistentHistogramMemoryAllocatorForTesting(); |
| 76 } |
| 77 |
| 39 scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) { | 78 scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) { |
| 40 return scoped_ptr<SparseHistogram>(new SparseHistogram(name)); | 79 return scoped_ptr<SparseHistogram>(new SparseHistogram(name)); |
| 41 } | 80 } |
| 42 | 81 |
| 82 const bool use_persistent_histogram_allocator_; |
| 83 |
| 43 StatisticsRecorder* statistics_recorder_; | 84 StatisticsRecorder* statistics_recorder_; |
| 85 scoped_ptr<char[]> allocator_memory_; |
| 86 PersistentMemoryAllocator* allocator_ = nullptr; |
| 87 |
| 88 private: |
| 89 DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest); |
| 44 }; | 90 }; |
| 45 | 91 |
| 46 TEST_F(SparseHistogramTest, BasicTest) { | 92 // Run all HistogramTest cases with both heap and persistent memory. |
| 93 INSTANTIATE_TEST_CASE_P(HeapAndPersistent, |
| 94 SparseHistogramTest, |
| 95 testing::Bool()); |
| 96 |
| 97 |
| 98 TEST_P(SparseHistogramTest, BasicTest) { |
| 47 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 99 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
| 48 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 100 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
| 49 EXPECT_EQ(0, snapshot->TotalCount()); | 101 EXPECT_EQ(0, snapshot->TotalCount()); |
| 50 EXPECT_EQ(0, snapshot->sum()); | 102 EXPECT_EQ(0, snapshot->sum()); |
| 51 | 103 |
| 52 histogram->Add(100); | 104 histogram->Add(100); |
| 53 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 105 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
| 54 EXPECT_EQ(1, snapshot1->TotalCount()); | 106 EXPECT_EQ(1, snapshot1->TotalCount()); |
| 55 EXPECT_EQ(1, snapshot1->GetCount(100)); | 107 EXPECT_EQ(1, snapshot1->GetCount(100)); |
| 56 | 108 |
| 57 histogram->Add(100); | 109 histogram->Add(100); |
| 58 histogram->Add(101); | 110 histogram->Add(101); |
| 59 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 111 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
| 60 EXPECT_EQ(3, snapshot2->TotalCount()); | 112 EXPECT_EQ(3, snapshot2->TotalCount()); |
| 61 EXPECT_EQ(2, snapshot2->GetCount(100)); | 113 EXPECT_EQ(2, snapshot2->GetCount(100)); |
| 62 EXPECT_EQ(1, snapshot2->GetCount(101)); | 114 EXPECT_EQ(1, snapshot2->GetCount(101)); |
| 63 } | 115 } |
| 64 | 116 |
| 65 TEST_F(SparseHistogramTest, BasicTestAddCount) { | 117 TEST_P(SparseHistogramTest, BasicTestAddCount) { |
| 66 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 118 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
| 67 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 119 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
| 68 EXPECT_EQ(0, snapshot->TotalCount()); | 120 EXPECT_EQ(0, snapshot->TotalCount()); |
| 69 EXPECT_EQ(0, snapshot->sum()); | 121 EXPECT_EQ(0, snapshot->sum()); |
| 70 | 122 |
| 71 histogram->AddCount(100, 15); | 123 histogram->AddCount(100, 15); |
| 72 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 124 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
| 73 EXPECT_EQ(15, snapshot1->TotalCount()); | 125 EXPECT_EQ(15, snapshot1->TotalCount()); |
| 74 EXPECT_EQ(15, snapshot1->GetCount(100)); | 126 EXPECT_EQ(15, snapshot1->GetCount(100)); |
| 75 | 127 |
| 76 histogram->AddCount(100, 15); | 128 histogram->AddCount(100, 15); |
| 77 histogram->AddCount(101, 25); | 129 histogram->AddCount(101, 25); |
| 78 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 130 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
| 79 EXPECT_EQ(55, snapshot2->TotalCount()); | 131 EXPECT_EQ(55, snapshot2->TotalCount()); |
| 80 EXPECT_EQ(30, snapshot2->GetCount(100)); | 132 EXPECT_EQ(30, snapshot2->GetCount(100)); |
| 81 EXPECT_EQ(25, snapshot2->GetCount(101)); | 133 EXPECT_EQ(25, snapshot2->GetCount(101)); |
| 82 } | 134 } |
| 83 | 135 |
| 84 TEST_F(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { | 136 TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { |
| 85 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 137 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
| 86 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); | 138 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
| 87 EXPECT_EQ(0, snapshot->TotalCount()); | 139 EXPECT_EQ(0, snapshot->TotalCount()); |
| 88 EXPECT_EQ(0, snapshot->sum()); | 140 EXPECT_EQ(0, snapshot->sum()); |
| 89 | 141 |
| 90 histogram->AddCount(1000000000, 15); | 142 histogram->AddCount(1000000000, 15); |
| 91 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); | 143 scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); |
| 92 EXPECT_EQ(15, snapshot1->TotalCount()); | 144 EXPECT_EQ(15, snapshot1->TotalCount()); |
| 93 EXPECT_EQ(15, snapshot1->GetCount(1000000000)); | 145 EXPECT_EQ(15, snapshot1->GetCount(1000000000)); |
| 94 | 146 |
| 95 histogram->AddCount(1000000000, 15); | 147 histogram->AddCount(1000000000, 15); |
| 96 histogram->AddCount(1010000000, 25); | 148 histogram->AddCount(1010000000, 25); |
| 97 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); | 149 scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); |
| 98 EXPECT_EQ(55, snapshot2->TotalCount()); | 150 EXPECT_EQ(55, snapshot2->TotalCount()); |
| 99 EXPECT_EQ(30, snapshot2->GetCount(1000000000)); | 151 EXPECT_EQ(30, snapshot2->GetCount(1000000000)); |
| 100 EXPECT_EQ(25, snapshot2->GetCount(1010000000)); | 152 EXPECT_EQ(25, snapshot2->GetCount(1010000000)); |
| 101 EXPECT_EQ(55250000000LL, snapshot2->sum()); | 153 EXPECT_EQ(55250000000LL, snapshot2->sum()); |
| 102 } | 154 } |
| 103 | 155 |
| 104 TEST_F(SparseHistogramTest, MacroBasicTest) { | 156 TEST_P(SparseHistogramTest, MacroBasicTest) { |
| 105 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); | 157 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); |
| 106 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200); | 158 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200); |
| 107 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); | 159 UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); |
| 108 | 160 |
| 109 StatisticsRecorder::Histograms histograms; | 161 StatisticsRecorder::Histograms histograms; |
| 110 StatisticsRecorder::GetHistograms(&histograms); | 162 StatisticsRecorder::GetHistograms(&histograms); |
| 111 | 163 |
| 112 ASSERT_EQ(1U, histograms.size()); | 164 ASSERT_EQ(1U, histograms.size()); |
| 113 HistogramBase* sparse_histogram = histograms[0]; | 165 HistogramBase* sparse_histogram = histograms[0]; |
| 114 | 166 |
| 115 EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); | 167 EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); |
| 116 EXPECT_EQ("Sparse", sparse_histogram->histogram_name()); | 168 EXPECT_EQ("Sparse", sparse_histogram->histogram_name()); |
| 117 EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, | 169 EXPECT_EQ( |
| 118 sparse_histogram->flags()); | 170 HistogramBase::kUmaTargetedHistogramFlag | |
| 171 (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent |
| 172 : 0), |
| 173 sparse_histogram->flags()); |
| 119 | 174 |
| 120 scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples(); | 175 scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples(); |
| 121 EXPECT_EQ(3, samples->TotalCount()); | 176 EXPECT_EQ(3, samples->TotalCount()); |
| 122 EXPECT_EQ(2, samples->GetCount(100)); | 177 EXPECT_EQ(2, samples->GetCount(100)); |
| 123 EXPECT_EQ(1, samples->GetCount(200)); | 178 EXPECT_EQ(1, samples->GetCount(200)); |
| 124 } | 179 } |
| 125 | 180 |
| 126 TEST_F(SparseHistogramTest, MacroInLoopTest) { | 181 TEST_P(SparseHistogramTest, MacroInLoopTest) { |
| 127 // Unlike the macros in histogram.h, SparseHistogram macros can have a | 182 // Unlike the macros in histogram.h, SparseHistogram macros can have a |
| 128 // variable as histogram name. | 183 // variable as histogram name. |
| 129 for (int i = 0; i < 2; i++) { | 184 for (int i = 0; i < 2; i++) { |
| 130 std::string name = StringPrintf("Sparse%d", i + 1); | 185 std::string name = StringPrintf("Sparse%d", i + 1); |
| 131 UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100); | 186 UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100); |
| 132 } | 187 } |
| 133 | 188 |
| 134 StatisticsRecorder::Histograms histograms; | 189 StatisticsRecorder::Histograms histograms; |
| 135 StatisticsRecorder::GetHistograms(&histograms); | 190 StatisticsRecorder::GetHistograms(&histograms); |
| 136 ASSERT_EQ(2U, histograms.size()); | 191 ASSERT_EQ(2U, histograms.size()); |
| 137 | 192 |
| 138 std::string name1 = histograms[0]->histogram_name(); | 193 std::string name1 = histograms[0]->histogram_name(); |
| 139 std::string name2 = histograms[1]->histogram_name(); | 194 std::string name2 = histograms[1]->histogram_name(); |
| 140 EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) || | 195 EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) || |
| 141 ("Sparse2" == name1 && "Sparse1" == name2)); | 196 ("Sparse2" == name1 && "Sparse1" == name2)); |
| 142 } | 197 } |
| 143 | 198 |
| 144 TEST_F(SparseHistogramTest, Serialize) { | 199 TEST_P(SparseHistogramTest, Serialize) { |
| 145 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); | 200 scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); |
| 146 histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); | 201 histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); |
| 147 | 202 |
| 148 Pickle pickle; | 203 Pickle pickle; |
| 149 histogram->SerializeInfo(&pickle); | 204 histogram->SerializeInfo(&pickle); |
| 150 | 205 |
| 151 PickleIterator iter(pickle); | 206 PickleIterator iter(pickle); |
| 152 | 207 |
| 153 int type; | 208 int type; |
| 154 EXPECT_TRUE(iter.ReadInt(&type)); | 209 EXPECT_TRUE(iter.ReadInt(&type)); |
| 155 EXPECT_EQ(SPARSE_HISTOGRAM, type); | 210 EXPECT_EQ(SPARSE_HISTOGRAM, type); |
| 156 | 211 |
| 157 std::string name; | 212 std::string name; |
| 158 EXPECT_TRUE(iter.ReadString(&name)); | 213 EXPECT_TRUE(iter.ReadString(&name)); |
| 159 EXPECT_EQ("Sparse", name); | 214 EXPECT_EQ("Sparse", name); |
| 160 | 215 |
| 161 int flag; | 216 int flag; |
| 162 EXPECT_TRUE(iter.ReadInt(&flag)); | 217 EXPECT_TRUE(iter.ReadInt(&flag)); |
| 163 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); | 218 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); |
| 164 | 219 |
| 165 // No more data in the pickle. | 220 // No more data in the pickle. |
| 166 EXPECT_FALSE(iter.SkipBytes(1)); | 221 EXPECT_FALSE(iter.SkipBytes(1)); |
| 167 } | 222 } |
| 168 | 223 |
| 224 TEST_P(SparseHistogramTest, FactoryTime) { |
| 225 const int kTestCreateCount = 1 << 10; // Must be power-of-2. |
| 226 const int kTestLookupCount = 100000; |
| 227 const int kTestAddCount = 100000; |
| 228 |
| 229 // Create all histogram names in advance for accurate timing below. |
| 230 std::vector<std::string> histogram_names; |
| 231 for (int i = 0; i < kTestCreateCount; ++i) { |
| 232 histogram_names.push_back( |
| 233 StringPrintf("TestHistogram.%d", i % kTestCreateCount)); |
| 234 } |
| 235 |
| 236 // Calculate cost of creating histograms. |
| 237 TimeTicks create_start = TimeTicks::Now(); |
| 238 for (int i = 0; i < kTestCreateCount; ++i) |
| 239 SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags); |
| 240 TimeDelta create_ticks = TimeTicks::Now() - create_start; |
| 241 int64_t create_ms = create_ticks.InMilliseconds(); |
| 242 |
| 243 VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms |
| 244 << "ms or about " |
| 245 << (create_ms * 1000000) / kTestCreateCount |
| 246 << "ns each."; |
| 247 |
| 248 // Calculate cost of looking up existing histograms. |
| 249 TimeTicks lookup_start = TimeTicks::Now(); |
| 250 for (int i = 0; i < kTestLookupCount; ++i) { |
| 251 // 6007 is co-prime with kTestCreateCount and so will do lookups in an |
| 252 // order less likely to be cacheable (but still hit them all) should the |
| 253 // underlying storage use the exact histogram name as the key. |
| 254 const int i_mult = 6007; |
| 255 static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); |
| 256 int index = (i * i_mult) & (kTestCreateCount - 1); |
| 257 SparseHistogram::FactoryGet(histogram_names[index], |
| 258 HistogramBase::kNoFlags); |
| 259 } |
| 260 TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; |
| 261 int64_t lookup_ms = lookup_ticks.InMilliseconds(); |
| 262 |
| 263 VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms |
| 264 << "ms or about " |
| 265 << (lookup_ms * 1000000) / kTestLookupCount |
| 266 << "ns each."; |
| 267 |
| 268 // Calculate cost of accessing histograms. |
| 269 HistogramBase* histogram = |
| 270 SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags); |
| 271 ASSERT_TRUE(histogram); |
| 272 TimeTicks add_start = TimeTicks::Now(); |
| 273 for (int i = 0; i < kTestAddCount; ++i) |
| 274 histogram->Add(i & 127); |
| 275 TimeDelta add_ticks = TimeTicks::Now() - add_start; |
| 276 int64_t add_ms = add_ticks.InMilliseconds(); |
| 277 |
| 278 VLOG(1) << kTestAddCount << " histogram adds took " << add_ms |
| 279 << "ms or about " |
| 280 << (add_ms * 1000000) / kTestAddCount |
| 281 << "ns each."; |
| 282 } |
| 283 |
| 169 } // namespace base | 284 } // namespace base |
| OLD | NEW |