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/histogram.h" 6 7 #include <limits.h> 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <climits> 12 #include <memory> 13 #include <string> 14 #include <vector> 15 16 #include "base/logging.h" 17 #include "base/metrics/bucket_ranges.h" 18 #include "base/metrics/histogram_macros.h" 19 #include "base/metrics/persistent_histogram_allocator.h" 20 #include "base/metrics/persistent_memory_allocator.h" 21 #include "base/metrics/sample_vector.h" 22 #include "base/metrics/statistics_recorder.h" 23 #include "base/pickle.h" 24 #include "base/strings/stringprintf.h" 25 #include "base/test/gtest_util.h" 26 #include "base/time/time.h" 27 #include "testing/gtest/include/gtest/gtest.h" 28 29 namespace base { 30 31 // Test parameter indicates if a persistent memory allocator should be used 32 // for histogram allocation. False will allocate histograms from the process 33 // heap. 34 class HistogramTest : public testing::TestWithParam<bool> { 35 protected: 36 const int32_t kAllocatorMemorySize = 8 << 20; // 8 MiB 37 38 HistogramTest() : use_persistent_histogram_allocator_(GetParam()) {} 39 40 void SetUp() override { 41 if (use_persistent_histogram_allocator_) 42 CreatePersistentHistogramAllocator(); 43 44 // Each test will have a clean state (no Histogram / BucketRanges 45 // registered). 46 InitializeStatisticsRecorder(); 47 } 48 49 void TearDown() override { 50 if (allocator_) { 51 ASSERT_FALSE(allocator_->IsFull()); 52 ASSERT_FALSE(allocator_->IsCorrupt()); 53 } 54 UninitializeStatisticsRecorder(); 55 DestroyPersistentHistogramAllocator(); 56 } 57 58 void InitializeStatisticsRecorder() { 59 DCHECK(!statistics_recorder_); 60 statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); 61 } 62 63 void UninitializeStatisticsRecorder() { 64 statistics_recorder_.reset(); 65 } 66 67 void CreatePersistentHistogramAllocator() { 68 // By getting the results-histogram before any persistent allocator 69 // is attached, that histogram is guaranteed not to be stored in 70 // any persistent memory segment (which simplifies some tests). 71 GlobalHistogramAllocator::GetCreateHistogramResultHistogram(); 72 73 GlobalHistogramAllocator::CreateWithLocalMemory( 74 kAllocatorMemorySize, 0, "HistogramAllocatorTest"); 75 allocator_ = GlobalHistogramAllocator::Get()->memory_allocator(); 76 } 77 78 void DestroyPersistentHistogramAllocator() { 79 allocator_ = nullptr; 80 GlobalHistogramAllocator::ReleaseForTesting(); 81 } 82 83 const bool use_persistent_histogram_allocator_; 84 85 std::unique_ptr<StatisticsRecorder> statistics_recorder_; 86 std::unique_ptr<char[]> allocator_memory_; 87 PersistentMemoryAllocator* allocator_ = nullptr; 88 89 private: 90 DISALLOW_COPY_AND_ASSIGN(HistogramTest); 91 }; 92 93 // Run all HistogramTest cases with both heap and persistent memory. 94 INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest, testing::Bool()); 95 96 97 // Check for basic syntax and use. 98 TEST_P(HistogramTest, BasicTest) { 99 // Try basic construction 100 HistogramBase* histogram = Histogram::FactoryGet( 101 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); 102 EXPECT_TRUE(histogram); 103 104 HistogramBase* linear_histogram = LinearHistogram::FactoryGet( 105 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); 106 EXPECT_TRUE(linear_histogram); 107 108 std::vector<int> custom_ranges; 109 custom_ranges.push_back(1); 110 custom_ranges.push_back(5); 111 HistogramBase* custom_histogram = CustomHistogram::FactoryGet( 112 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); 113 EXPECT_TRUE(custom_histogram); 114 115 // Macros that create hitograms have an internal static variable which will 116 // continue to point to those from the very first run of this method even 117 // during subsequent runs. 118 static bool already_run = false; 119 if (already_run) 120 return; 121 already_run = true; 122 123 // Use standard macros (but with fixed samples) 124 LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1)); 125 LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30); 126 127 LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130); 128 } 129 130 // Check that the macro correctly matches histograms by name and records their 131 // data together. 132 TEST_P(HistogramTest, NameMatchTest) { 133 // Macros that create hitograms have an internal static variable which will 134 // continue to point to those from the very first run of this method even 135 // during subsequent runs. 136 static bool already_run = false; 137 if (already_run) 138 return; 139 already_run = true; 140 141 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); 142 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); 143 HistogramBase* histogram = LinearHistogram::FactoryGet( 144 "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags); 145 146 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 147 EXPECT_EQ(2, samples->TotalCount()); 148 EXPECT_EQ(2, samples->GetCount(10)); 149 } 150 151 // Check that delta calculations work correctly. 152 TEST_P(HistogramTest, DeltaTest) { 153 HistogramBase* histogram = 154 Histogram::FactoryGet("DeltaHistogram", 1, 64, 8, 155 HistogramBase::kNoFlags); 156 histogram->Add(1); 157 histogram->Add(10); 158 histogram->Add(50); 159 160 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); 161 EXPECT_EQ(3, samples->TotalCount()); 162 EXPECT_EQ(1, samples->GetCount(1)); 163 EXPECT_EQ(1, samples->GetCount(10)); 164 EXPECT_EQ(1, samples->GetCount(50)); 165 EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); 166 167 samples = histogram->SnapshotDelta(); 168 EXPECT_EQ(0, samples->TotalCount()); 169 170 histogram->Add(10); 171 histogram->Add(10); 172 samples = histogram->SnapshotDelta(); 173 EXPECT_EQ(2, samples->TotalCount()); 174 EXPECT_EQ(2, samples->GetCount(10)); 175 176 samples = histogram->SnapshotDelta(); 177 EXPECT_EQ(0, samples->TotalCount()); 178 } 179 180 // Check that final-delta calculations work correctly. 181 TEST_P(HistogramTest, FinalDeltaTest) { 182 HistogramBase* histogram = 183 Histogram::FactoryGet("FinalDeltaHistogram", 1, 64, 8, 184 HistogramBase::kNoFlags); 185 histogram->Add(1); 186 histogram->Add(10); 187 histogram->Add(50); 188 189 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta(); 190 EXPECT_EQ(3, samples->TotalCount()); 191 EXPECT_EQ(1, samples->GetCount(1)); 192 EXPECT_EQ(1, samples->GetCount(10)); 193 EXPECT_EQ(1, samples->GetCount(50)); 194 EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); 195 196 histogram->Add(2); 197 histogram->Add(50); 198 199 samples = histogram->SnapshotFinalDelta(); 200 EXPECT_EQ(2, samples->TotalCount()); 201 EXPECT_EQ(1, samples->GetCount(2)); 202 EXPECT_EQ(1, samples->GetCount(50)); 203 EXPECT_EQ(samples->TotalCount(), samples->redundant_count()); 204 } 205 206 TEST_P(HistogramTest, ExponentialRangesTest) { 207 // Check that we got a nice exponential when there was enough room. 208 BucketRanges ranges(9); 209 Histogram::InitializeBucketRanges(1, 64, &ranges); 210 EXPECT_EQ(0, ranges.range(0)); 211 int power_of_2 = 1; 212 for (int i = 1; i < 8; i++) { 213 EXPECT_EQ(power_of_2, ranges.range(i)); 214 power_of_2 *= 2; 215 } 216 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); 217 218 // Check the corresponding Histogram will use the correct ranges. 219 Histogram* histogram = static_cast<Histogram*>( 220 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 221 EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); 222 223 // When bucket count is limited, exponential ranges will partially look like 224 // linear. 225 BucketRanges ranges2(16); 226 Histogram::InitializeBucketRanges(1, 32, &ranges2); 227 228 EXPECT_EQ(0, ranges2.range(0)); 229 EXPECT_EQ(1, ranges2.range(1)); 230 EXPECT_EQ(2, ranges2.range(2)); 231 EXPECT_EQ(3, ranges2.range(3)); 232 EXPECT_EQ(4, ranges2.range(4)); 233 EXPECT_EQ(5, ranges2.range(5)); 234 EXPECT_EQ(6, ranges2.range(6)); 235 EXPECT_EQ(7, ranges2.range(7)); 236 EXPECT_EQ(9, ranges2.range(8)); 237 EXPECT_EQ(11, ranges2.range(9)); 238 EXPECT_EQ(14, ranges2.range(10)); 239 EXPECT_EQ(17, ranges2.range(11)); 240 EXPECT_EQ(21, ranges2.range(12)); 241 EXPECT_EQ(26, ranges2.range(13)); 242 EXPECT_EQ(32, ranges2.range(14)); 243 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15)); 244 245 // Check the corresponding Histogram will use the correct ranges. 246 Histogram* histogram2 = static_cast<Histogram*>( 247 Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags)); 248 EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); 249 } 250 251 TEST_P(HistogramTest, LinearRangesTest) { 252 BucketRanges ranges(9); 253 LinearHistogram::InitializeBucketRanges(1, 7, &ranges); 254 // Gets a nice linear set of bucket ranges. 255 for (int i = 0; i < 8; i++) 256 EXPECT_EQ(i, ranges.range(i)); 257 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); 258 259 // The correspoding LinearHistogram should use the correct ranges. 260 Histogram* histogram = static_cast<Histogram*>( 261 LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags)); 262 EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); 263 264 // Linear ranges are not divisible. 265 BucketRanges ranges2(6); 266 LinearHistogram::InitializeBucketRanges(1, 6, &ranges2); 267 EXPECT_EQ(0, ranges2.range(0)); 268 EXPECT_EQ(1, ranges2.range(1)); 269 EXPECT_EQ(3, ranges2.range(2)); 270 EXPECT_EQ(4, ranges2.range(3)); 271 EXPECT_EQ(6, ranges2.range(4)); 272 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5)); 273 // The correspoding LinearHistogram should use the correct ranges. 274 Histogram* histogram2 = static_cast<Histogram*>( 275 LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags)); 276 EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); 277 } 278 279 TEST_P(HistogramTest, ArrayToCustomRangesTest) { 280 const HistogramBase::Sample ranges[3] = {5, 10, 20}; 281 std::vector<HistogramBase::Sample> ranges_vec = 282 CustomHistogram::ArrayToCustomRanges(ranges, 3); 283 ASSERT_EQ(6u, ranges_vec.size()); 284 EXPECT_EQ(5, ranges_vec[0]); 285 EXPECT_EQ(6, ranges_vec[1]); 286 EXPECT_EQ(10, ranges_vec[2]); 287 EXPECT_EQ(11, ranges_vec[3]); 288 EXPECT_EQ(20, ranges_vec[4]); 289 EXPECT_EQ(21, ranges_vec[5]); 290 } 291 292 TEST_P(HistogramTest, CustomHistogramTest) { 293 // A well prepared custom ranges. 294 std::vector<HistogramBase::Sample> custom_ranges; 295 custom_ranges.push_back(1); 296 custom_ranges.push_back(2); 297 298 Histogram* histogram = static_cast<Histogram*>( 299 CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges, 300 HistogramBase::kNoFlags)); 301 const BucketRanges* ranges = histogram->bucket_ranges(); 302 ASSERT_EQ(4u, ranges->size()); 303 EXPECT_EQ(0, ranges->range(0)); // Auto added. 304 EXPECT_EQ(1, ranges->range(1)); 305 EXPECT_EQ(2, ranges->range(2)); 306 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); // Auto added. 307 308 // A unordered custom ranges. 309 custom_ranges.clear(); 310 custom_ranges.push_back(2); 311 custom_ranges.push_back(1); 312 histogram = static_cast<Histogram*>( 313 CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges, 314 HistogramBase::kNoFlags)); 315 ranges = histogram->bucket_ranges(); 316 ASSERT_EQ(4u, ranges->size()); 317 EXPECT_EQ(0, ranges->range(0)); 318 EXPECT_EQ(1, ranges->range(1)); 319 EXPECT_EQ(2, ranges->range(2)); 320 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); 321 322 // A custom ranges with duplicated values. 323 custom_ranges.clear(); 324 custom_ranges.push_back(4); 325 custom_ranges.push_back(1); 326 custom_ranges.push_back(4); 327 histogram = static_cast<Histogram*>( 328 CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges, 329 HistogramBase::kNoFlags)); 330 ranges = histogram->bucket_ranges(); 331 ASSERT_EQ(4u, ranges->size()); 332 EXPECT_EQ(0, ranges->range(0)); 333 EXPECT_EQ(1, ranges->range(1)); 334 EXPECT_EQ(4, ranges->range(2)); 335 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); 336 } 337 338 TEST_P(HistogramTest, CustomHistogramWithOnly2Buckets) { 339 // This test exploits the fact that the CustomHistogram can have 2 buckets, 340 // while the base class Histogram is *supposed* to have at least 3 buckets. 341 // We should probably change the restriction on the base class (or not inherit 342 // the base class!). 343 344 std::vector<HistogramBase::Sample> custom_ranges; 345 custom_ranges.push_back(4); 346 347 Histogram* histogram = static_cast<Histogram*>( 348 CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges, 349 HistogramBase::kNoFlags)); 350 const BucketRanges* ranges = histogram->bucket_ranges(); 351 ASSERT_EQ(3u, ranges->size()); 352 EXPECT_EQ(0, ranges->range(0)); 353 EXPECT_EQ(4, ranges->range(1)); 354 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); 355 } 356 357 TEST_P(HistogramTest, AddCountTest) { 358 const size_t kBucketCount = 50; 359 Histogram* histogram = static_cast<Histogram*>( 360 Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount, 361 HistogramBase::kNoFlags)); 362 363 histogram->AddCount(20, 15); 364 histogram->AddCount(30, 14); 365 366 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 367 EXPECT_EQ(29, samples->TotalCount()); 368 EXPECT_EQ(15, samples->GetCount(20)); 369 EXPECT_EQ(14, samples->GetCount(30)); 370 371 histogram->AddCount(20, 25); 372 histogram->AddCount(30, 24); 373 374 std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples(); 375 EXPECT_EQ(78, samples2->TotalCount()); 376 EXPECT_EQ(40, samples2->GetCount(20)); 377 EXPECT_EQ(38, samples2->GetCount(30)); 378 } 379 380 TEST_P(HistogramTest, AddCount_LargeValuesDontOverflow) { 381 const size_t kBucketCount = 50; 382 Histogram* histogram = static_cast<Histogram*>( 383 Histogram::FactoryGet("AddCountHistogram", 10, 1000000000, kBucketCount, 384 HistogramBase::kNoFlags)); 385 386 histogram->AddCount(200000000, 15); 387 histogram->AddCount(300000000, 14); 388 389 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 390 EXPECT_EQ(29, samples->TotalCount()); 391 EXPECT_EQ(15, samples->GetCount(200000000)); 392 EXPECT_EQ(14, samples->GetCount(300000000)); 393 394 histogram->AddCount(200000000, 25); 395 histogram->AddCount(300000000, 24); 396 397 std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples(); 398 EXPECT_EQ(78, samples2->TotalCount()); 399 EXPECT_EQ(40, samples2->GetCount(200000000)); 400 EXPECT_EQ(38, samples2->GetCount(300000000)); 401 EXPECT_EQ(19400000000LL, samples2->sum()); 402 } 403 404 // Make sure histogram handles out-of-bounds data gracefully. 405 TEST_P(HistogramTest, BoundsTest) { 406 const size_t kBucketCount = 50; 407 Histogram* histogram = static_cast<Histogram*>( 408 Histogram::FactoryGet("Bounded", 10, 100, kBucketCount, 409 HistogramBase::kNoFlags)); 410 411 // Put two samples "out of bounds" above and below. 412 histogram->Add(5); 413 histogram->Add(-50); 414 415 histogram->Add(100); 416 histogram->Add(10000); 417 418 // Verify they landed in the underflow, and overflow buckets. 419 std::unique_ptr<SampleVector> samples = histogram->SnapshotSampleVector(); 420 EXPECT_EQ(2, samples->GetCountAtIndex(0)); 421 EXPECT_EQ(0, samples->GetCountAtIndex(1)); 422 size_t array_size = histogram->bucket_count(); 423 EXPECT_EQ(kBucketCount, array_size); 424 EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2)); 425 EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1)); 426 427 std::vector<int> custom_ranges; 428 custom_ranges.push_back(10); 429 custom_ranges.push_back(50); 430 custom_ranges.push_back(100); 431 Histogram* test_custom_histogram = static_cast<Histogram*>( 432 CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram", 433 custom_ranges, HistogramBase::kNoFlags)); 434 435 // Put two samples "out of bounds" above and below. 436 test_custom_histogram->Add(5); 437 test_custom_histogram->Add(-50); 438 test_custom_histogram->Add(100); 439 test_custom_histogram->Add(1000); 440 test_custom_histogram->Add(INT_MAX); 441 442 // Verify they landed in the underflow, and overflow buckets. 443 std::unique_ptr<SampleVector> custom_samples = 444 test_custom_histogram->SnapshotSampleVector(); 445 EXPECT_EQ(2, custom_samples->GetCountAtIndex(0)); 446 EXPECT_EQ(0, custom_samples->GetCountAtIndex(1)); 447 size_t bucket_count = test_custom_histogram->bucket_count(); 448 EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2)); 449 EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1)); 450 } 451 452 // Check to be sure samples land as expected is "correct" buckets. 453 TEST_P(HistogramTest, BucketPlacementTest) { 454 Histogram* histogram = static_cast<Histogram*>( 455 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 456 457 // Add i+1 samples to the i'th bucket. 458 histogram->Add(0); 459 int power_of_2 = 1; 460 for (int i = 1; i < 8; i++) { 461 for (int j = 0; j <= i; j++) 462 histogram->Add(power_of_2); 463 power_of_2 *= 2; 464 } 465 466 // Check to see that the bucket counts reflect our additions. 467 std::unique_ptr<SampleVector> samples = histogram->SnapshotSampleVector(); 468 for (int i = 0; i < 8; i++) 469 EXPECT_EQ(i + 1, samples->GetCountAtIndex(i)); 470 } 471 472 TEST_P(HistogramTest, CorruptSampleCounts) { 473 // The internal code creates histograms via macros and thus keeps static 474 // pointers to them. If those pointers are to persistent memory which will 475 // be free'd then any following calls to that code will crash with a 476 // segmentation violation. 477 if (use_persistent_histogram_allocator_) 478 return; 479 480 Histogram* histogram = static_cast<Histogram*>( 481 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 482 483 // Add some samples. 484 histogram->Add(20); 485 histogram->Add(40); 486 487 std::unique_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector(); 488 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 489 histogram->FindCorruption(*snapshot)); 490 EXPECT_EQ(2, snapshot->redundant_count()); 491 EXPECT_EQ(2, snapshot->TotalCount()); 492 493 snapshot->counts_[3] += 100; // Sample count won't match redundant count. 494 EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR, 495 histogram->FindCorruption(*snapshot)); 496 snapshot->counts_[2] -= 200; 497 EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR, 498 histogram->FindCorruption(*snapshot)); 499 500 // But we can't spot a corruption if it is compensated for. 501 snapshot->counts_[1] += 100; 502 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 503 histogram->FindCorruption(*snapshot)); 504 } 505 506 TEST_P(HistogramTest, CorruptBucketBounds) { 507 Histogram* histogram = static_cast<Histogram*>( 508 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 509 510 std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples(); 511 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 512 histogram->FindCorruption(*snapshot)); 513 514 BucketRanges* bucket_ranges = 515 const_cast<BucketRanges*>(histogram->bucket_ranges()); 516 HistogramBase::Sample tmp = bucket_ranges->range(1); 517 bucket_ranges->set_range(1, bucket_ranges->range(2)); 518 bucket_ranges->set_range(2, tmp); 519 EXPECT_EQ( 520 HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR, 521 histogram->FindCorruption(*snapshot)); 522 523 bucket_ranges->set_range(2, bucket_ranges->range(1)); 524 bucket_ranges->set_range(1, tmp); 525 EXPECT_EQ(0U, histogram->FindCorruption(*snapshot)); 526 527 // Show that two simple changes don't offset each other 528 bucket_ranges->set_range(3, bucket_ranges->range(3) + 1); 529 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, 530 histogram->FindCorruption(*snapshot)); 531 532 bucket_ranges->set_range(4, bucket_ranges->range(4) - 1); 533 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, 534 histogram->FindCorruption(*snapshot)); 535 536 // Repair histogram so that destructor won't DCHECK(). 537 bucket_ranges->set_range(3, bucket_ranges->range(3) - 1); 538 bucket_ranges->set_range(4, bucket_ranges->range(4) + 1); 539 } 540 541 TEST_P(HistogramTest, HistogramSerializeInfo) { 542 Histogram* histogram = static_cast<Histogram*>( 543 Histogram::FactoryGet("Histogram", 1, 64, 8, 544 HistogramBase::kIPCSerializationSourceFlag)); 545 Pickle pickle; 546 histogram->SerializeInfo(&pickle); 547 548 PickleIterator iter(pickle); 549 550 int type; 551 EXPECT_TRUE(iter.ReadInt(&type)); 552 EXPECT_EQ(HISTOGRAM, type); 553 554 std::string name; 555 EXPECT_TRUE(iter.ReadString(&name)); 556 EXPECT_EQ("Histogram", name); 557 558 int flag; 559 EXPECT_TRUE(iter.ReadInt(&flag)); 560 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, 561 flag & ~HistogramBase::kIsPersistent); 562 563 int min; 564 EXPECT_TRUE(iter.ReadInt(&min)); 565 EXPECT_EQ(1, min); 566 567 int max; 568 EXPECT_TRUE(iter.ReadInt(&max)); 569 EXPECT_EQ(64, max); 570 571 uint32_t bucket_count; 572 EXPECT_TRUE(iter.ReadUInt32(&bucket_count)); 573 EXPECT_EQ(8u, bucket_count); 574 575 uint32_t checksum; 576 EXPECT_TRUE(iter.ReadUInt32(&checksum)); 577 EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum); 578 579 // No more data in the pickle. 580 EXPECT_FALSE(iter.SkipBytes(1)); 581 } 582 583 TEST_P(HistogramTest, CustomHistogramSerializeInfo) { 584 std::vector<int> custom_ranges; 585 custom_ranges.push_back(10); 586 custom_ranges.push_back(100); 587 588 HistogramBase* custom_histogram = CustomHistogram::FactoryGet( 589 "TestCustomRangeBoundedHistogram", 590 custom_ranges, 591 HistogramBase::kNoFlags); 592 Pickle pickle; 593 custom_histogram->SerializeInfo(&pickle); 594 595 // Validate the pickle. 596 PickleIterator iter(pickle); 597 598 int i; 599 std::string s; 600 uint32_t bucket_count; 601 uint32_t ui32; 602 EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) && 603 iter.ReadInt(&i) && iter.ReadInt(&i) && 604 iter.ReadUInt32(&bucket_count) && iter.ReadUInt32(&ui32)); 605 EXPECT_EQ(3u, bucket_count); 606 607 int range; 608 EXPECT_TRUE(iter.ReadInt(&range)); 609 EXPECT_EQ(10, range); 610 EXPECT_TRUE(iter.ReadInt(&range)); 611 EXPECT_EQ(100, range); 612 613 // No more data in the pickle. 614 EXPECT_FALSE(iter.SkipBytes(1)); 615 } 616 617 TEST_P(HistogramTest, BadConstruction) { 618 HistogramBase* histogram = Histogram::FactoryGet( 619 "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags); 620 EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8)); 621 622 // Try to get the same histogram name with different arguments. 623 HistogramBase* bad_histogram = Histogram::FactoryGet( 624 "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags); 625 EXPECT_EQ(NULL, bad_histogram); 626 bad_histogram = Histogram::FactoryGet( 627 "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags); 628 EXPECT_EQ(NULL, bad_histogram); 629 630 HistogramBase* linear_histogram = LinearHistogram::FactoryGet( 631 "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags); 632 EXPECT_TRUE(linear_histogram->HasConstructionArguments(1, 100, 8)); 633 634 // Try to get the same histogram name with different arguments. 635 bad_histogram = LinearHistogram::FactoryGet( 636 "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags); 637 EXPECT_EQ(NULL, bad_histogram); 638 bad_histogram = LinearHistogram::FactoryGet( 639 "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags); 640 EXPECT_EQ(NULL, bad_histogram); 641 } 642 643 TEST_P(HistogramTest, FactoryTime) { 644 const int kTestCreateCount = 1 << 14; // Must be power-of-2. 645 const int kTestLookupCount = 100000; 646 const int kTestAddCount = 1000000; 647 648 // Create all histogram names in advance for accurate timing below. 649 std::vector<std::string> histogram_names; 650 for (int i = 0; i < kTestCreateCount; ++i) { 651 histogram_names.push_back( 652 StringPrintf("TestHistogram.%d", i % kTestCreateCount)); 653 } 654 655 // Calculate cost of creating histograms. 656 TimeTicks create_start = TimeTicks::Now(); 657 for (int i = 0; i < kTestCreateCount; ++i) { 658 Histogram::FactoryGet(histogram_names[i], 1, 100, 10, 659 HistogramBase::kNoFlags); 660 } 661 TimeDelta create_ticks = TimeTicks::Now() - create_start; 662 int64_t create_ms = create_ticks.InMilliseconds(); 663 664 VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms 665 << "ms or about " 666 << (create_ms * 1000000) / kTestCreateCount 667 << "ns each."; 668 669 // Calculate cost of looking up existing histograms. 670 TimeTicks lookup_start = TimeTicks::Now(); 671 for (int i = 0; i < kTestLookupCount; ++i) { 672 // 6007 is co-prime with kTestCreateCount and so will do lookups in an 673 // order less likely to be cacheable (but still hit them all) should the 674 // underlying storage use the exact histogram name as the key. 675 const int i_mult = 6007; 676 static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big"); 677 int index = (i * i_mult) & (kTestCreateCount - 1); 678 Histogram::FactoryGet(histogram_names[index], 1, 100, 10, 679 HistogramBase::kNoFlags); 680 } 681 TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start; 682 int64_t lookup_ms = lookup_ticks.InMilliseconds(); 683 684 VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms 685 << "ms or about " 686 << (lookup_ms * 1000000) / kTestLookupCount 687 << "ns each."; 688 689 // Calculate cost of accessing histograms. 690 HistogramBase* histogram = Histogram::FactoryGet( 691 histogram_names[0], 1, 100, 10, HistogramBase::kNoFlags); 692 ASSERT_TRUE(histogram); 693 TimeTicks add_start = TimeTicks::Now(); 694 for (int i = 0; i < kTestAddCount; ++i) 695 histogram->Add(i & 127); 696 TimeDelta add_ticks = TimeTicks::Now() - add_start; 697 int64_t add_ms = add_ticks.InMilliseconds(); 698 699 VLOG(1) << kTestAddCount << " histogram adds took " << add_ms 700 << "ms or about " 701 << (add_ms * 1000000) / kTestAddCount 702 << "ns each."; 703 } 704 705 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a 706 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX - 707 // 1). But we accept ranges exceeding those limits, and silently clamped to 708 // those limits. This is for backwards compatibility. 709 TEST(HistogramDeathTest, BadRangesTest) { 710 HistogramBase* histogram = Histogram::FactoryGet( 711 "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, 712 HistogramBase::kNoFlags); 713 EXPECT_TRUE( 714 histogram->HasConstructionArguments( 715 1, HistogramBase::kSampleType_MAX - 1, 8)); 716 717 HistogramBase* linear_histogram = LinearHistogram::FactoryGet( 718 "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8, 719 HistogramBase::kNoFlags); 720 EXPECT_TRUE( 721 linear_histogram->HasConstructionArguments( 722 1, HistogramBase::kSampleType_MAX - 1, 8)); 723 724 std::vector<int> custom_ranges; 725 custom_ranges.push_back(0); 726 custom_ranges.push_back(5); 727 Histogram* custom_histogram = static_cast<Histogram*>( 728 CustomHistogram::FactoryGet( 729 "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags)); 730 const BucketRanges* ranges = custom_histogram->bucket_ranges(); 731 ASSERT_EQ(3u, ranges->size()); 732 EXPECT_EQ(0, ranges->range(0)); 733 EXPECT_EQ(5, ranges->range(1)); 734 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); 735 736 // CustomHistogram does not accepts kSampleType_MAX as range. 737 custom_ranges.push_back(HistogramBase::kSampleType_MAX); 738 EXPECT_DEATH_IF_SUPPORTED( 739 CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges, 740 HistogramBase::kNoFlags), 741 ""); 742 743 // CustomHistogram needs at least 1 valid range. 744 custom_ranges.clear(); 745 custom_ranges.push_back(0); 746 EXPECT_DEATH_IF_SUPPORTED( 747 CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges, 748 HistogramBase::kNoFlags), 749 ""); 750 } 751 752 } // namespace base 753