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 // Test of Histogram class 6 7 #include <climits> 8 #include <algorithm> 9 #include <vector> 10 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/metrics/bucket_ranges.h" 14 #include "base/metrics/histogram.h" 15 #include "base/metrics/sample_vector.h" 16 #include "base/metrics/statistics_recorder.h" 17 #include "base/pickle.h" 18 #include "base/time/time.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using std::vector; 22 23 namespace base { 24 25 class HistogramTest : public testing::Test { 26 protected: 27 virtual void SetUp() { 28 // Each test will have a clean state (no Histogram / BucketRanges 29 // registered). 30 InitializeStatisticsRecorder(); 31 } 32 33 virtual void TearDown() { 34 UninitializeStatisticsRecorder(); 35 } 36 37 void InitializeStatisticsRecorder() { 38 statistics_recorder_ = new StatisticsRecorder(); 39 } 40 41 void UninitializeStatisticsRecorder() { 42 delete statistics_recorder_; 43 statistics_recorder_ = NULL; 44 } 45 46 StatisticsRecorder* statistics_recorder_; 47 }; 48 49 // Check for basic syntax and use. 50 TEST_F(HistogramTest, BasicTest) { 51 // Try basic construction 52 HistogramBase* histogram = Histogram::FactoryGet( 53 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); 54 EXPECT_TRUE(histogram); 55 56 HistogramBase* linear_histogram = LinearHistogram::FactoryGet( 57 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); 58 EXPECT_TRUE(linear_histogram); 59 60 vector<int> custom_ranges; 61 custom_ranges.push_back(1); 62 custom_ranges.push_back(5); 63 HistogramBase* custom_histogram = CustomHistogram::FactoryGet( 64 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); 65 EXPECT_TRUE(custom_histogram); 66 67 // Use standard macros (but with fixed samples) 68 HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1)); 69 HISTOGRAM_COUNTS("Test3Histogram", 30); 70 71 DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1)); 72 DHISTOGRAM_COUNTS("Test5Histogram", 30); 73 74 HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130); 75 } 76 77 // Check that the macro correctly matches histograms by name and records their 78 // data together. 79 TEST_F(HistogramTest, NameMatchTest) { 80 HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); 81 HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); 82 HistogramBase* histogram = LinearHistogram::FactoryGet( 83 "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags); 84 85 scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); 86 EXPECT_EQ(2, samples->TotalCount()); 87 EXPECT_EQ(2, samples->GetCount(10)); 88 } 89 90 TEST_F(HistogramTest, ExponentialRangesTest) { 91 // Check that we got a nice exponential when there was enough rooom. 92 BucketRanges ranges(9); 93 Histogram::InitializeBucketRanges(1, 64, &ranges); 94 EXPECT_EQ(0, ranges.range(0)); 95 int power_of_2 = 1; 96 for (int i = 1; i < 8; i++) { 97 EXPECT_EQ(power_of_2, ranges.range(i)); 98 power_of_2 *= 2; 99 } 100 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); 101 102 // Check the corresponding Histogram will use the correct ranges. 103 Histogram* histogram = static_cast<Histogram*>( 104 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 105 EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); 106 107 // When bucket count is limited, exponential ranges will partially look like 108 // linear. 109 BucketRanges ranges2(16); 110 Histogram::InitializeBucketRanges(1, 32, &ranges2); 111 112 EXPECT_EQ(0, ranges2.range(0)); 113 EXPECT_EQ(1, ranges2.range(1)); 114 EXPECT_EQ(2, ranges2.range(2)); 115 EXPECT_EQ(3, ranges2.range(3)); 116 EXPECT_EQ(4, ranges2.range(4)); 117 EXPECT_EQ(5, ranges2.range(5)); 118 EXPECT_EQ(6, ranges2.range(6)); 119 EXPECT_EQ(7, ranges2.range(7)); 120 EXPECT_EQ(9, ranges2.range(8)); 121 EXPECT_EQ(11, ranges2.range(9)); 122 EXPECT_EQ(14, ranges2.range(10)); 123 EXPECT_EQ(17, ranges2.range(11)); 124 EXPECT_EQ(21, ranges2.range(12)); 125 EXPECT_EQ(26, ranges2.range(13)); 126 EXPECT_EQ(32, ranges2.range(14)); 127 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15)); 128 129 // Check the corresponding Histogram will use the correct ranges. 130 Histogram* histogram2 = static_cast<Histogram*>( 131 Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags)); 132 EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); 133 } 134 135 TEST_F(HistogramTest, LinearRangesTest) { 136 BucketRanges ranges(9); 137 LinearHistogram::InitializeBucketRanges(1, 7, &ranges); 138 // Gets a nice linear set of bucket ranges. 139 for (int i = 0; i < 8; i++) 140 EXPECT_EQ(i, ranges.range(i)); 141 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); 142 143 // The correspoding LinearHistogram should use the correct ranges. 144 Histogram* histogram = static_cast<Histogram*>( 145 LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags)); 146 EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); 147 148 // Linear ranges are not divisible. 149 BucketRanges ranges2(6); 150 LinearHistogram::InitializeBucketRanges(1, 6, &ranges2); 151 EXPECT_EQ(0, ranges2.range(0)); 152 EXPECT_EQ(1, ranges2.range(1)); 153 EXPECT_EQ(3, ranges2.range(2)); 154 EXPECT_EQ(4, ranges2.range(3)); 155 EXPECT_EQ(6, ranges2.range(4)); 156 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5)); 157 // The correspoding LinearHistogram should use the correct ranges. 158 Histogram* histogram2 = static_cast<Histogram*>( 159 LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags)); 160 EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); 161 } 162 163 TEST_F(HistogramTest, ArrayToCustomRangesTest) { 164 const HistogramBase::Sample ranges[3] = {5, 10, 20}; 165 vector<HistogramBase::Sample> ranges_vec = 166 CustomHistogram::ArrayToCustomRanges(ranges, 3); 167 ASSERT_EQ(6u, ranges_vec.size()); 168 EXPECT_EQ(5, ranges_vec[0]); 169 EXPECT_EQ(6, ranges_vec[1]); 170 EXPECT_EQ(10, ranges_vec[2]); 171 EXPECT_EQ(11, ranges_vec[3]); 172 EXPECT_EQ(20, ranges_vec[4]); 173 EXPECT_EQ(21, ranges_vec[5]); 174 } 175 176 TEST_F(HistogramTest, CustomHistogramTest) { 177 // A well prepared custom ranges. 178 vector<HistogramBase::Sample> custom_ranges; 179 custom_ranges.push_back(1); 180 custom_ranges.push_back(2); 181 182 Histogram* histogram = static_cast<Histogram*>( 183 CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges, 184 HistogramBase::kNoFlags)); 185 const BucketRanges* ranges = histogram->bucket_ranges(); 186 ASSERT_EQ(4u, ranges->size()); 187 EXPECT_EQ(0, ranges->range(0)); // Auto added. 188 EXPECT_EQ(1, ranges->range(1)); 189 EXPECT_EQ(2, ranges->range(2)); 190 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); // Auto added. 191 192 // A unordered custom ranges. 193 custom_ranges.clear(); 194 custom_ranges.push_back(2); 195 custom_ranges.push_back(1); 196 histogram = static_cast<Histogram*>( 197 CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges, 198 HistogramBase::kNoFlags)); 199 ranges = histogram->bucket_ranges(); 200 ASSERT_EQ(4u, ranges->size()); 201 EXPECT_EQ(0, ranges->range(0)); 202 EXPECT_EQ(1, ranges->range(1)); 203 EXPECT_EQ(2, ranges->range(2)); 204 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); 205 206 // A custom ranges with duplicated values. 207 custom_ranges.clear(); 208 custom_ranges.push_back(4); 209 custom_ranges.push_back(1); 210 custom_ranges.push_back(4); 211 histogram = static_cast<Histogram*>( 212 CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges, 213 HistogramBase::kNoFlags)); 214 ranges = histogram->bucket_ranges(); 215 ASSERT_EQ(4u, ranges->size()); 216 EXPECT_EQ(0, ranges->range(0)); 217 EXPECT_EQ(1, ranges->range(1)); 218 EXPECT_EQ(4, ranges->range(2)); 219 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); 220 } 221 222 TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) { 223 // This test exploits the fact that the CustomHistogram can have 2 buckets, 224 // while the base class Histogram is *supposed* to have at least 3 buckets. 225 // We should probably change the restriction on the base class (or not inherit 226 // the base class!). 227 228 vector<HistogramBase::Sample> custom_ranges; 229 custom_ranges.push_back(4); 230 231 Histogram* histogram = static_cast<Histogram*>( 232 CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges, 233 HistogramBase::kNoFlags)); 234 const BucketRanges* ranges = histogram->bucket_ranges(); 235 ASSERT_EQ(3u, ranges->size()); 236 EXPECT_EQ(0, ranges->range(0)); 237 EXPECT_EQ(4, ranges->range(1)); 238 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); 239 } 240 241 // Make sure histogram handles out-of-bounds data gracefully. 242 TEST_F(HistogramTest, BoundsTest) { 243 const size_t kBucketCount = 50; 244 Histogram* histogram = static_cast<Histogram*>( 245 Histogram::FactoryGet("Bounded", 10, 100, kBucketCount, 246 HistogramBase::kNoFlags)); 247 248 // Put two samples "out of bounds" above and below. 249 histogram->Add(5); 250 histogram->Add(-50); 251 252 histogram->Add(100); 253 histogram->Add(10000); 254 255 // Verify they landed in the underflow, and overflow buckets. 256 scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector(); 257 EXPECT_EQ(2, samples->GetCountAtIndex(0)); 258 EXPECT_EQ(0, samples->GetCountAtIndex(1)); 259 size_t array_size = histogram->bucket_count(); 260 EXPECT_EQ(kBucketCount, array_size); 261 EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2)); 262 EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1)); 263 264 vector<int> custom_ranges; 265 custom_ranges.push_back(10); 266 custom_ranges.push_back(50); 267 custom_ranges.push_back(100); 268 Histogram* test_custom_histogram = static_cast<Histogram*>( 269 CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram", 270 custom_ranges, HistogramBase::kNoFlags)); 271 272 // Put two samples "out of bounds" above and below. 273 test_custom_histogram->Add(5); 274 test_custom_histogram->Add(-50); 275 test_custom_histogram->Add(100); 276 test_custom_histogram->Add(1000); 277 test_custom_histogram->Add(INT_MAX); 278 279 // Verify they landed in the underflow, and overflow buckets. 280 scoped_ptr<SampleVector> custom_samples = 281 test_custom_histogram->SnapshotSampleVector(); 282 EXPECT_EQ(2, custom_samples->GetCountAtIndex(0)); 283 EXPECT_EQ(0, custom_samples->GetCountAtIndex(1)); 284 size_t bucket_count = test_custom_histogram->bucket_count(); 285 EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2)); 286 EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1)); 287 } 288 289 // Check to be sure samples land as expected is "correct" buckets. 290 TEST_F(HistogramTest, BucketPlacementTest) { 291 Histogram* histogram = static_cast<Histogram*>( 292 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 293 294 // Add i+1 samples to the i'th bucket. 295 histogram->Add(0); 296 int power_of_2 = 1; 297 for (int i = 1; i < 8; i++) { 298 for (int j = 0; j <= i; j++) 299 histogram->Add(power_of_2); 300 power_of_2 *= 2; 301 } 302 303 // Check to see that the bucket counts reflect our additions. 304 scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector(); 305 for (int i = 0; i < 8; i++) 306 EXPECT_EQ(i + 1, samples->GetCountAtIndex(i)); 307 } 308 309 TEST_F(HistogramTest, CorruptSampleCounts) { 310 Histogram* histogram = static_cast<Histogram*>( 311 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 312 313 // Add some samples. 314 histogram->Add(20); 315 histogram->Add(40); 316 317 scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector(); 318 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 319 histogram->FindCorruption(*snapshot)); 320 EXPECT_EQ(2, snapshot->redundant_count()); 321 EXPECT_EQ(2, snapshot->TotalCount()); 322 323 snapshot->counts_[3] += 100; // Sample count won't match redundant count. 324 EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR, 325 histogram->FindCorruption(*snapshot)); 326 snapshot->counts_[2] -= 200; 327 EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR, 328 histogram->FindCorruption(*snapshot)); 329 330 // But we can't spot a corruption if it is compensated for. 331 snapshot->counts_[1] += 100; 332 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 333 histogram->FindCorruption(*snapshot)); 334 } 335 336 TEST_F(HistogramTest, CorruptBucketBounds) { 337 Histogram* histogram = static_cast<Histogram*>( 338 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); 339 340 scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector(); 341 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, 342 histogram->FindCorruption(*snapshot)); 343 344 BucketRanges* bucket_ranges = 345 const_cast<BucketRanges*>(histogram->bucket_ranges()); 346 HistogramBase::Sample tmp = bucket_ranges->range(1); 347 bucket_ranges->set_range(1, bucket_ranges->range(2)); 348 bucket_ranges->set_range(2, tmp); 349 EXPECT_EQ( 350 HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR, 351 histogram->FindCorruption(*snapshot)); 352 353 bucket_ranges->set_range(2, bucket_ranges->range(1)); 354 bucket_ranges->set_range(1, tmp); 355 EXPECT_EQ(0, histogram->FindCorruption(*snapshot)); 356 357 // Show that two simple changes don't offset each other 358 bucket_ranges->set_range(3, bucket_ranges->range(3) + 1); 359 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, 360 histogram->FindCorruption(*snapshot)); 361 362 bucket_ranges->set_range(4, bucket_ranges->range(4) - 1); 363 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, 364 histogram->FindCorruption(*snapshot)); 365 366 // Repair histogram so that destructor won't DCHECK(). 367 bucket_ranges->set_range(3, bucket_ranges->range(3) - 1); 368 bucket_ranges->set_range(4, bucket_ranges->range(4) + 1); 369 } 370 371 TEST_F(HistogramTest, HistogramSerializeInfo) { 372 Histogram* histogram = static_cast<Histogram*>( 373 Histogram::FactoryGet("Histogram", 1, 64, 8, 374 HistogramBase::kIPCSerializationSourceFlag)); 375 Pickle pickle; 376 histogram->SerializeInfo(&pickle); 377 378 PickleIterator iter(pickle); 379 380 int type; 381 EXPECT_TRUE(iter.ReadInt(&type)); 382 EXPECT_EQ(HISTOGRAM, type); 383 384 std::string name; 385 EXPECT_TRUE(iter.ReadString(&name)); 386 EXPECT_EQ("Histogram", name); 387 388 int flag; 389 EXPECT_TRUE(iter.ReadInt(&flag)); 390 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); 391 392 int min; 393 EXPECT_TRUE(iter.ReadInt(&min)); 394 EXPECT_EQ(1, min); 395 396 int max; 397 EXPECT_TRUE(iter.ReadInt(&max)); 398 EXPECT_EQ(64, max); 399 400 int64 bucket_count; 401 EXPECT_TRUE(iter.ReadInt64(&bucket_count)); 402 EXPECT_EQ(8, bucket_count); 403 404 uint32 checksum; 405 EXPECT_TRUE(iter.ReadUInt32(&checksum)); 406 EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum); 407 408 // No more data in the pickle. 409 EXPECT_FALSE(iter.SkipBytes(1)); 410 } 411 412 TEST_F(HistogramTest, CustomHistogramSerializeInfo) { 413 vector<int> custom_ranges; 414 custom_ranges.push_back(10); 415 custom_ranges.push_back(100); 416 417 HistogramBase* custom_histogram = CustomHistogram::FactoryGet( 418 "TestCustomRangeBoundedHistogram", 419 custom_ranges, 420 HistogramBase::kNoFlags); 421 Pickle pickle; 422 custom_histogram->SerializeInfo(&pickle); 423 424 // Validate the pickle. 425 PickleIterator iter(pickle); 426 427 int i; 428 std::string s; 429 int64 bucket_count; 430 uint32 ui32; 431 EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) && 432 iter.ReadInt(&i) && iter.ReadInt(&i) && 433 iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32)); 434 EXPECT_EQ(3, bucket_count); 435 436 int range; 437 EXPECT_TRUE(iter.ReadInt(&range)); 438 EXPECT_EQ(10, range); 439 EXPECT_TRUE(iter.ReadInt(&range)); 440 EXPECT_EQ(100, range); 441 442 // No more data in the pickle. 443 EXPECT_FALSE(iter.SkipBytes(1)); 444 } 445 446 #if GTEST_HAS_DEATH_TEST 447 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a 448 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX - 449 // 1). But we accept ranges exceeding those limits, and silently clamped to 450 // those limits. This is for backwards compatibility. 451 TEST(HistogramDeathTest, BadRangesTest) { 452 HistogramBase* histogram = Histogram::FactoryGet( 453 "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, 454 HistogramBase::kNoFlags); 455 EXPECT_TRUE( 456 histogram->HasConstructionArguments( 457 1, HistogramBase::kSampleType_MAX - 1, 8)); 458 459 HistogramBase* linear_histogram = LinearHistogram::FactoryGet( 460 "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8, 461 HistogramBase::kNoFlags); 462 EXPECT_TRUE( 463 linear_histogram->HasConstructionArguments( 464 1, HistogramBase::kSampleType_MAX - 1, 8)); 465 466 vector<int> custom_ranges; 467 custom_ranges.push_back(0); 468 custom_ranges.push_back(5); 469 Histogram* custom_histogram = static_cast<Histogram*>( 470 CustomHistogram::FactoryGet( 471 "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags)); 472 const BucketRanges* ranges = custom_histogram->bucket_ranges(); 473 ASSERT_EQ(3u, ranges->size()); 474 EXPECT_EQ(0, ranges->range(0)); 475 EXPECT_EQ(5, ranges->range(1)); 476 EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); 477 478 // CustomHistogram does not accepts kSampleType_MAX as range. 479 custom_ranges.push_back(HistogramBase::kSampleType_MAX); 480 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges, 481 HistogramBase::kNoFlags), 482 ""); 483 484 // CustomHistogram needs at least 1 valid range. 485 custom_ranges.clear(); 486 custom_ranges.push_back(0); 487 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges, 488 HistogramBase::kNoFlags), 489 ""); 490 } 491 #endif 492 493 } // namespace base 494