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