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