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/sparse_histogram.h"
      6 
      7 #include <memory>
      8 #include <string>
      9 
     10 #include "base/metrics/histogram_base.h"
     11 #include "base/metrics/histogram_functions.h"
     12 #include "base/metrics/histogram_samples.h"
     13 #include "base/metrics/metrics_hashes.h"
     14 #include "base/metrics/persistent_histogram_allocator.h"
     15 #include "base/metrics/persistent_memory_allocator.h"
     16 #include "base/metrics/sample_map.h"
     17 #include "base/metrics/statistics_recorder.h"
     18 #include "base/pickle.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "testing/gmock/include/gmock/gmock.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace base {
     24 
     25 // Test parameter indicates if a persistent memory allocator should be used
     26 // for histogram allocation. False will allocate histograms from the process
     27 // heap.
     28 class SparseHistogramTest : public testing::TestWithParam<bool> {
     29  protected:
     30   const int32_t kAllocatorMemorySize = 8 << 20;  // 8 MiB
     31 
     32   SparseHistogramTest() : use_persistent_histogram_allocator_(GetParam()) {}
     33 
     34   void SetUp() override {
     35     if (use_persistent_histogram_allocator_)
     36       CreatePersistentMemoryAllocator();
     37 
     38     // Each test will have a clean state (no Histogram / BucketRanges
     39     // registered).
     40     InitializeStatisticsRecorder();
     41   }
     42 
     43   void TearDown() override {
     44     if (allocator_) {
     45       ASSERT_FALSE(allocator_->IsFull());
     46       ASSERT_FALSE(allocator_->IsCorrupt());
     47     }
     48     UninitializeStatisticsRecorder();
     49     DestroyPersistentMemoryAllocator();
     50   }
     51 
     52   void InitializeStatisticsRecorder() {
     53     DCHECK(!statistics_recorder_);
     54     statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
     55   }
     56 
     57   void UninitializeStatisticsRecorder() {
     58     statistics_recorder_.reset();
     59   }
     60 
     61   void CreatePersistentMemoryAllocator() {
     62     GlobalHistogramAllocator::CreateWithLocalMemory(
     63         kAllocatorMemorySize, 0, "SparseHistogramAllocatorTest");
     64     allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
     65   }
     66 
     67   void DestroyPersistentMemoryAllocator() {
     68     allocator_ = nullptr;
     69     GlobalHistogramAllocator::ReleaseForTesting();
     70   }
     71 
     72   std::unique_ptr<SparseHistogram> NewSparseHistogram(const char* name) {
     73     // std::make_unique can't access protected ctor so do it manually. This
     74     // test class is a friend so can access it.
     75     return std::unique_ptr<SparseHistogram>(new SparseHistogram(name));
     76   }
     77 
     78   const bool use_persistent_histogram_allocator_;
     79 
     80   std::unique_ptr<StatisticsRecorder> statistics_recorder_;
     81   PersistentMemoryAllocator* allocator_ = nullptr;
     82 
     83  private:
     84   DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest);
     85 };
     86 
     87 // Run all HistogramTest cases with both heap and persistent memory.
     88 INSTANTIATE_TEST_CASE_P(HeapAndPersistent,
     89                         SparseHistogramTest,
     90                         testing::Bool());
     91 
     92 
     93 TEST_P(SparseHistogramTest, BasicTest) {
     94   std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
     95   std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
     96   EXPECT_EQ(0, snapshot->TotalCount());
     97   EXPECT_EQ(0, snapshot->sum());
     98 
     99   histogram->Add(100);
    100   std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
    101   EXPECT_EQ(1, snapshot1->TotalCount());
    102   EXPECT_EQ(1, snapshot1->GetCount(100));
    103 
    104   histogram->Add(100);
    105   histogram->Add(101);
    106   std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
    107   EXPECT_EQ(3, snapshot2->TotalCount());
    108   EXPECT_EQ(2, snapshot2->GetCount(100));
    109   EXPECT_EQ(1, snapshot2->GetCount(101));
    110 }
    111 
    112 TEST_P(SparseHistogramTest, BasicTestAddCount) {
    113   std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
    114   std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
    115   EXPECT_EQ(0, snapshot->TotalCount());
    116   EXPECT_EQ(0, snapshot->sum());
    117 
    118   histogram->AddCount(100, 15);
    119   std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
    120   EXPECT_EQ(15, snapshot1->TotalCount());
    121   EXPECT_EQ(15, snapshot1->GetCount(100));
    122 
    123   histogram->AddCount(100, 15);
    124   histogram->AddCount(101, 25);
    125   std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
    126   EXPECT_EQ(55, snapshot2->TotalCount());
    127   EXPECT_EQ(30, snapshot2->GetCount(100));
    128   EXPECT_EQ(25, snapshot2->GetCount(101));
    129 }
    130 
    131 TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) {
    132   std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
    133   std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
    134   EXPECT_EQ(0, snapshot->TotalCount());
    135   EXPECT_EQ(0, snapshot->sum());
    136 
    137   histogram->AddCount(1000000000, 15);
    138   std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
    139   EXPECT_EQ(15, snapshot1->TotalCount());
    140   EXPECT_EQ(15, snapshot1->GetCount(1000000000));
    141 
    142   histogram->AddCount(1000000000, 15);
    143   histogram->AddCount(1010000000, 25);
    144   std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
    145   EXPECT_EQ(55, snapshot2->TotalCount());
    146   EXPECT_EQ(30, snapshot2->GetCount(1000000000));
    147   EXPECT_EQ(25, snapshot2->GetCount(1010000000));
    148   EXPECT_EQ(55250000000LL, snapshot2->sum());
    149 }
    150 
    151 // Make sure that counts returned by Histogram::SnapshotDelta do not overflow
    152 // even when a total count (returned by Histogram::SnapshotSample) does.
    153 TEST_P(SparseHistogramTest, AddCount_LargeCountsDontOverflow) {
    154   std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
    155   std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
    156   EXPECT_EQ(0, snapshot->TotalCount());
    157   EXPECT_EQ(0, snapshot->sum());
    158 
    159   const int count = (1 << 30) - 1;
    160 
    161   // Repeat N times to make sure that there is no internal value overflow.
    162   for (int i = 0; i < 10; ++i) {
    163     histogram->AddCount(42, count);
    164     std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
    165     EXPECT_EQ(count, samples->TotalCount());
    166     EXPECT_EQ(count, samples->GetCount(42));
    167   }
    168 }
    169 
    170 TEST_P(SparseHistogramTest, MacroBasicTest) {
    171   UmaHistogramSparse("Sparse", 100);
    172   UmaHistogramSparse("Sparse", 200);
    173   UmaHistogramSparse("Sparse", 100);
    174 
    175   const StatisticsRecorder::Histograms histograms =
    176       StatisticsRecorder::GetHistograms();
    177 
    178   ASSERT_THAT(histograms, testing::SizeIs(1));
    179   const HistogramBase* const sparse_histogram = histograms[0];
    180 
    181   EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType());
    182   EXPECT_EQ("Sparse", StringPiece(sparse_histogram->histogram_name()));
    183   EXPECT_EQ(
    184       HistogramBase::kUmaTargetedHistogramFlag |
    185           (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent
    186                                                : 0),
    187       sparse_histogram->flags());
    188 
    189   std::unique_ptr<HistogramSamples> samples =
    190       sparse_histogram->SnapshotSamples();
    191   EXPECT_EQ(3, samples->TotalCount());
    192   EXPECT_EQ(2, samples->GetCount(100));
    193   EXPECT_EQ(1, samples->GetCount(200));
    194 }
    195 
    196 TEST_P(SparseHistogramTest, MacroInLoopTest) {
    197   // Unlike the macros in histogram.h, SparseHistogram macros can have a
    198   // variable as histogram name.
    199   for (int i = 0; i < 2; i++) {
    200     UmaHistogramSparse(StringPrintf("Sparse%d", i), 100);
    201   }
    202 
    203   const StatisticsRecorder::Histograms histograms =
    204       StatisticsRecorder::Sort(StatisticsRecorder::GetHistograms());
    205   ASSERT_THAT(histograms, testing::SizeIs(2));
    206   EXPECT_STREQ(histograms[0]->histogram_name(), "Sparse0");
    207   EXPECT_STREQ(histograms[1]->histogram_name(), "Sparse1");
    208 }
    209 
    210 TEST_P(SparseHistogramTest, Serialize) {
    211   std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
    212   histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag);
    213 
    214   Pickle pickle;
    215   histogram->SerializeInfo(&pickle);
    216 
    217   PickleIterator iter(pickle);
    218 
    219   int type;
    220   EXPECT_TRUE(iter.ReadInt(&type));
    221   EXPECT_EQ(SPARSE_HISTOGRAM, type);
    222 
    223   std::string name;
    224   EXPECT_TRUE(iter.ReadString(&name));
    225   EXPECT_EQ("Sparse", name);
    226 
    227   int flag;
    228   EXPECT_TRUE(iter.ReadInt(&flag));
    229   EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
    230 
    231   // No more data in the pickle.
    232   EXPECT_FALSE(iter.SkipBytes(1));
    233 }
    234 
    235 // Ensure that race conditions that cause multiple, identical sparse histograms
    236 // to be created will safely resolve to a single one.
    237 TEST_P(SparseHistogramTest, DuplicationSafety) {
    238   const char histogram_name[] = "Duplicated";
    239   size_t histogram_count = StatisticsRecorder::GetHistogramCount();
    240 
    241   // Create a histogram that we will later duplicate.
    242   HistogramBase* original =
    243       SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags);
    244   ++histogram_count;
    245   DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
    246   original->Add(1);
    247 
    248   // Create a duplicate. This has to happen differently depending on where the
    249   // memory is taken from.
    250   if (use_persistent_histogram_allocator_) {
    251     // To allocate from persistent memory, clear the last_created reference in
    252     // the GlobalHistogramAllocator. This will cause an Import to recreate
    253     // the just-created histogram which will then be released as a duplicate.
    254     GlobalHistogramAllocator::Get()->ClearLastCreatedReferenceForTesting();
    255     // Creating a different histogram will first do an Import to ensure it
    256     // hasn't been created elsewhere, triggering the duplication and release.
    257     SparseHistogram::FactoryGet("something.new", HistogramBase::kNoFlags);
    258     ++histogram_count;
    259   } else {
    260     // To allocate from the heap, just call the (private) constructor directly.
    261     // Delete it immediately like would have happened within FactoryGet();
    262     std::unique_ptr<SparseHistogram> something =
    263         NewSparseHistogram(histogram_name);
    264     DCHECK_NE(original, something.get());
    265   }
    266   DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
    267 
    268   // Re-creating the histogram via FactoryGet() will return the same one.
    269   HistogramBase* duplicate =
    270       SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags);
    271   DCHECK_EQ(original, duplicate);
    272   DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
    273   duplicate->Add(2);
    274 
    275   // Ensure that original histograms are still cross-functional.
    276   original->Add(2);
    277   duplicate->Add(1);
    278   std::unique_ptr<HistogramSamples> snapshot_orig = original->SnapshotSamples();
    279   std::unique_ptr<HistogramSamples> snapshot_dup = duplicate->SnapshotSamples();
    280   DCHECK_EQ(2, snapshot_orig->GetCount(2));
    281   DCHECK_EQ(2, snapshot_dup->GetCount(1));
    282 }
    283 
    284 TEST_P(SparseHistogramTest, FactoryTime) {
    285   const int kTestCreateCount = 1 << 10;  // Must be power-of-2.
    286   const int kTestLookupCount = 100000;
    287   const int kTestAddCount = 100000;
    288 
    289   // Create all histogram names in advance for accurate timing below.
    290   std::vector<std::string> histogram_names;
    291   for (int i = 0; i < kTestCreateCount; ++i) {
    292     histogram_names.push_back(
    293         StringPrintf("TestHistogram.%d", i % kTestCreateCount));
    294   }
    295 
    296   // Calculate cost of creating histograms.
    297   TimeTicks create_start = TimeTicks::Now();
    298   for (int i = 0; i < kTestCreateCount; ++i)
    299     SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags);
    300   TimeDelta create_ticks = TimeTicks::Now() - create_start;
    301   int64_t create_ms = create_ticks.InMilliseconds();
    302 
    303   VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms
    304           << "ms or about "
    305           << (create_ms * 1000000) / kTestCreateCount
    306           << "ns each.";
    307 
    308   // Calculate cost of looking up existing histograms.
    309   TimeTicks lookup_start = TimeTicks::Now();
    310   for (int i = 0; i < kTestLookupCount; ++i) {
    311     // 6007 is co-prime with kTestCreateCount and so will do lookups in an
    312     // order less likely to be cacheable (but still hit them all) should the
    313     // underlying storage use the exact histogram name as the key.
    314     const int i_mult = 6007;
    315     static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big");
    316     int index = (i * i_mult) & (kTestCreateCount - 1);
    317     SparseHistogram::FactoryGet(histogram_names[index],
    318                                 HistogramBase::kNoFlags);
    319   }
    320   TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start;
    321   int64_t lookup_ms = lookup_ticks.InMilliseconds();
    322 
    323   VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms
    324           << "ms or about "
    325           << (lookup_ms * 1000000) / kTestLookupCount
    326           << "ns each.";
    327 
    328   // Calculate cost of accessing histograms.
    329   HistogramBase* histogram =
    330       SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags);
    331   ASSERT_TRUE(histogram);
    332   TimeTicks add_start = TimeTicks::Now();
    333   for (int i = 0; i < kTestAddCount; ++i)
    334     histogram->Add(i & 127);
    335   TimeDelta add_ticks = TimeTicks::Now() - add_start;
    336   int64_t add_ms = add_ticks.InMilliseconds();
    337 
    338   VLOG(1) << kTestAddCount << " histogram adds took " << add_ms
    339           << "ms or about "
    340           << (add_ms * 1000000) / kTestAddCount
    341           << "ns each.";
    342 }
    343 
    344 TEST_P(SparseHistogramTest, ExtremeValues) {
    345   static const struct {
    346     Histogram::Sample sample;
    347     int64_t expected_max;
    348   } cases[] = {
    349       // Note: We use -2147483647 - 1 rather than -2147483648 because the later
    350       // is interpreted as - operator applied to 2147483648 and the latter can't
    351       // be represented as an int32 and causes a warning.
    352       {-2147483647 - 1, -2147483647LL},
    353       {0, 1},
    354       {2147483647, 2147483648LL},
    355   };
    356 
    357   for (size_t i = 0; i < arraysize(cases); ++i) {
    358     HistogramBase* histogram =
    359         SparseHistogram::FactoryGet(StringPrintf("ExtremeValues_%zu", i),
    360                                     HistogramBase::kUmaTargetedHistogramFlag);
    361     histogram->Add(cases[i].sample);
    362 
    363     std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples();
    364     std::unique_ptr<SampleCountIterator> it = snapshot->Iterator();
    365     ASSERT_FALSE(it->Done());
    366 
    367     base::Histogram::Sample min;
    368     int64_t max;
    369     base::Histogram::Count count;
    370     it->Get(&min, &max, &count);
    371 
    372     EXPECT_EQ(1, count);
    373     EXPECT_EQ(cases[i].sample, min);
    374     EXPECT_EQ(cases[i].expected_max, max);
    375 
    376     it->Next();
    377     EXPECT_TRUE(it->Done());
    378   }
    379 }
    380 
    381 TEST_P(SparseHistogramTest, HistogramNameHash) {
    382   const char kName[] = "TestName";
    383   HistogramBase* histogram = SparseHistogram::FactoryGet(
    384       kName, HistogramBase::kUmaTargetedHistogramFlag);
    385   EXPECT_EQ(histogram->name_hash(), HashMetricName(kName));
    386 }
    387 
    388 }  // namespace base
    389