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// Test of Histogram class
6
7#include <climits>
8#include <algorithm>
9#include <vector>
10
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/metrics/bucket_ranges.h"
14#include "base/metrics/histogram.h"
15#include "base/metrics/sample_vector.h"
16#include "base/metrics/statistics_recorder.h"
17#include "base/pickle.h"
18#include "base/time/time.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21using std::vector;
22
23namespace base {
24
25class HistogramTest : public testing::Test {
26 protected:
27  virtual void SetUp() {
28    // Each test will have a clean state (no Histogram / BucketRanges
29    // registered).
30    InitializeStatisticsRecorder();
31  }
32
33  virtual void TearDown() {
34    UninitializeStatisticsRecorder();
35  }
36
37  void InitializeStatisticsRecorder() {
38    statistics_recorder_ = new StatisticsRecorder();
39  }
40
41  void UninitializeStatisticsRecorder() {
42    delete statistics_recorder_;
43    statistics_recorder_ = NULL;
44  }
45
46  StatisticsRecorder* statistics_recorder_;
47};
48
49// Check for basic syntax and use.
50TEST_F(HistogramTest, BasicTest) {
51  // Try basic construction
52  HistogramBase* histogram = Histogram::FactoryGet(
53      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
54  EXPECT_TRUE(histogram);
55
56  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
57      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
58  EXPECT_TRUE(linear_histogram);
59
60  vector<int> custom_ranges;
61  custom_ranges.push_back(1);
62  custom_ranges.push_back(5);
63  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
64      "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
65  EXPECT_TRUE(custom_histogram);
66
67  // Use standard macros (but with fixed samples)
68  HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
69  HISTOGRAM_COUNTS("Test3Histogram", 30);
70
71  DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
72  DHISTOGRAM_COUNTS("Test5Histogram", 30);
73
74  HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
75}
76
77// Check that the macro correctly matches histograms by name and records their
78// data together.
79TEST_F(HistogramTest, NameMatchTest) {
80  HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
81  HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
82  HistogramBase* histogram = LinearHistogram::FactoryGet(
83      "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags);
84
85  scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
86  EXPECT_EQ(2, samples->TotalCount());
87  EXPECT_EQ(2, samples->GetCount(10));
88}
89
90TEST_F(HistogramTest, ExponentialRangesTest) {
91  // Check that we got a nice exponential when there was enough rooom.
92  BucketRanges ranges(9);
93  Histogram::InitializeBucketRanges(1, 64, &ranges);
94  EXPECT_EQ(0, ranges.range(0));
95  int power_of_2 = 1;
96  for (int i = 1; i < 8; i++) {
97    EXPECT_EQ(power_of_2, ranges.range(i));
98    power_of_2 *= 2;
99  }
100  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
101
102  // Check the corresponding Histogram will use the correct ranges.
103  Histogram* histogram = static_cast<Histogram*>(
104      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
105  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
106
107  // When bucket count is limited, exponential ranges will partially look like
108  // linear.
109  BucketRanges ranges2(16);
110  Histogram::InitializeBucketRanges(1, 32, &ranges2);
111
112  EXPECT_EQ(0, ranges2.range(0));
113  EXPECT_EQ(1, ranges2.range(1));
114  EXPECT_EQ(2, ranges2.range(2));
115  EXPECT_EQ(3, ranges2.range(3));
116  EXPECT_EQ(4, ranges2.range(4));
117  EXPECT_EQ(5, ranges2.range(5));
118  EXPECT_EQ(6, ranges2.range(6));
119  EXPECT_EQ(7, ranges2.range(7));
120  EXPECT_EQ(9, ranges2.range(8));
121  EXPECT_EQ(11, ranges2.range(9));
122  EXPECT_EQ(14, ranges2.range(10));
123  EXPECT_EQ(17, ranges2.range(11));
124  EXPECT_EQ(21, ranges2.range(12));
125  EXPECT_EQ(26, ranges2.range(13));
126  EXPECT_EQ(32, ranges2.range(14));
127  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15));
128
129  // Check the corresponding Histogram will use the correct ranges.
130  Histogram* histogram2 = static_cast<Histogram*>(
131      Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags));
132  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
133}
134
135TEST_F(HistogramTest, LinearRangesTest) {
136  BucketRanges ranges(9);
137  LinearHistogram::InitializeBucketRanges(1, 7, &ranges);
138  // Gets a nice linear set of bucket ranges.
139  for (int i = 0; i < 8; i++)
140    EXPECT_EQ(i, ranges.range(i));
141  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
142
143  // The correspoding LinearHistogram should use the correct ranges.
144  Histogram* histogram = static_cast<Histogram*>(
145      LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags));
146  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
147
148  // Linear ranges are not divisible.
149  BucketRanges ranges2(6);
150  LinearHistogram::InitializeBucketRanges(1, 6, &ranges2);
151  EXPECT_EQ(0, ranges2.range(0));
152  EXPECT_EQ(1, ranges2.range(1));
153  EXPECT_EQ(3, ranges2.range(2));
154  EXPECT_EQ(4, ranges2.range(3));
155  EXPECT_EQ(6, ranges2.range(4));
156  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5));
157  // The correspoding LinearHistogram should use the correct ranges.
158  Histogram* histogram2 = static_cast<Histogram*>(
159      LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags));
160  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
161}
162
163TEST_F(HistogramTest, ArrayToCustomRangesTest) {
164  const HistogramBase::Sample ranges[3] = {5, 10, 20};
165  vector<HistogramBase::Sample> ranges_vec =
166      CustomHistogram::ArrayToCustomRanges(ranges, 3);
167  ASSERT_EQ(6u, ranges_vec.size());
168  EXPECT_EQ(5, ranges_vec[0]);
169  EXPECT_EQ(6, ranges_vec[1]);
170  EXPECT_EQ(10, ranges_vec[2]);
171  EXPECT_EQ(11, ranges_vec[3]);
172  EXPECT_EQ(20, ranges_vec[4]);
173  EXPECT_EQ(21, ranges_vec[5]);
174}
175
176TEST_F(HistogramTest, CustomHistogramTest) {
177  // A well prepared custom ranges.
178  vector<HistogramBase::Sample> custom_ranges;
179  custom_ranges.push_back(1);
180  custom_ranges.push_back(2);
181
182  Histogram* histogram = static_cast<Histogram*>(
183      CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges,
184                                  HistogramBase::kNoFlags));
185  const BucketRanges* ranges = histogram->bucket_ranges();
186  ASSERT_EQ(4u, ranges->size());
187  EXPECT_EQ(0, ranges->range(0));  // Auto added.
188  EXPECT_EQ(1, ranges->range(1));
189  EXPECT_EQ(2, ranges->range(2));
190  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));  // Auto added.
191
192  // A unordered custom ranges.
193  custom_ranges.clear();
194  custom_ranges.push_back(2);
195  custom_ranges.push_back(1);
196  histogram = static_cast<Histogram*>(
197      CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges,
198                                  HistogramBase::kNoFlags));
199  ranges = histogram->bucket_ranges();
200  ASSERT_EQ(4u, ranges->size());
201  EXPECT_EQ(0, ranges->range(0));
202  EXPECT_EQ(1, ranges->range(1));
203  EXPECT_EQ(2, ranges->range(2));
204  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
205
206  // A custom ranges with duplicated values.
207  custom_ranges.clear();
208  custom_ranges.push_back(4);
209  custom_ranges.push_back(1);
210  custom_ranges.push_back(4);
211  histogram = static_cast<Histogram*>(
212      CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges,
213                                  HistogramBase::kNoFlags));
214  ranges = histogram->bucket_ranges();
215  ASSERT_EQ(4u, ranges->size());
216  EXPECT_EQ(0, ranges->range(0));
217  EXPECT_EQ(1, ranges->range(1));
218  EXPECT_EQ(4, ranges->range(2));
219  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
220}
221
222TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
223  // This test exploits the fact that the CustomHistogram can have 2 buckets,
224  // while the base class Histogram is *supposed* to have at least 3 buckets.
225  // We should probably change the restriction on the base class (or not inherit
226  // the base class!).
227
228  vector<HistogramBase::Sample> custom_ranges;
229  custom_ranges.push_back(4);
230
231  Histogram* histogram = static_cast<Histogram*>(
232      CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges,
233                                  HistogramBase::kNoFlags));
234  const BucketRanges* ranges = histogram->bucket_ranges();
235  ASSERT_EQ(3u, ranges->size());
236  EXPECT_EQ(0, ranges->range(0));
237  EXPECT_EQ(4, ranges->range(1));
238  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
239}
240
241// Make sure histogram handles out-of-bounds data gracefully.
242TEST_F(HistogramTest, BoundsTest) {
243  const size_t kBucketCount = 50;
244  Histogram* histogram = static_cast<Histogram*>(
245      Histogram::FactoryGet("Bounded", 10, 100, kBucketCount,
246                            HistogramBase::kNoFlags));
247
248  // Put two samples "out of bounds" above and below.
249  histogram->Add(5);
250  histogram->Add(-50);
251
252  histogram->Add(100);
253  histogram->Add(10000);
254
255  // Verify they landed in the underflow, and overflow buckets.
256  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
257  EXPECT_EQ(2, samples->GetCountAtIndex(0));
258  EXPECT_EQ(0, samples->GetCountAtIndex(1));
259  size_t array_size = histogram->bucket_count();
260  EXPECT_EQ(kBucketCount, array_size);
261  EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
262  EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
263
264  vector<int> custom_ranges;
265  custom_ranges.push_back(10);
266  custom_ranges.push_back(50);
267  custom_ranges.push_back(100);
268  Histogram* test_custom_histogram = static_cast<Histogram*>(
269      CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
270                                  custom_ranges, HistogramBase::kNoFlags));
271
272  // Put two samples "out of bounds" above and below.
273  test_custom_histogram->Add(5);
274  test_custom_histogram->Add(-50);
275  test_custom_histogram->Add(100);
276  test_custom_histogram->Add(1000);
277  test_custom_histogram->Add(INT_MAX);
278
279  // Verify they landed in the underflow, and overflow buckets.
280  scoped_ptr<SampleVector> custom_samples =
281      test_custom_histogram->SnapshotSampleVector();
282  EXPECT_EQ(2, custom_samples->GetCountAtIndex(0));
283  EXPECT_EQ(0, custom_samples->GetCountAtIndex(1));
284  size_t bucket_count = test_custom_histogram->bucket_count();
285  EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2));
286  EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1));
287}
288
289// Check to be sure samples land as expected is "correct" buckets.
290TEST_F(HistogramTest, BucketPlacementTest) {
291  Histogram* histogram = static_cast<Histogram*>(
292      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
293
294  // Add i+1 samples to the i'th bucket.
295  histogram->Add(0);
296  int power_of_2 = 1;
297  for (int i = 1; i < 8; i++) {
298    for (int j = 0; j <= i; j++)
299      histogram->Add(power_of_2);
300    power_of_2 *= 2;
301  }
302
303  // Check to see that the bucket counts reflect our additions.
304  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
305  for (int i = 0; i < 8; i++)
306    EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
307}
308
309TEST_F(HistogramTest, CorruptSampleCounts) {
310  Histogram* histogram = static_cast<Histogram*>(
311      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
312
313  // Add some samples.
314  histogram->Add(20);
315  histogram->Add(40);
316
317  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
318  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
319            histogram->FindCorruption(*snapshot));
320  EXPECT_EQ(2, snapshot->redundant_count());
321  EXPECT_EQ(2, snapshot->TotalCount());
322
323  snapshot->counts_[3] += 100;  // Sample count won't match redundant count.
324  EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR,
325            histogram->FindCorruption(*snapshot));
326  snapshot->counts_[2] -= 200;
327  EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR,
328            histogram->FindCorruption(*snapshot));
329
330  // But we can't spot a corruption if it is compensated for.
331  snapshot->counts_[1] += 100;
332  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
333            histogram->FindCorruption(*snapshot));
334}
335
336TEST_F(HistogramTest, CorruptBucketBounds) {
337  Histogram* histogram = static_cast<Histogram*>(
338      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
339
340  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
341  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
342            histogram->FindCorruption(*snapshot));
343
344  BucketRanges* bucket_ranges =
345      const_cast<BucketRanges*>(histogram->bucket_ranges());
346  HistogramBase::Sample tmp = bucket_ranges->range(1);
347  bucket_ranges->set_range(1, bucket_ranges->range(2));
348  bucket_ranges->set_range(2, tmp);
349  EXPECT_EQ(
350      HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR,
351      histogram->FindCorruption(*snapshot));
352
353  bucket_ranges->set_range(2, bucket_ranges->range(1));
354  bucket_ranges->set_range(1, tmp);
355  EXPECT_EQ(0, histogram->FindCorruption(*snapshot));
356
357  // Show that two simple changes don't offset each other
358  bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
359  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
360            histogram->FindCorruption(*snapshot));
361
362  bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
363  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
364            histogram->FindCorruption(*snapshot));
365
366  // Repair histogram so that destructor won't DCHECK().
367  bucket_ranges->set_range(3, bucket_ranges->range(3) - 1);
368  bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
369}
370
371TEST_F(HistogramTest, HistogramSerializeInfo) {
372  Histogram* histogram = static_cast<Histogram*>(
373      Histogram::FactoryGet("Histogram", 1, 64, 8,
374                            HistogramBase::kIPCSerializationSourceFlag));
375  Pickle pickle;
376  histogram->SerializeInfo(&pickle);
377
378  PickleIterator iter(pickle);
379
380  int type;
381  EXPECT_TRUE(iter.ReadInt(&type));
382  EXPECT_EQ(HISTOGRAM, type);
383
384  std::string name;
385  EXPECT_TRUE(iter.ReadString(&name));
386  EXPECT_EQ("Histogram", name);
387
388  int flag;
389  EXPECT_TRUE(iter.ReadInt(&flag));
390  EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
391
392  int min;
393  EXPECT_TRUE(iter.ReadInt(&min));
394  EXPECT_EQ(1, min);
395
396  int max;
397  EXPECT_TRUE(iter.ReadInt(&max));
398  EXPECT_EQ(64, max);
399
400  int64 bucket_count;
401  EXPECT_TRUE(iter.ReadInt64(&bucket_count));
402  EXPECT_EQ(8, bucket_count);
403
404  uint32 checksum;
405  EXPECT_TRUE(iter.ReadUInt32(&checksum));
406  EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
407
408  // No more data in the pickle.
409  EXPECT_FALSE(iter.SkipBytes(1));
410}
411
412TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
413  vector<int> custom_ranges;
414  custom_ranges.push_back(10);
415  custom_ranges.push_back(100);
416
417  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
418      "TestCustomRangeBoundedHistogram",
419      custom_ranges,
420      HistogramBase::kNoFlags);
421  Pickle pickle;
422  custom_histogram->SerializeInfo(&pickle);
423
424  // Validate the pickle.
425  PickleIterator iter(pickle);
426
427  int i;
428  std::string s;
429  int64 bucket_count;
430  uint32 ui32;
431  EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
432              iter.ReadInt(&i) && iter.ReadInt(&i) &&
433              iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
434  EXPECT_EQ(3, bucket_count);
435
436  int range;
437  EXPECT_TRUE(iter.ReadInt(&range));
438  EXPECT_EQ(10, range);
439  EXPECT_TRUE(iter.ReadInt(&range));
440  EXPECT_EQ(100, range);
441
442  // No more data in the pickle.
443  EXPECT_FALSE(iter.SkipBytes(1));
444}
445
446#if GTEST_HAS_DEATH_TEST
447// For Histogram, LinearHistogram and CustomHistogram, the minimum for a
448// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
449// 1). But we accept ranges exceeding those limits, and silently clamped to
450// those limits. This is for backwards compatibility.
451TEST(HistogramDeathTest, BadRangesTest) {
452  HistogramBase* histogram = Histogram::FactoryGet(
453      "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
454      HistogramBase::kNoFlags);
455  EXPECT_TRUE(
456      histogram->HasConstructionArguments(
457          1, HistogramBase::kSampleType_MAX - 1, 8));
458
459  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
460      "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
461      HistogramBase::kNoFlags);
462  EXPECT_TRUE(
463      linear_histogram->HasConstructionArguments(
464          1, HistogramBase::kSampleType_MAX - 1, 8));
465
466  vector<int> custom_ranges;
467  custom_ranges.push_back(0);
468  custom_ranges.push_back(5);
469  Histogram* custom_histogram = static_cast<Histogram*>(
470      CustomHistogram::FactoryGet(
471          "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags));
472  const BucketRanges* ranges = custom_histogram->bucket_ranges();
473  ASSERT_EQ(3u, ranges->size());
474  EXPECT_EQ(0, ranges->range(0));
475  EXPECT_EQ(5, ranges->range(1));
476  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
477
478  // CustomHistogram does not accepts kSampleType_MAX as range.
479  custom_ranges.push_back(HistogramBase::kSampleType_MAX);
480  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
481                                           HistogramBase::kNoFlags),
482               "");
483
484  // CustomHistogram needs at least 1 valid range.
485  custom_ranges.clear();
486  custom_ranges.push_back(0);
487  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
488                                           HistogramBase::kNoFlags),
489               "");
490}
491#endif
492
493}  // namespace base
494