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 3 // found in the LICENSE file. 4 5 #include "base/metrics/sparse_histogram.h" 6 7 #include <memory> 8 #include <string> 9 10 #include "base/metrics/histogram_base.h" 11 #include "base/metrics/histogram_functions.h" 12 #include "base/metrics/histogram_samples.h" 13 #include "base/metrics/metrics_hashes.h" 14 #include "base/metrics/persistent_histogram_allocator.h" 15 #include "base/metrics/persistent_memory_allocator.h" 16 #include "base/metrics/sample_map.h" 17 #include "base/metrics/statistics_recorder.h" 18 #include "base/pickle.h" 19 #include "base/strings/stringprintf.h" 20 #include "testing/gmock/include/gmock/gmock.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 namespace base { 24 25 // Test parameter indicates if a persistent memory allocator should be used 26 // for histogram allocation. False will allocate histograms from the process 27 // heap. 28 class SparseHistogramTest : public testing::TestWithParam<bool> { 29 protected: 30 const int32_t kAllocatorMemorySize = 8 << 20; // 8 MiB 31 32 SparseHistogramTest() : use_persistent_histogram_allocator_(GetParam()) {} 33 34 void SetUp() override { 35 if (use_persistent_histogram_allocator_) 36 CreatePersistentMemoryAllocator(); 37 38 // Each test will have a clean state (no Histogram / BucketRanges 39 // registered). 40 InitializeStatisticsRecorder(); 41 } 42 43 void TearDown() override { 44 if (allocator_) { 45 ASSERT_FALSE(allocator_->IsFull()); 46 ASSERT_FALSE(allocator_->IsCorrupt()); 47 } 48 UninitializeStatisticsRecorder(); 49 DestroyPersistentMemoryAllocator(); 50 } 51 52 void InitializeStatisticsRecorder() { 53 DCHECK(!statistics_recorder_); 54 statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); 55 } 56 57 void UninitializeStatisticsRecorder() { 58 statistics_recorder_.reset(); 59 } 60 61 void CreatePersistentMemoryAllocator() { 62 GlobalHistogramAllocator::CreateWithLocalMemory( 63 kAllocatorMemorySize, 0, "SparseHistogramAllocatorTest"); 64 allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); 65 } 66 67 void DestroyPersistentMemoryAllocator() { 68 allocator_ = nullptr; 69 GlobalHistogramAllocator::ReleaseForTesting(); 70 } 71 72 std::unique_ptr<SparseHistogram> NewSparseHistogram(const char* name) { 73 // std::make_unique can't access protected ctor so do it manually. This 74 // test class is a friend so can access it. 75 return std::unique_ptr<SparseHistogram>(new SparseHistogram(name)); 76 } 77 78 const bool use_persistent_histogram_allocator_; 79 80 std::unique_ptr<StatisticsRecorder> statistics_recorder_; 81 PersistentMemoryAllocator* allocator_ = nullptr; 82 83 private: 84 DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest); 85 }; 86 87 // Run all HistogramTest cases with both heap and persistent memory. 88 INSTANTIATE_TEST_CASE_P(HeapAndPersistent, 89 SparseHistogramTest, 90 testing::Bool()); 91 92 93 TEST_P(SparseHistogramTest, BasicTest) { 94 std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); 95 std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); 96 EXPECT_EQ(0, snapshot->TotalCount()); 97 EXPECT_EQ(0, snapshot->sum()); 98 99 histogram->Add(100); 100 std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); 101 EXPECT_EQ(1, snapshot1->TotalCount()); 102 EXPECT_EQ(1, snapshot1->GetCount(100)); 103 104 histogram->Add(100); 105 histogram->Add(101); 106 std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); 107 EXPECT_EQ(3, snapshot2->TotalCount()); 108 EXPECT_EQ(2, snapshot2->GetCount(100)); 109 EXPECT_EQ(1, snapshot2->GetCount(101)); 110 } 111 112 TEST_P(SparseHistogramTest, BasicTestAddCount) { 113 std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); 114 std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); 115 EXPECT_EQ(0, snapshot->TotalCount()); 116 EXPECT_EQ(0, snapshot->sum()); 117 118 histogram->AddCount(100, 15); 119 std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); 120 EXPECT_EQ(15, snapshot1->TotalCount()); 121 EXPECT_EQ(15, snapshot1->GetCount(100)); 122 123 histogram->AddCount(100, 15); 124 histogram->AddCount(101, 25); 125 std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); 126 EXPECT_EQ(55, snapshot2->TotalCount()); 127 EXPECT_EQ(30, snapshot2->GetCount(100)); 128 EXPECT_EQ(25, snapshot2->GetCount(101)); 129 } 130 131 TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) { 132 std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); 133 std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); 134 EXPECT_EQ(0, snapshot->TotalCount()); 135 EXPECT_EQ(0, snapshot->sum()); 136 137 histogram->AddCount(1000000000, 15); 138 std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples()); 139 EXPECT_EQ(15, snapshot1->TotalCount()); 140 EXPECT_EQ(15, snapshot1->GetCount(1000000000)); 141 142 histogram->AddCount(1000000000, 15); 143 histogram->AddCount(1010000000, 25); 144 std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples()); 145 EXPECT_EQ(55, snapshot2->TotalCount()); 146 EXPECT_EQ(30, snapshot2->GetCount(1000000000)); 147 EXPECT_EQ(25, snapshot2->GetCount(1010000000)); 148 EXPECT_EQ(55250000000LL, snapshot2->sum()); 149 } 150 151 // Make sure that counts returned by Histogram::SnapshotDelta do not overflow 152 // even when a total count (returned by Histogram::SnapshotSample) does. 153 TEST_P(SparseHistogramTest, AddCount_LargeCountsDontOverflow) { 154 std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); 155 std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); 156 EXPECT_EQ(0, snapshot->TotalCount()); 157 EXPECT_EQ(0, snapshot->sum()); 158 159 const int count = (1 << 30) - 1; 160 161 // Repeat N times to make sure that there is no internal value overflow. 162 for (int i = 0; i < 10; ++i) { 163 histogram->AddCount(42, count); 164 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); 165 EXPECT_EQ(count, samples->TotalCount()); 166 EXPECT_EQ(count, samples->GetCount(42)); 167 } 168 } 169 170 TEST_P(SparseHistogramTest, MacroBasicTest) { 171 UmaHistogramSparse("Sparse", 100); 172 UmaHistogramSparse("Sparse", 200); 173 UmaHistogramSparse("Sparse", 100); 174 175 const StatisticsRecorder::Histograms histograms = 176 StatisticsRecorder::GetHistograms(); 177 178 ASSERT_THAT(histograms, testing::SizeIs(1)); 179 const HistogramBase* const sparse_histogram = histograms[0]; 180 181 EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); 182 EXPECT_EQ("Sparse", StringPiece(sparse_histogram->histogram_name())); 183 EXPECT_EQ( 184 HistogramBase::kUmaTargetedHistogramFlag | 185 (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent 186 : 0), 187 sparse_histogram->flags()); 188 189 std::unique_ptr<HistogramSamples> samples = 190 sparse_histogram->SnapshotSamples(); 191 EXPECT_EQ(3, samples->TotalCount()); 192 EXPECT_EQ(2, samples->GetCount(100)); 193 EXPECT_EQ(1, samples->GetCount(200)); 194 } 195 196 TEST_P(SparseHistogramTest, MacroInLoopTest) { 197 // Unlike the macros in histogram.h, SparseHistogram macros can have a 198 // variable as histogram name. 199 for (int i = 0; i < 2; i++) { 200 UmaHistogramSparse(StringPrintf("Sparse%d", i), 100); 201 } 202 203 const StatisticsRecorder::Histograms histograms = 204 StatisticsRecorder::Sort(StatisticsRecorder::GetHistograms()); 205 ASSERT_THAT(histograms, testing::SizeIs(2)); 206 EXPECT_STREQ(histograms[0]->histogram_name(), "Sparse0"); 207 EXPECT_STREQ(histograms[1]->histogram_name(), "Sparse1"); 208 } 209 210 TEST_P(SparseHistogramTest, Serialize) { 211 std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse")); 212 histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); 213 214 Pickle pickle; 215 histogram->SerializeInfo(&pickle); 216 217 PickleIterator iter(pickle); 218 219 int type; 220 EXPECT_TRUE(iter.ReadInt(&type)); 221 EXPECT_EQ(SPARSE_HISTOGRAM, type); 222 223 std::string name; 224 EXPECT_TRUE(iter.ReadString(&name)); 225 EXPECT_EQ("Sparse", name); 226 227 int flag; 228 EXPECT_TRUE(iter.ReadInt(&flag)); 229 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); 230 231 // No more data in the pickle. 232 EXPECT_FALSE(iter.SkipBytes(1)); 233 } 234 235 // Ensure that race conditions that cause multiple, identical sparse histograms 236 // to be created will safely resolve to a single one. 237 TEST_P(SparseHistogramTest, DuplicationSafety) { 238 const char histogram_name[] = "Duplicated"; 239 size_t histogram_count = StatisticsRecorder::GetHistogramCount(); 240 241 // Create a histogram that we will later duplicate. 242 HistogramBase* original = 243 SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags); 244 ++histogram_count; 245 DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); 246 original->Add(1); 247 248 // Create a duplicate. This has to happen differently depending on where the 249 // memory is taken from. 250 if (use_persistent_histogram_allocator_) { 251 // To allocate from persistent memory, clear the last_created reference in 252 // the GlobalHistogramAllocator. This will cause an Import to recreate 253 // the just-created histogram which will then be released as a duplicate. 254 GlobalHistogramAllocator::Get()->ClearLastCreatedReferenceForTesting(); 255 // Creating a different histogram will first do an Import to ensure it 256 // hasn't been created elsewhere, triggering the duplication and release. 257 SparseHistogram::FactoryGet("something.new", HistogramBase::kNoFlags); 258 ++histogram_count; 259 } else { 260 // To allocate from the heap, just call the (private) constructor directly. 261 // Delete it immediately like would have happened within FactoryGet(); 262 std::unique_ptr<SparseHistogram> something = 263 NewSparseHistogram(histogram_name); 264 DCHECK_NE(original, something.get()); 265 } 266 DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); 267 268 // Re-creating the histogram via FactoryGet() will return the same one. 269 HistogramBase* duplicate = 270 SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags); 271 DCHECK_EQ(original, duplicate); 272 DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount()); 273 duplicate->Add(2); 274 275 // Ensure that original histograms are still cross-functional. 276 original->Add(2); 277 duplicate->Add(1); 278 std::unique_ptr<HistogramSamples> snapshot_orig = original->SnapshotSamples(); 279 std::unique_ptr<HistogramSamples> snapshot_dup = duplicate->SnapshotSamples(); 280 DCHECK_EQ(2, snapshot_orig->GetCount(2)); 281 DCHECK_EQ(2, snapshot_dup->GetCount(1)); 282 } 283 284 TEST_P(SparseHistogramTest, FactoryTime) { 285 const int kTestCreateCount = 1 << 10; // Must be power-of-2. 286 const int kTestLookupCount = 100000; 287 const int kTestAddCount = 100000; 288 289 // Create all histogram names in advance for accurate timing below. 290 std::vector<std::string> histogram_names; 291 for (int i = 0; i < kTestCreateCount; ++i) { 292 histogram_names.push_back( 293 StringPrintf("TestHistogram.%d", i % kTestCreateCount)); 294 } 295 296 // Calculate cost of creating histograms. 297 TimeTicks create_start = TimeTicks::Now(); 298 for (int i = 0; i < kTestCreateCount; ++i) 299 SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags); 300 TimeDelta create_ticks = TimeTicks::Now() - create_start; 301 int64_t create_ms = create_ticks.InMilliseconds(); 302 303 VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms 304 << "ms or about " 305 << (create_ms * 1000000) / kTestCreateCount 306 << "ns each."; 307 308 // Calculate cost of looking up existing histograms. 309 TimeTicks lookup_start = TimeTicks::Now(); 310 for (int i = 0; i < kTestLookupCount; ++i) { 311 // 6007 is co-prime with kTestCreateCount and so will do lookups in an 312 // order less likely to be cacheable (but still hit them all) should the 313 // underlying storage use the exact histogram name as the key. 314 const int i_mult = 6007; 315 static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); 316 int index = (i * i_mult) & (kTestCreateCount - 1); 317 SparseHistogram::FactoryGet(histogram_names[index], 318 HistogramBase::kNoFlags); 319 } 320 TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; 321 int64_t lookup_ms = lookup_ticks.InMilliseconds(); 322 323 VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms 324 << "ms or about " 325 << (lookup_ms * 1000000) / kTestLookupCount 326 << "ns each."; 327 328 // Calculate cost of accessing histograms. 329 HistogramBase* histogram = 330 SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags); 331 ASSERT_TRUE(histogram); 332 TimeTicks add_start = TimeTicks::Now(); 333 for (int i = 0; i < kTestAddCount; ++i) 334 histogram->Add(i & 127); 335 TimeDelta add_ticks = TimeTicks::Now() - add_start; 336 int64_t add_ms = add_ticks.InMilliseconds(); 337 338 VLOG(1) << kTestAddCount << " histogram adds took " << add_ms 339 << "ms or about " 340 << (add_ms * 1000000) / kTestAddCount 341 << "ns each."; 342 } 343 344 TEST_P(SparseHistogramTest, ExtremeValues) { 345 static const struct { 346 Histogram::Sample sample; 347 int64_t expected_max; 348 } cases[] = { 349 // Note: We use -2147483647 - 1 rather than -2147483648 because the later 350 // is interpreted as - operator applied to 2147483648 and the latter can't 351 // be represented as an int32 and causes a warning. 352 {-2147483647 - 1, -2147483647LL}, 353 {0, 1}, 354 {2147483647, 2147483648LL}, 355 }; 356 357 for (size_t i = 0; i < arraysize(cases); ++i) { 358 HistogramBase* histogram = 359 SparseHistogram::FactoryGet(StringPrintf("ExtremeValues_%zu", i), 360 HistogramBase::kUmaTargetedHistogramFlag); 361 histogram->Add(cases[i].sample); 362 363 std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples(); 364 std::unique_ptr<SampleCountIterator> it = snapshot->Iterator(); 365 ASSERT_FALSE(it->Done()); 366 367 base::Histogram::Sample min; 368 int64_t max; 369 base::Histogram::Count count; 370 it->Get(&min, &max, &count); 371 372 EXPECT_EQ(1, count); 373 EXPECT_EQ(cases[i].sample, min); 374 EXPECT_EQ(cases[i].expected_max, max); 375 376 it->Next(); 377 EXPECT_TRUE(it->Done()); 378 } 379 } 380 381 TEST_P(SparseHistogramTest, HistogramNameHash) { 382 const char kName[] = "TestName"; 383 HistogramBase* histogram = SparseHistogram::FactoryGet( 384 kName, HistogramBase::kUmaTargetedHistogramFlag); 385 EXPECT_EQ(histogram->name_hash(), HashMetricName(kName)); 386 } 387 388 } // namespace base 389