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