Home | History | Annotate | Download | only in metrics
      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