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