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