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/time.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 class HistogramTest
: public testing::Test
{
27 void SetUp() override
{
28 // Each test will have a clean state (no Histogram / BucketRanges
30 InitializeStatisticsRecorder();
33 void TearDown() override
{ UninitializeStatisticsRecorder(); }
35 void InitializeStatisticsRecorder() {
36 statistics_recorder_
= new StatisticsRecorder();
39 void UninitializeStatisticsRecorder() {
40 delete statistics_recorder_
;
41 statistics_recorder_
= NULL
;
44 StatisticsRecorder
* statistics_recorder_
;
47 // Check for basic syntax and use.
48 TEST_F(HistogramTest
, BasicTest
) {
49 // Try basic construction
50 HistogramBase
* histogram
= Histogram::FactoryGet(
51 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags
);
52 EXPECT_TRUE(histogram
);
54 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
55 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags
);
56 EXPECT_TRUE(linear_histogram
);
58 vector
<int> custom_ranges
;
59 custom_ranges
.push_back(1);
60 custom_ranges
.push_back(5);
61 HistogramBase
* custom_histogram
= CustomHistogram::FactoryGet(
62 "TestCustomHistogram", custom_ranges
, HistogramBase::kNoFlags
);
63 EXPECT_TRUE(custom_histogram
);
65 // Use standard macros (but with fixed samples)
66 LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
67 LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
69 LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
72 // Check that the macro correctly matches histograms by name and records their
74 TEST_F(HistogramTest
, NameMatchTest
) {
75 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
76 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
77 HistogramBase
* histogram
= LinearHistogram::FactoryGet(
78 "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags
);
80 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
81 EXPECT_EQ(2, samples
->TotalCount());
82 EXPECT_EQ(2, samples
->GetCount(10));
85 TEST_F(HistogramTest
, ExponentialRangesTest
) {
86 // Check that we got a nice exponential when there was enough rooom.
87 BucketRanges
ranges(9);
88 Histogram::InitializeBucketRanges(1, 64, &ranges
);
89 EXPECT_EQ(0, ranges
.range(0));
91 for (int i
= 1; i
< 8; i
++) {
92 EXPECT_EQ(power_of_2
, ranges
.range(i
));
95 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
.range(8));
97 // Check the corresponding Histogram will use the correct ranges.
98 Histogram
* histogram
= static_cast<Histogram
*>(
99 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
100 EXPECT_TRUE(ranges
.Equals(histogram
->bucket_ranges()));
102 // When bucket count is limited, exponential ranges will partially look like
104 BucketRanges
ranges2(16);
105 Histogram::InitializeBucketRanges(1, 32, &ranges2
);
107 EXPECT_EQ(0, ranges2
.range(0));
108 EXPECT_EQ(1, ranges2
.range(1));
109 EXPECT_EQ(2, ranges2
.range(2));
110 EXPECT_EQ(3, ranges2
.range(3));
111 EXPECT_EQ(4, ranges2
.range(4));
112 EXPECT_EQ(5, ranges2
.range(5));
113 EXPECT_EQ(6, ranges2
.range(6));
114 EXPECT_EQ(7, ranges2
.range(7));
115 EXPECT_EQ(9, ranges2
.range(8));
116 EXPECT_EQ(11, ranges2
.range(9));
117 EXPECT_EQ(14, ranges2
.range(10));
118 EXPECT_EQ(17, ranges2
.range(11));
119 EXPECT_EQ(21, ranges2
.range(12));
120 EXPECT_EQ(26, ranges2
.range(13));
121 EXPECT_EQ(32, ranges2
.range(14));
122 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges2
.range(15));
124 // Check the corresponding Histogram will use the correct ranges.
125 Histogram
* histogram2
= static_cast<Histogram
*>(
126 Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags
));
127 EXPECT_TRUE(ranges2
.Equals(histogram2
->bucket_ranges()));
130 TEST_F(HistogramTest
, LinearRangesTest
) {
131 BucketRanges
ranges(9);
132 LinearHistogram::InitializeBucketRanges(1, 7, &ranges
);
133 // Gets a nice linear set of bucket ranges.
134 for (int i
= 0; i
< 8; i
++)
135 EXPECT_EQ(i
, ranges
.range(i
));
136 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
.range(8));
138 // The correspoding LinearHistogram should use the correct ranges.
139 Histogram
* histogram
= static_cast<Histogram
*>(
140 LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags
));
141 EXPECT_TRUE(ranges
.Equals(histogram
->bucket_ranges()));
143 // Linear ranges are not divisible.
144 BucketRanges
ranges2(6);
145 LinearHistogram::InitializeBucketRanges(1, 6, &ranges2
);
146 EXPECT_EQ(0, ranges2
.range(0));
147 EXPECT_EQ(1, ranges2
.range(1));
148 EXPECT_EQ(3, ranges2
.range(2));
149 EXPECT_EQ(4, ranges2
.range(3));
150 EXPECT_EQ(6, ranges2
.range(4));
151 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges2
.range(5));
152 // The correspoding LinearHistogram should use the correct ranges.
153 Histogram
* histogram2
= static_cast<Histogram
*>(
154 LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags
));
155 EXPECT_TRUE(ranges2
.Equals(histogram2
->bucket_ranges()));
158 TEST_F(HistogramTest
, ArrayToCustomRangesTest
) {
159 const HistogramBase::Sample ranges
[3] = {5, 10, 20};
160 vector
<HistogramBase::Sample
> ranges_vec
=
161 CustomHistogram::ArrayToCustomRanges(ranges
, 3);
162 ASSERT_EQ(6u, ranges_vec
.size());
163 EXPECT_EQ(5, ranges_vec
[0]);
164 EXPECT_EQ(6, ranges_vec
[1]);
165 EXPECT_EQ(10, ranges_vec
[2]);
166 EXPECT_EQ(11, ranges_vec
[3]);
167 EXPECT_EQ(20, ranges_vec
[4]);
168 EXPECT_EQ(21, ranges_vec
[5]);
171 TEST_F(HistogramTest
, CustomHistogramTest
) {
172 // A well prepared custom ranges.
173 vector
<HistogramBase::Sample
> custom_ranges
;
174 custom_ranges
.push_back(1);
175 custom_ranges
.push_back(2);
177 Histogram
* histogram
= static_cast<Histogram
*>(
178 CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges
,
179 HistogramBase::kNoFlags
));
180 const BucketRanges
* ranges
= histogram
->bucket_ranges();
181 ASSERT_EQ(4u, ranges
->size());
182 EXPECT_EQ(0, ranges
->range(0)); // Auto added.
183 EXPECT_EQ(1, ranges
->range(1));
184 EXPECT_EQ(2, ranges
->range(2));
185 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3)); // Auto added.
187 // A unordered custom ranges.
188 custom_ranges
.clear();
189 custom_ranges
.push_back(2);
190 custom_ranges
.push_back(1);
191 histogram
= static_cast<Histogram
*>(
192 CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges
,
193 HistogramBase::kNoFlags
));
194 ranges
= histogram
->bucket_ranges();
195 ASSERT_EQ(4u, ranges
->size());
196 EXPECT_EQ(0, ranges
->range(0));
197 EXPECT_EQ(1, ranges
->range(1));
198 EXPECT_EQ(2, ranges
->range(2));
199 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3));
201 // A custom ranges with duplicated values.
202 custom_ranges
.clear();
203 custom_ranges
.push_back(4);
204 custom_ranges
.push_back(1);
205 custom_ranges
.push_back(4);
206 histogram
= static_cast<Histogram
*>(
207 CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges
,
208 HistogramBase::kNoFlags
));
209 ranges
= histogram
->bucket_ranges();
210 ASSERT_EQ(4u, ranges
->size());
211 EXPECT_EQ(0, ranges
->range(0));
212 EXPECT_EQ(1, ranges
->range(1));
213 EXPECT_EQ(4, ranges
->range(2));
214 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3));
217 TEST_F(HistogramTest
, CustomHistogramWithOnly2Buckets
) {
218 // This test exploits the fact that the CustomHistogram can have 2 buckets,
219 // while the base class Histogram is *supposed* to have at least 3 buckets.
220 // We should probably change the restriction on the base class (or not inherit
223 vector
<HistogramBase::Sample
> custom_ranges
;
224 custom_ranges
.push_back(4);
226 Histogram
* histogram
= static_cast<Histogram
*>(
227 CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges
,
228 HistogramBase::kNoFlags
));
229 const BucketRanges
* ranges
= histogram
->bucket_ranges();
230 ASSERT_EQ(3u, ranges
->size());
231 EXPECT_EQ(0, ranges
->range(0));
232 EXPECT_EQ(4, ranges
->range(1));
233 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(2));
236 // Make sure histogram handles out-of-bounds data gracefully.
237 TEST_F(HistogramTest
, BoundsTest
) {
238 const size_t kBucketCount
= 50;
239 Histogram
* histogram
= static_cast<Histogram
*>(
240 Histogram::FactoryGet("Bounded", 10, 100, kBucketCount
,
241 HistogramBase::kNoFlags
));
243 // Put two samples "out of bounds" above and below.
248 histogram
->Add(10000);
250 // Verify they landed in the underflow, and overflow buckets.
251 scoped_ptr
<SampleVector
> samples
= histogram
->SnapshotSampleVector();
252 EXPECT_EQ(2, samples
->GetCountAtIndex(0));
253 EXPECT_EQ(0, samples
->GetCountAtIndex(1));
254 size_t array_size
= histogram
->bucket_count();
255 EXPECT_EQ(kBucketCount
, array_size
);
256 EXPECT_EQ(0, samples
->GetCountAtIndex(array_size
- 2));
257 EXPECT_EQ(2, samples
->GetCountAtIndex(array_size
- 1));
259 vector
<int> custom_ranges
;
260 custom_ranges
.push_back(10);
261 custom_ranges
.push_back(50);
262 custom_ranges
.push_back(100);
263 Histogram
* test_custom_histogram
= static_cast<Histogram
*>(
264 CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
265 custom_ranges
, HistogramBase::kNoFlags
));
267 // Put two samples "out of bounds" above and below.
268 test_custom_histogram
->Add(5);
269 test_custom_histogram
->Add(-50);
270 test_custom_histogram
->Add(100);
271 test_custom_histogram
->Add(1000);
272 test_custom_histogram
->Add(INT_MAX
);
274 // Verify they landed in the underflow, and overflow buckets.
275 scoped_ptr
<SampleVector
> custom_samples
=
276 test_custom_histogram
->SnapshotSampleVector();
277 EXPECT_EQ(2, custom_samples
->GetCountAtIndex(0));
278 EXPECT_EQ(0, custom_samples
->GetCountAtIndex(1));
279 size_t bucket_count
= test_custom_histogram
->bucket_count();
280 EXPECT_EQ(0, custom_samples
->GetCountAtIndex(bucket_count
- 2));
281 EXPECT_EQ(3, custom_samples
->GetCountAtIndex(bucket_count
- 1));
284 // Check to be sure samples land as expected is "correct" buckets.
285 TEST_F(HistogramTest
, BucketPlacementTest
) {
286 Histogram
* histogram
= static_cast<Histogram
*>(
287 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
289 // Add i+1 samples to the i'th bucket.
292 for (int i
= 1; i
< 8; i
++) {
293 for (int j
= 0; j
<= i
; j
++)
294 histogram
->Add(power_of_2
);
298 // Check to see that the bucket counts reflect our additions.
299 scoped_ptr
<SampleVector
> samples
= histogram
->SnapshotSampleVector();
300 for (int i
= 0; i
< 8; i
++)
301 EXPECT_EQ(i
+ 1, samples
->GetCountAtIndex(i
));
304 TEST_F(HistogramTest
, CorruptSampleCounts
) {
305 Histogram
* histogram
= static_cast<Histogram
*>(
306 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
312 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
313 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
314 histogram
->FindCorruption(*snapshot
));
315 EXPECT_EQ(2, snapshot
->redundant_count());
316 EXPECT_EQ(2, snapshot
->TotalCount());
318 snapshot
->counts_
[3] += 100; // Sample count won't match redundant count.
319 EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR
,
320 histogram
->FindCorruption(*snapshot
));
321 snapshot
->counts_
[2] -= 200;
322 EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR
,
323 histogram
->FindCorruption(*snapshot
));
325 // But we can't spot a corruption if it is compensated for.
326 snapshot
->counts_
[1] += 100;
327 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
328 histogram
->FindCorruption(*snapshot
));
331 TEST_F(HistogramTest
, CorruptBucketBounds
) {
332 Histogram
* histogram
= static_cast<Histogram
*>(
333 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
335 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
336 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
337 histogram
->FindCorruption(*snapshot
));
339 BucketRanges
* bucket_ranges
=
340 const_cast<BucketRanges
*>(histogram
->bucket_ranges());
341 HistogramBase::Sample tmp
= bucket_ranges
->range(1);
342 bucket_ranges
->set_range(1, bucket_ranges
->range(2));
343 bucket_ranges
->set_range(2, tmp
);
345 HistogramBase::BUCKET_ORDER_ERROR
| HistogramBase::RANGE_CHECKSUM_ERROR
,
346 histogram
->FindCorruption(*snapshot
));
348 bucket_ranges
->set_range(2, bucket_ranges
->range(1));
349 bucket_ranges
->set_range(1, tmp
);
350 EXPECT_EQ(0, histogram
->FindCorruption(*snapshot
));
352 // Show that two simple changes don't offset each other
353 bucket_ranges
->set_range(3, bucket_ranges
->range(3) + 1);
354 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR
,
355 histogram
->FindCorruption(*snapshot
));
357 bucket_ranges
->set_range(4, bucket_ranges
->range(4) - 1);
358 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR
,
359 histogram
->FindCorruption(*snapshot
));
361 // Repair histogram so that destructor won't DCHECK().
362 bucket_ranges
->set_range(3, bucket_ranges
->range(3) - 1);
363 bucket_ranges
->set_range(4, bucket_ranges
->range(4) + 1);
366 TEST_F(HistogramTest
, HistogramSerializeInfo
) {
367 Histogram
* histogram
= static_cast<Histogram
*>(
368 Histogram::FactoryGet("Histogram", 1, 64, 8,
369 HistogramBase::kIPCSerializationSourceFlag
));
371 histogram
->SerializeInfo(&pickle
);
373 PickleIterator
iter(pickle
);
376 EXPECT_TRUE(iter
.ReadInt(&type
));
377 EXPECT_EQ(HISTOGRAM
, type
);
380 EXPECT_TRUE(iter
.ReadString(&name
));
381 EXPECT_EQ("Histogram", name
);
384 EXPECT_TRUE(iter
.ReadInt(&flag
));
385 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag
, flag
);
388 EXPECT_TRUE(iter
.ReadInt(&min
));
392 EXPECT_TRUE(iter
.ReadInt(&max
));
396 EXPECT_TRUE(iter
.ReadInt64(&bucket_count
));
397 EXPECT_EQ(8, bucket_count
);
400 EXPECT_TRUE(iter
.ReadUInt32(&checksum
));
401 EXPECT_EQ(histogram
->bucket_ranges()->checksum(), checksum
);
403 // No more data in the pickle.
404 EXPECT_FALSE(iter
.SkipBytes(1));
407 TEST_F(HistogramTest
, CustomHistogramSerializeInfo
) {
408 vector
<int> custom_ranges
;
409 custom_ranges
.push_back(10);
410 custom_ranges
.push_back(100);
412 HistogramBase
* custom_histogram
= CustomHistogram::FactoryGet(
413 "TestCustomRangeBoundedHistogram",
415 HistogramBase::kNoFlags
);
417 custom_histogram
->SerializeInfo(&pickle
);
419 // Validate the pickle.
420 PickleIterator
iter(pickle
);
426 EXPECT_TRUE(iter
.ReadInt(&i
) && iter
.ReadString(&s
) && iter
.ReadInt(&i
) &&
427 iter
.ReadInt(&i
) && iter
.ReadInt(&i
) &&
428 iter
.ReadInt64(&bucket_count
) && iter
.ReadUInt32(&ui32
));
429 EXPECT_EQ(3, bucket_count
);
432 EXPECT_TRUE(iter
.ReadInt(&range
));
433 EXPECT_EQ(10, range
);
434 EXPECT_TRUE(iter
.ReadInt(&range
));
435 EXPECT_EQ(100, range
);
437 // No more data in the pickle.
438 EXPECT_FALSE(iter
.SkipBytes(1));
441 TEST_F(HistogramTest
, BadConstruction
) {
442 HistogramBase
* histogram
= Histogram::FactoryGet(
443 "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags
);
444 EXPECT_TRUE(histogram
->HasConstructionArguments(1, 100, 8));
446 // Try to get the same histogram name with different arguments.
447 HistogramBase
* bad_histogram
= Histogram::FactoryGet(
448 "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags
);
449 EXPECT_EQ(NULL
, bad_histogram
);
450 bad_histogram
= Histogram::FactoryGet(
451 "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags
);
452 EXPECT_EQ(NULL
, bad_histogram
);
454 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
455 "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags
);
456 EXPECT_TRUE(linear_histogram
->HasConstructionArguments(1, 100, 8));
458 // Try to get the same histogram name with different arguments.
459 bad_histogram
= LinearHistogram::FactoryGet(
460 "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags
);
461 EXPECT_EQ(NULL
, bad_histogram
);
462 bad_histogram
= LinearHistogram::FactoryGet(
463 "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags
);
464 EXPECT_EQ(NULL
, bad_histogram
);
467 #if GTEST_HAS_DEATH_TEST
468 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a
469 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
470 // 1). But we accept ranges exceeding those limits, and silently clamped to
471 // those limits. This is for backwards compatibility.
472 TEST(HistogramDeathTest
, BadRangesTest
) {
473 HistogramBase
* histogram
= Histogram::FactoryGet(
474 "BadRanges", 0, HistogramBase::kSampleType_MAX
, 8,
475 HistogramBase::kNoFlags
);
477 histogram
->HasConstructionArguments(
478 1, HistogramBase::kSampleType_MAX
- 1, 8));
480 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
481 "BadRangesLinear", 0, HistogramBase::kSampleType_MAX
, 8,
482 HistogramBase::kNoFlags
);
484 linear_histogram
->HasConstructionArguments(
485 1, HistogramBase::kSampleType_MAX
- 1, 8));
487 vector
<int> custom_ranges
;
488 custom_ranges
.push_back(0);
489 custom_ranges
.push_back(5);
490 Histogram
* custom_histogram
= static_cast<Histogram
*>(
491 CustomHistogram::FactoryGet(
492 "BadRangesCustom", custom_ranges
, HistogramBase::kNoFlags
));
493 const BucketRanges
* ranges
= custom_histogram
->bucket_ranges();
494 ASSERT_EQ(3u, ranges
->size());
495 EXPECT_EQ(0, ranges
->range(0));
496 EXPECT_EQ(5, ranges
->range(1));
497 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(2));
499 // CustomHistogram does not accepts kSampleType_MAX as range.
500 custom_ranges
.push_back(HistogramBase::kSampleType_MAX
);
501 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges
,
502 HistogramBase::kNoFlags
),
505 // CustomHistogram needs at least 1 valid range.
506 custom_ranges
.clear();
507 custom_ranges
.push_back(0);
508 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges
,
509 HistogramBase::kNoFlags
),