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.
5 // Test of Histogram class
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.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 class HistogramTest
: public testing::Test
{
27 virtual void SetUp() {
28 // Each test will have a clean state (no Histogram / BucketRanges
30 InitializeStatisticsRecorder();
33 virtual void TearDown() {
34 UninitializeStatisticsRecorder();
37 void InitializeStatisticsRecorder() {
38 statistics_recorder_
= new StatisticsRecorder();
41 void UninitializeStatisticsRecorder() {
42 delete statistics_recorder_
;
43 statistics_recorder_
= NULL
;
46 StatisticsRecorder
* statistics_recorder_
;
49 // Check for basic syntax and use.
50 TEST_F(HistogramTest
, BasicTest
) {
51 // Try basic construction
52 HistogramBase
* histogram
= Histogram::FactoryGet(
53 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags
);
54 EXPECT_TRUE(histogram
);
56 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
57 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags
);
58 EXPECT_TRUE(linear_histogram
);
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
);
67 // Use standard macros (but with fixed samples)
68 HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
69 HISTOGRAM_COUNTS("Test3Histogram", 30);
71 DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
72 DHISTOGRAM_COUNTS("Test5Histogram", 30);
74 HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
77 // Check that the macro correctly matches histograms by name and records their
79 TEST_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
);
85 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
86 EXPECT_EQ(2, samples
->TotalCount());
87 EXPECT_EQ(2, samples
->GetCount(10));
90 TEST_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, 8, &ranges
);
94 EXPECT_EQ(0, ranges
.range(0));
96 for (int i
= 1; i
< 8; i
++) {
97 EXPECT_EQ(power_of_2
, ranges
.range(i
));
100 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
.range(8));
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()));
107 // When bucket count is limited, exponential ranges will partially look like
109 BucketRanges
ranges2(16);
110 Histogram::InitializeBucketRanges(1, 32, 15, &ranges2
);
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));
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()));
135 TEST_F(HistogramTest
, LinearRangesTest
) {
136 BucketRanges
ranges(9);
137 LinearHistogram::InitializeBucketRanges(1, 7, 8, &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));
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()));
148 // Linear ranges are not divisible.
149 BucketRanges
ranges2(6);
150 LinearHistogram::InitializeBucketRanges(1, 6, 5, &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()));
163 TEST_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]);
176 TEST_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);
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.
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));
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));
222 TEST_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
228 vector
<HistogramBase::Sample
> custom_ranges
;
229 custom_ranges
.push_back(4);
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));
241 // Make sure histogram handles out-of-bounds data gracefully.
242 TEST_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
));
248 // Put two samples "out of bounds" above and below.
253 histogram
->Add(10000);
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));
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
));
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
);
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));
289 // Check to be sure samples land as expected is "correct" buckets.
290 TEST_F(HistogramTest
, BucketPlacementTest
) {
291 Histogram
* histogram
= static_cast<Histogram
*>(
292 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
294 // Add i+1 samples to the i'th bucket.
297 for (int i
= 1; i
< 8; i
++) {
298 for (int j
= 0; j
<= i
; j
++)
299 histogram
->Add(power_of_2
);
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
));
309 TEST_F(HistogramTest
, CorruptSampleCounts
) {
310 Histogram
* histogram
= static_cast<Histogram
*>(
311 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
317 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
318 EXPECT_EQ(Histogram::NO_INCONSISTENCIES
,
319 histogram
->FindCorruption(*snapshot
));
320 EXPECT_EQ(2, snapshot
->redundant_count());
321 EXPECT_EQ(2, snapshot
->TotalCount());
323 snapshot
->counts_
[3] += 100; // Sample count won't match redundant count.
324 EXPECT_EQ(Histogram::COUNT_LOW_ERROR
,
325 histogram
->FindCorruption(*snapshot
));
326 snapshot
->counts_
[2] -= 200;
327 EXPECT_EQ(Histogram::COUNT_HIGH_ERROR
,
328 histogram
->FindCorruption(*snapshot
));
330 // But we can't spot a corruption if it is compensated for.
331 snapshot
->counts_
[1] += 100;
332 EXPECT_EQ(Histogram::NO_INCONSISTENCIES
,
333 histogram
->FindCorruption(*snapshot
));
336 TEST_F(HistogramTest
, CorruptBucketBounds
) {
337 Histogram
* histogram
= static_cast<Histogram
*>(
338 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
340 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
341 EXPECT_EQ(Histogram::NO_INCONSISTENCIES
,
342 histogram
->FindCorruption(*snapshot
));
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(Histogram::BUCKET_ORDER_ERROR
| Histogram::RANGE_CHECKSUM_ERROR
,
350 histogram
->FindCorruption(*snapshot
));
352 bucket_ranges
->set_range(2, bucket_ranges
->range(1));
353 bucket_ranges
->set_range(1, tmp
);
354 EXPECT_EQ(0, histogram
->FindCorruption(*snapshot
));
356 // Show that two simple changes don't offset each other
357 bucket_ranges
->set_range(3, bucket_ranges
->range(3) + 1);
358 EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR
,
359 histogram
->FindCorruption(*snapshot
));
361 bucket_ranges
->set_range(4, bucket_ranges
->range(4) - 1);
362 EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR
,
363 histogram
->FindCorruption(*snapshot
));
365 // Repair histogram so that destructor won't DCHECK().
366 bucket_ranges
->set_range(3, bucket_ranges
->range(3) - 1);
367 bucket_ranges
->set_range(4, bucket_ranges
->range(4) + 1);
370 TEST_F(HistogramTest
, HistogramSerializeInfo
) {
371 Histogram
* histogram
= static_cast<Histogram
*>(
372 Histogram::FactoryGet("Histogram", 1, 64, 8,
373 HistogramBase::kIPCSerializationSourceFlag
));
375 histogram
->SerializeInfo(&pickle
);
377 PickleIterator
iter(pickle
);
380 EXPECT_TRUE(iter
.ReadInt(&type
));
381 EXPECT_EQ(HISTOGRAM
, type
);
384 EXPECT_TRUE(iter
.ReadString(&name
));
385 EXPECT_EQ("Histogram", name
);
388 EXPECT_TRUE(iter
.ReadInt(&flag
));
389 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag
, flag
);
392 EXPECT_TRUE(iter
.ReadInt(&min
));
396 EXPECT_TRUE(iter
.ReadInt(&max
));
400 EXPECT_TRUE(iter
.ReadInt64(&bucket_count
));
401 EXPECT_EQ(8, bucket_count
);
404 EXPECT_TRUE(iter
.ReadUInt32(&checksum
));
405 EXPECT_EQ(histogram
->bucket_ranges()->checksum(), checksum
);
407 // No more data in the pickle.
408 EXPECT_FALSE(iter
.SkipBytes(1));
411 TEST_F(HistogramTest
, CustomHistogramSerializeInfo
) {
412 vector
<int> custom_ranges
;
413 custom_ranges
.push_back(10);
414 custom_ranges
.push_back(100);
416 HistogramBase
* custom_histogram
= CustomHistogram::FactoryGet(
417 "TestCustomRangeBoundedHistogram",
419 HistogramBase::kNoFlags
);
421 custom_histogram
->SerializeInfo(&pickle
);
423 // Validate the pickle.
424 PickleIterator
iter(pickle
);
430 EXPECT_TRUE(iter
.ReadInt(&i
) && iter
.ReadString(&s
) && iter
.ReadInt(&i
) &&
431 iter
.ReadInt(&i
) && iter
.ReadInt(&i
) &&
432 iter
.ReadInt64(&bucket_count
) && iter
.ReadUInt32(&ui32
));
433 EXPECT_EQ(3, bucket_count
);
436 EXPECT_TRUE(iter
.ReadInt(&range
));
437 EXPECT_EQ(10, range
);
438 EXPECT_TRUE(iter
.ReadInt(&range
));
439 EXPECT_EQ(100, range
);
441 // No more data in the pickle.
442 EXPECT_FALSE(iter
.SkipBytes(1));
445 #if GTEST_HAS_DEATH_TEST
446 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a
447 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
448 // 1). But we accept ranges exceeding those limits, and silently clamped to
449 // those limits. This is for backwards compatibility.
450 TEST(HistogramDeathTest
, BadRangesTest
) {
451 HistogramBase
* histogram
= Histogram::FactoryGet(
452 "BadRanges", 0, HistogramBase::kSampleType_MAX
, 8,
453 HistogramBase::kNoFlags
);
455 histogram
->HasConstructionArguments(
456 1, HistogramBase::kSampleType_MAX
- 1, 8));
458 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
459 "BadRangesLinear", 0, HistogramBase::kSampleType_MAX
, 8,
460 HistogramBase::kNoFlags
);
462 linear_histogram
->HasConstructionArguments(
463 1, HistogramBase::kSampleType_MAX
- 1, 8));
465 vector
<int> custom_ranges
;
466 custom_ranges
.push_back(0);
467 custom_ranges
.push_back(5);
468 Histogram
* custom_histogram
= static_cast<Histogram
*>(
469 CustomHistogram::FactoryGet(
470 "BadRangesCustom", custom_ranges
, HistogramBase::kNoFlags
));
471 const BucketRanges
* ranges
= custom_histogram
->bucket_ranges();
472 ASSERT_EQ(3u, ranges
->size());
473 EXPECT_EQ(0, ranges
->range(0));
474 EXPECT_EQ(5, ranges
->range(1));
475 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(2));
477 // CustomHistogram does not accepts kSampleType_MAX as range.
478 custom_ranges
.push_back(HistogramBase::kSampleType_MAX
);
479 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges
,
480 HistogramBase::kNoFlags
),
483 // CustomHistogram needs at least 1 valid range.
484 custom_ranges
.clear();
485 custom_ranges
.push_back(0);
486 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges
,
487 HistogramBase::kNoFlags
),