histogram_unittest.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2006-2008 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 "base/metrics/histogram.h"
8#include "base/time.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace base {
12namespace {
13
14class HistogramTest : public testing::Test {
15};
16
17// Check for basic syntax and use.
18TEST(HistogramTest, StartupShutdownTest) {
19  // Try basic construction
20  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
21      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
22  scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
23      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
24
25  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
26      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
27  scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
28      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
29
30  std::vector<int> custom_ranges;
31  custom_ranges.push_back(1);
32  custom_ranges.push_back(5);
33  custom_ranges.push_back(10);
34  custom_ranges.push_back(20);
35  custom_ranges.push_back(30);
36  scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
37      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
38  scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
39      "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags);
40
41  // Use standard macros (but with fixed samples)
42  HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
43  HISTOGRAM_COUNTS("Test3Histogram", 30);
44
45  DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
46  DHISTOGRAM_COUNTS("Test5Histogram", 30);
47
48  HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
49
50  // Try to construct samples.
51  Histogram::SampleSet sample1;
52  Histogram::SampleSet sample2;
53
54  // Use copy constructor of SampleSet
55  sample1 = sample2;
56  Histogram::SampleSet sample3(sample1);
57
58  // Finally test a statistics recorder, without really using it.
59  StatisticsRecorder recorder;
60}
61
62// Repeat with a recorder present to register with.
63TEST(HistogramTest, RecordedStartupTest) {
64  // Test a statistics recorder, by letting histograms register.
65  StatisticsRecorder recorder;  // This initializes the global state.
66
67  StatisticsRecorder::Histograms histograms;
68  EXPECT_EQ(0U, histograms.size());
69  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
70  EXPECT_EQ(0U, histograms.size());
71
72  // Try basic construction
73  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
74      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
75  histograms.clear();
76  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
77  EXPECT_EQ(1U, histograms.size());
78  scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
79      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
80  histograms.clear();
81  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
82  EXPECT_EQ(2U, histograms.size());
83
84  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
85      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
86  histograms.clear();
87  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
88  EXPECT_EQ(3U, histograms.size());
89
90  scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
91      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
92  histograms.clear();
93  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
94  EXPECT_EQ(4U, histograms.size());
95
96  std::vector<int> custom_ranges;
97  custom_ranges.push_back(1);
98  custom_ranges.push_back(5);
99  custom_ranges.push_back(10);
100  custom_ranges.push_back(20);
101  custom_ranges.push_back(30);
102  scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
103      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
104  scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
105      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
106
107  histograms.clear();
108  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
109  EXPECT_EQ(5U, histograms.size());
110
111  // Use standard macros (but with fixed samples)
112  HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
113  HISTOGRAM_COUNTS("Test3Histogram", 30);
114  histograms.clear();
115  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
116  EXPECT_EQ(7U, histograms.size());
117
118  HISTOGRAM_ENUMERATION("TestEnumerationHistogram", 20, 200);
119  histograms.clear();
120  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
121  EXPECT_EQ(8U, histograms.size());
122
123  DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
124  DHISTOGRAM_COUNTS("Test5Histogram", 30);
125  histograms.clear();
126  StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
127#ifndef NDEBUG
128  EXPECT_EQ(10U, histograms.size());
129#else
130  EXPECT_EQ(8U, histograms.size());
131#endif
132}
133
134TEST(HistogramTest, RangeTest) {
135  StatisticsRecorder recorder;
136  StatisticsRecorder::Histograms histograms;
137
138  recorder.GetHistograms(&histograms);
139  EXPECT_EQ(0U, histograms.size());
140
141  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
142      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
143  // Check that we got a nice exponential when there was enough rooom.
144  EXPECT_EQ(0, histogram->ranges(0));
145  int power_of_2 = 1;
146  for (int i = 1; i < 8; i++) {
147    EXPECT_EQ(power_of_2, histogram->ranges(i));
148    power_of_2 *= 2;
149  }
150  EXPECT_EQ(INT_MAX, histogram->ranges(8));
151
152  scoped_refptr<Histogram> short_histogram = Histogram::FactoryGet(
153      "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags);
154  // Check that when the number of buckets is short, we get a linear histogram
155  // for lack of space to do otherwise.
156  for (int i = 0; i < 8; i++)
157    EXPECT_EQ(i, short_histogram->ranges(i));
158  EXPECT_EQ(INT_MAX, short_histogram->ranges(8));
159
160  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
161      "Linear", 1, 7, 8, Histogram::kNoFlags);
162  // We also get a nice linear set of bucket ranges when we ask for it
163  for (int i = 0; i < 8; i++)
164    EXPECT_EQ(i, linear_histogram->ranges(i));
165  EXPECT_EQ(INT_MAX, linear_histogram->ranges(8));
166
167  scoped_refptr<Histogram> linear_broad_histogram = LinearHistogram::FactoryGet(
168      "Linear widened", 2, 14, 8, Histogram::kNoFlags);
169  // ...but when the list has more space, then the ranges naturally spread out.
170  for (int i = 0; i < 8; i++)
171    EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i));
172  EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8));
173
174  scoped_refptr<Histogram> transitioning_histogram =
175      Histogram::FactoryGet("LinearAndExponential", 1, 32, 15,
176                                      Histogram::kNoFlags);
177  // When space is a little tight, we transition from linear to exponential.
178  EXPECT_EQ(0, transitioning_histogram->ranges(0));
179  EXPECT_EQ(1, transitioning_histogram->ranges(1));
180  EXPECT_EQ(2, transitioning_histogram->ranges(2));
181  EXPECT_EQ(3, transitioning_histogram->ranges(3));
182  EXPECT_EQ(4, transitioning_histogram->ranges(4));
183  EXPECT_EQ(5, transitioning_histogram->ranges(5));
184  EXPECT_EQ(6, transitioning_histogram->ranges(6));
185  EXPECT_EQ(7, transitioning_histogram->ranges(7));
186  EXPECT_EQ(9, transitioning_histogram->ranges(8));
187  EXPECT_EQ(11, transitioning_histogram->ranges(9));
188  EXPECT_EQ(14, transitioning_histogram->ranges(10));
189  EXPECT_EQ(17, transitioning_histogram->ranges(11));
190  EXPECT_EQ(21, transitioning_histogram->ranges(12));
191  EXPECT_EQ(26, transitioning_histogram->ranges(13));
192  EXPECT_EQ(32, transitioning_histogram->ranges(14));
193  EXPECT_EQ(INT_MAX, transitioning_histogram->ranges(15));
194
195  std::vector<int> custom_ranges;
196  custom_ranges.push_back(0);
197  custom_ranges.push_back(9);
198  custom_ranges.push_back(10);
199  custom_ranges.push_back(11);
200  custom_ranges.push_back(300);
201  scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
202      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
203
204  EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(0));
205  EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(1));
206  EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(2));
207  EXPECT_EQ(custom_ranges[3], test_custom_histogram->ranges(3));
208  EXPECT_EQ(custom_ranges[4], test_custom_histogram->ranges(4));
209
210  recorder.GetHistograms(&histograms);
211  EXPECT_EQ(6U, histograms.size());
212}
213
214TEST(HistogramTest, CustomRangeTest) {
215  StatisticsRecorder recorder;
216  StatisticsRecorder::Histograms histograms;
217
218  // Check that missing leading zero is handled by an auto-insertion.
219  std::vector<int> custom_ranges;
220  // Don't include a zero.
221  custom_ranges.push_back(9);
222  custom_ranges.push_back(10);
223  custom_ranges.push_back(11);
224  scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
225      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
226
227  EXPECT_EQ(0, test_custom_histogram->ranges(0));  // Auto added
228  EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(1));
229  EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(2));
230  EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(3));
231
232  // Check that unsorted data with dups is handled gracefully.
233  const int kSmall = 7;
234  const int kMid = 8;
235  const int kBig = 9;
236  custom_ranges.clear();
237  custom_ranges.push_back(kBig);
238  custom_ranges.push_back(kMid);
239  custom_ranges.push_back(kSmall);
240  custom_ranges.push_back(kSmall);
241  custom_ranges.push_back(kMid);
242  custom_ranges.push_back(0);  // Push an explicit zero.
243  custom_ranges.push_back(kBig);
244
245  scoped_refptr<Histogram> unsorted_histogram = CustomHistogram::FactoryGet(
246      "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags);
247  EXPECT_EQ(0, unsorted_histogram->ranges(0));
248  EXPECT_EQ(kSmall, unsorted_histogram->ranges(1));
249  EXPECT_EQ(kMid, unsorted_histogram->ranges(2));
250  EXPECT_EQ(kBig, unsorted_histogram->ranges(3));
251}
252
253
254// Make sure histogram handles out-of-bounds data gracefully.
255TEST(HistogramTest, BoundsTest) {
256  const size_t kBucketCount = 50;
257  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
258      "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags);
259
260  // Put two samples "out of bounds" above and below.
261  histogram->Add(5);
262  histogram->Add(-50);
263
264  histogram->Add(100);
265  histogram->Add(10000);
266
267  // Verify they landed in the underflow, and overflow buckets.
268  Histogram::SampleSet sample;
269  histogram->SnapshotSample(&sample);
270  EXPECT_EQ(2, sample.counts(0));
271  EXPECT_EQ(0, sample.counts(1));
272  size_t array_size = histogram->bucket_count();
273  EXPECT_EQ(kBucketCount, array_size);
274  EXPECT_EQ(0, sample.counts(array_size - 2));
275  EXPECT_EQ(2, sample.counts(array_size - 1));
276}
277
278// Check to be sure samples land as expected is "correct" buckets.
279TEST(HistogramTest, BucketPlacementTest) {
280  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
281      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
282
283  // Check that we got a nice exponential since there was enough rooom.
284  EXPECT_EQ(0, histogram->ranges(0));
285  int power_of_2 = 1;
286  for (int i = 1; i < 8; i++) {
287    EXPECT_EQ(power_of_2, histogram->ranges(i));
288    power_of_2 *= 2;
289  }
290  EXPECT_EQ(INT_MAX, histogram->ranges(8));
291
292  // Add i+1 samples to the i'th bucket.
293  histogram->Add(0);
294  power_of_2 = 1;
295  for (int i = 1; i < 8; i++) {
296    for (int j = 0; j <= i; j++)
297      histogram->Add(power_of_2);
298    power_of_2 *= 2;
299  }
300  // Leave overflow bucket empty.
301
302  // Check to see that the bucket counts reflect our additions.
303  Histogram::SampleSet sample;
304  histogram->SnapshotSample(&sample);
305  EXPECT_EQ(INT_MAX, histogram->ranges(8));
306  for (int i = 0; i < 8; i++)
307    EXPECT_EQ(i + 1, sample.counts(i));
308}
309
310}  // namespace
311}  // namespace base
312