Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2011 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 "base/metrics/histogram.h"
      8 #include "base/scoped_ptr.h"
      9 #include "base/time.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 namespace base {
     13 namespace {
     14 
     15 class HistogramTest : public testing::Test {
     16 };
     17 
     18 // Check for basic syntax and use.
     19 TEST(HistogramTest, StartupShutdownTest) {
     20   // Try basic construction
     21   Histogram* histogram(Histogram::FactoryGet(
     22       "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
     23   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
     24   Histogram* histogram1(Histogram::FactoryGet(
     25       "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
     26   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
     27   EXPECT_NE(histogram, histogram1);
     28 
     29 
     30   Histogram* linear_histogram(LinearHistogram::FactoryGet(
     31       "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
     32   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
     33   Histogram* linear_histogram1(LinearHistogram::FactoryGet(
     34       "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
     35   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
     36   EXPECT_NE(linear_histogram, linear_histogram1);
     37 
     38   std::vector<int> custom_ranges;
     39   custom_ranges.push_back(1);
     40   custom_ranges.push_back(5);
     41   custom_ranges.push_back(10);
     42   custom_ranges.push_back(20);
     43   custom_ranges.push_back(30);
     44   Histogram* custom_histogram(CustomHistogram::FactoryGet(
     45       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
     46   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
     47   Histogram* custom_histogram1(CustomHistogram::FactoryGet(
     48       "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags));
     49   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
     50 
     51   // Use standard macros (but with fixed samples)
     52   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
     53   HISTOGRAM_COUNTS("Test3Histogram", 30);
     54 
     55   DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
     56   DHISTOGRAM_COUNTS("Test5Histogram", 30);
     57 
     58   HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
     59 
     60   // Try to construct samples.
     61   Histogram::SampleSet sample1;
     62   Histogram::SampleSet sample2;
     63 
     64   // Use copy constructor of SampleSet
     65   sample1 = sample2;
     66   Histogram::SampleSet sample3(sample1);
     67 
     68   // Finally test a statistics recorder, without really using it.
     69   StatisticsRecorder recorder;
     70 }
     71 
     72 // Repeat with a recorder present to register with.
     73 TEST(HistogramTest, RecordedStartupTest) {
     74   // Test a statistics recorder, by letting histograms register.
     75   StatisticsRecorder recorder;  // This initializes the global state.
     76 
     77   StatisticsRecorder::Histograms histograms;
     78   EXPECT_EQ(0U, histograms.size());
     79   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
     80   EXPECT_EQ(0U, histograms.size());
     81 
     82   // Try basic construction
     83   Histogram* histogram(Histogram::FactoryGet(
     84       "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
     85   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
     86   histograms.clear();
     87   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
     88   EXPECT_EQ(1U, histograms.size());
     89   Histogram* histogram1(Histogram::FactoryGet(
     90       "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
     91   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
     92   histograms.clear();
     93   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
     94   EXPECT_EQ(2U, histograms.size());
     95 
     96   Histogram* linear_histogram(LinearHistogram::FactoryGet(
     97       "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
     98   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
     99   histograms.clear();
    100   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    101   EXPECT_EQ(3U, histograms.size());
    102 
    103   Histogram* linear_histogram1(LinearHistogram::FactoryGet(
    104       "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
    105   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
    106   histograms.clear();
    107   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    108   EXPECT_EQ(4U, histograms.size());
    109 
    110   std::vector<int> custom_ranges;
    111   custom_ranges.push_back(1);
    112   custom_ranges.push_back(5);
    113   custom_ranges.push_back(10);
    114   custom_ranges.push_back(20);
    115   custom_ranges.push_back(30);
    116   Histogram* custom_histogram(CustomHistogram::FactoryGet(
    117       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
    118   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
    119   Histogram* custom_histogram1(CustomHistogram::FactoryGet(
    120       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
    121   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
    122 
    123   histograms.clear();
    124   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    125   EXPECT_EQ(5U, histograms.size());
    126 
    127   // Use standard macros (but with fixed samples)
    128   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
    129   HISTOGRAM_COUNTS("Test3Histogram", 30);
    130   histograms.clear();
    131   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    132   EXPECT_EQ(7U, histograms.size());
    133 
    134   HISTOGRAM_ENUMERATION("TestEnumerationHistogram", 20, 200);
    135   histograms.clear();
    136   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    137   EXPECT_EQ(8U, histograms.size());
    138 
    139   DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
    140   DHISTOGRAM_COUNTS("Test5Histogram", 30);
    141   histograms.clear();
    142   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
    143 #ifndef NDEBUG
    144   EXPECT_EQ(10U, histograms.size());
    145 #else
    146   EXPECT_EQ(8U, histograms.size());
    147 #endif
    148 }
    149 
    150 TEST(HistogramTest, RangeTest) {
    151   StatisticsRecorder recorder;
    152   StatisticsRecorder::Histograms histograms;
    153 
    154   recorder.GetHistograms(&histograms);
    155   EXPECT_EQ(0U, histograms.size());
    156 
    157   Histogram* histogram(Histogram::FactoryGet(
    158       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
    159   // Check that we got a nice exponential when there was enough rooom.
    160   EXPECT_EQ(0, histogram->ranges(0));
    161   int power_of_2 = 1;
    162   for (int i = 1; i < 8; i++) {
    163     EXPECT_EQ(power_of_2, histogram->ranges(i));
    164     power_of_2 *= 2;
    165   }
    166   EXPECT_EQ(INT_MAX, histogram->ranges(8));
    167 
    168   Histogram* short_histogram(Histogram::FactoryGet(
    169       "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags));
    170   // Check that when the number of buckets is short, we get a linear histogram
    171   // for lack of space to do otherwise.
    172   for (int i = 0; i < 8; i++)
    173     EXPECT_EQ(i, short_histogram->ranges(i));
    174   EXPECT_EQ(INT_MAX, short_histogram->ranges(8));
    175 
    176   Histogram* linear_histogram(LinearHistogram::FactoryGet(
    177       "Linear", 1, 7, 8, Histogram::kNoFlags));
    178   // We also get a nice linear set of bucket ranges when we ask for it
    179   for (int i = 0; i < 8; i++)
    180     EXPECT_EQ(i, linear_histogram->ranges(i));
    181   EXPECT_EQ(INT_MAX, linear_histogram->ranges(8));
    182 
    183   Histogram* linear_broad_histogram(LinearHistogram::FactoryGet(
    184       "Linear widened", 2, 14, 8, Histogram::kNoFlags));
    185   // ...but when the list has more space, then the ranges naturally spread out.
    186   for (int i = 0; i < 8; i++)
    187     EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i));
    188   EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8));
    189 
    190   Histogram* transitioning_histogram(Histogram::FactoryGet(
    191       "LinearAndExponential", 1, 32, 15, Histogram::kNoFlags));
    192   // When space is a little tight, we transition from linear to exponential.
    193   EXPECT_EQ(0, transitioning_histogram->ranges(0));
    194   EXPECT_EQ(1, transitioning_histogram->ranges(1));
    195   EXPECT_EQ(2, transitioning_histogram->ranges(2));
    196   EXPECT_EQ(3, transitioning_histogram->ranges(3));
    197   EXPECT_EQ(4, transitioning_histogram->ranges(4));
    198   EXPECT_EQ(5, transitioning_histogram->ranges(5));
    199   EXPECT_EQ(6, transitioning_histogram->ranges(6));
    200   EXPECT_EQ(7, transitioning_histogram->ranges(7));
    201   EXPECT_EQ(9, transitioning_histogram->ranges(8));
    202   EXPECT_EQ(11, transitioning_histogram->ranges(9));
    203   EXPECT_EQ(14, transitioning_histogram->ranges(10));
    204   EXPECT_EQ(17, transitioning_histogram->ranges(11));
    205   EXPECT_EQ(21, transitioning_histogram->ranges(12));
    206   EXPECT_EQ(26, transitioning_histogram->ranges(13));
    207   EXPECT_EQ(32, transitioning_histogram->ranges(14));
    208   EXPECT_EQ(INT_MAX, transitioning_histogram->ranges(15));
    209 
    210   std::vector<int> custom_ranges;
    211   custom_ranges.push_back(0);
    212   custom_ranges.push_back(9);
    213   custom_ranges.push_back(10);
    214   custom_ranges.push_back(11);
    215   custom_ranges.push_back(300);
    216   Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
    217       "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
    218 
    219   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(0));
    220   EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(1));
    221   EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(2));
    222   EXPECT_EQ(custom_ranges[3], test_custom_histogram->ranges(3));
    223   EXPECT_EQ(custom_ranges[4], test_custom_histogram->ranges(4));
    224 
    225   recorder.GetHistograms(&histograms);
    226   EXPECT_EQ(6U, histograms.size());
    227 }
    228 
    229 TEST(HistogramTest, CustomRangeTest) {
    230   StatisticsRecorder recorder;
    231   StatisticsRecorder::Histograms histograms;
    232 
    233   // Check that missing leading zero is handled by an auto-insertion.
    234   std::vector<int> custom_ranges;
    235   // Don't include a zero.
    236   custom_ranges.push_back(9);
    237   custom_ranges.push_back(10);
    238   custom_ranges.push_back(11);
    239   Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
    240       "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
    241 
    242   EXPECT_EQ(0, test_custom_histogram->ranges(0));  // Auto added
    243   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(1));
    244   EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(2));
    245   EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(3));
    246 
    247   // Check that unsorted data with dups is handled gracefully.
    248   const int kSmall = 7;
    249   const int kMid = 8;
    250   const int kBig = 9;
    251   custom_ranges.clear();
    252   custom_ranges.push_back(kBig);
    253   custom_ranges.push_back(kMid);
    254   custom_ranges.push_back(kSmall);
    255   custom_ranges.push_back(kSmall);
    256   custom_ranges.push_back(kMid);
    257   custom_ranges.push_back(0);  // Push an explicit zero.
    258   custom_ranges.push_back(kBig);
    259 
    260   Histogram* unsorted_histogram(CustomHistogram::FactoryGet(
    261       "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags));
    262   EXPECT_EQ(0, unsorted_histogram->ranges(0));
    263   EXPECT_EQ(kSmall, unsorted_histogram->ranges(1));
    264   EXPECT_EQ(kMid, unsorted_histogram->ranges(2));
    265   EXPECT_EQ(kBig, unsorted_histogram->ranges(3));
    266 }
    267 
    268 
    269 // Make sure histogram handles out-of-bounds data gracefully.
    270 TEST(HistogramTest, BoundsTest) {
    271   const size_t kBucketCount = 50;
    272   Histogram* histogram(Histogram::FactoryGet(
    273       "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
    274 
    275   // Put two samples "out of bounds" above and below.
    276   histogram->Add(5);
    277   histogram->Add(-50);
    278 
    279   histogram->Add(100);
    280   histogram->Add(10000);
    281 
    282   // Verify they landed in the underflow, and overflow buckets.
    283   Histogram::SampleSet sample;
    284   histogram->SnapshotSample(&sample);
    285   EXPECT_EQ(2, sample.counts(0));
    286   EXPECT_EQ(0, sample.counts(1));
    287   size_t array_size = histogram->bucket_count();
    288   EXPECT_EQ(kBucketCount, array_size);
    289   EXPECT_EQ(0, sample.counts(array_size - 2));
    290   EXPECT_EQ(2, sample.counts(array_size - 1));
    291 }
    292 
    293 // Check to be sure samples land as expected is "correct" buckets.
    294 TEST(HistogramTest, BucketPlacementTest) {
    295   Histogram* histogram(Histogram::FactoryGet(
    296       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
    297 
    298   // Check that we got a nice exponential since there was enough rooom.
    299   EXPECT_EQ(0, histogram->ranges(0));
    300   int power_of_2 = 1;
    301   for (int i = 1; i < 8; i++) {
    302     EXPECT_EQ(power_of_2, histogram->ranges(i));
    303     power_of_2 *= 2;
    304   }
    305   EXPECT_EQ(INT_MAX, histogram->ranges(8));
    306 
    307   // Add i+1 samples to the i'th bucket.
    308   histogram->Add(0);
    309   power_of_2 = 1;
    310   for (int i = 1; i < 8; i++) {
    311     for (int j = 0; j <= i; j++)
    312       histogram->Add(power_of_2);
    313     power_of_2 *= 2;
    314   }
    315   // Leave overflow bucket empty.
    316 
    317   // Check to see that the bucket counts reflect our additions.
    318   Histogram::SampleSet sample;
    319   histogram->SnapshotSample(&sample);
    320   EXPECT_EQ(INT_MAX, histogram->ranges(8));
    321   for (int i = 0; i < 8; i++)
    322     EXPECT_EQ(i + 1, sample.counts(i));
    323 }
    324 
    325 }  // namespace
    326 
    327 //------------------------------------------------------------------------------
    328 // We can't be an an anonymous namespace while being friends, so we pop back
    329 // out to the base namespace here.  We need to be friends to corrupt the
    330 // internals of the histogram and/or sampleset.
    331 TEST(HistogramTest, CorruptSampleCounts) {
    332   Histogram* histogram(Histogram::FactoryGet(
    333       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
    334 
    335   EXPECT_EQ(0, histogram->sample_.redundant_count());
    336   histogram->Add(20);  // Add some samples.
    337   histogram->Add(40);
    338   EXPECT_EQ(2, histogram->sample_.redundant_count());
    339 
    340   Histogram::SampleSet snapshot;
    341   histogram->SnapshotSample(&snapshot);
    342   EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
    343   EXPECT_EQ(0, histogram->FindCorruption(snapshot));  // No default corruption.
    344   EXPECT_EQ(2, snapshot.redundant_count());
    345 
    346   snapshot.counts_[3] += 100;  // Sample count won't match redundant count.
    347   EXPECT_EQ(Histogram::COUNT_LOW_ERROR, histogram->FindCorruption(snapshot));
    348   snapshot.counts_[2] -= 200;
    349   EXPECT_EQ(Histogram::COUNT_HIGH_ERROR, histogram->FindCorruption(snapshot));
    350 
    351   // But we can't spot a corruption if it is compensated for.
    352   snapshot.counts_[1] += 100;
    353   EXPECT_EQ(0, histogram->FindCorruption(snapshot));
    354 }
    355 
    356 TEST(HistogramTest, CorruptBucketBounds) {
    357   Histogram* histogram(Histogram::FactoryGet(
    358       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
    359 
    360   Histogram::SampleSet snapshot;
    361   histogram->SnapshotSample(&snapshot);
    362   EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
    363   EXPECT_EQ(0, histogram->FindCorruption(snapshot));  // No default corruption.
    364 
    365   std::swap(histogram->ranges_[1], histogram->ranges_[2]);
    366   EXPECT_EQ(Histogram::BUCKET_ORDER_ERROR | Histogram::RANGE_CHECKSUM_ERROR,
    367             histogram->FindCorruption(snapshot));
    368 
    369   std::swap(histogram->ranges_[1], histogram->ranges_[2]);
    370   EXPECT_EQ(0, histogram->FindCorruption(snapshot));
    371 
    372   ++histogram->ranges_[3];
    373   EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
    374             histogram->FindCorruption(snapshot));
    375 
    376   // Show that two simple changes don't offset each other
    377   --histogram->ranges_[4];
    378   EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
    379             histogram->FindCorruption(snapshot));
    380 
    381   // Repair histogram so that destructor won't DCHECK().
    382   --histogram->ranges_[3];
    383   ++histogram->ranges_[4];
    384 }
    385 
    386 // Table was generated similarly to sample code for CRC-32 given on:
    387 // http://www.w3.org/TR/PNG/#D-CRCAppendix.
    388 TEST(HistogramTest, Crc32TableTest) {
    389   for (int i = 0; i < 256; ++i) {
    390     uint32 checksum = i;
    391     for (int j = 0; j < 8; ++j) {
    392       const uint32 kReversedPolynomial = 0xedb88320L;
    393       if (checksum & 1)
    394         checksum = kReversedPolynomial ^ (checksum >> 1);
    395       else
    396         checksum >>= 1;
    397     }
    398     EXPECT_EQ(Histogram::kCrcTable[i], checksum);
    399   }
    400 }
    401 
    402 }  // namespace base
    403