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 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 LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
69 LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
71 LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
74 // Check that the macro correctly matches histograms by name and records their
76 TEST_F(HistogramTest
, NameMatchTest
) {
77 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
78 LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
79 HistogramBase
* histogram
= LinearHistogram::FactoryGet(
80 "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags
);
82 scoped_ptr
<HistogramSamples
> samples
= histogram
->SnapshotSamples();
83 EXPECT_EQ(2, samples
->TotalCount());
84 EXPECT_EQ(2, samples
->GetCount(10));
87 TEST_F(HistogramTest
, ExponentialRangesTest
) {
88 // Check that we got a nice exponential when there was enough rooom.
89 BucketRanges
ranges(9);
90 Histogram::InitializeBucketRanges(1, 64, &ranges
);
91 EXPECT_EQ(0, ranges
.range(0));
93 for (int i
= 1; i
< 8; i
++) {
94 EXPECT_EQ(power_of_2
, ranges
.range(i
));
97 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
.range(8));
99 // Check the corresponding Histogram will use the correct ranges.
100 Histogram
* histogram
= static_cast<Histogram
*>(
101 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
102 EXPECT_TRUE(ranges
.Equals(histogram
->bucket_ranges()));
104 // When bucket count is limited, exponential ranges will partially look like
106 BucketRanges
ranges2(16);
107 Histogram::InitializeBucketRanges(1, 32, &ranges2
);
109 EXPECT_EQ(0, ranges2
.range(0));
110 EXPECT_EQ(1, ranges2
.range(1));
111 EXPECT_EQ(2, ranges2
.range(2));
112 EXPECT_EQ(3, ranges2
.range(3));
113 EXPECT_EQ(4, ranges2
.range(4));
114 EXPECT_EQ(5, ranges2
.range(5));
115 EXPECT_EQ(6, ranges2
.range(6));
116 EXPECT_EQ(7, ranges2
.range(7));
117 EXPECT_EQ(9, ranges2
.range(8));
118 EXPECT_EQ(11, ranges2
.range(9));
119 EXPECT_EQ(14, ranges2
.range(10));
120 EXPECT_EQ(17, ranges2
.range(11));
121 EXPECT_EQ(21, ranges2
.range(12));
122 EXPECT_EQ(26, ranges2
.range(13));
123 EXPECT_EQ(32, ranges2
.range(14));
124 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges2
.range(15));
126 // Check the corresponding Histogram will use the correct ranges.
127 Histogram
* histogram2
= static_cast<Histogram
*>(
128 Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags
));
129 EXPECT_TRUE(ranges2
.Equals(histogram2
->bucket_ranges()));
132 TEST_F(HistogramTest
, LinearRangesTest
) {
133 BucketRanges
ranges(9);
134 LinearHistogram::InitializeBucketRanges(1, 7, &ranges
);
135 // Gets a nice linear set of bucket ranges.
136 for (int i
= 0; i
< 8; i
++)
137 EXPECT_EQ(i
, ranges
.range(i
));
138 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
.range(8));
140 // The correspoding LinearHistogram should use the correct ranges.
141 Histogram
* histogram
= static_cast<Histogram
*>(
142 LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags
));
143 EXPECT_TRUE(ranges
.Equals(histogram
->bucket_ranges()));
145 // Linear ranges are not divisible.
146 BucketRanges
ranges2(6);
147 LinearHistogram::InitializeBucketRanges(1, 6, &ranges2
);
148 EXPECT_EQ(0, ranges2
.range(0));
149 EXPECT_EQ(1, ranges2
.range(1));
150 EXPECT_EQ(3, ranges2
.range(2));
151 EXPECT_EQ(4, ranges2
.range(3));
152 EXPECT_EQ(6, ranges2
.range(4));
153 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges2
.range(5));
154 // The correspoding LinearHistogram should use the correct ranges.
155 Histogram
* histogram2
= static_cast<Histogram
*>(
156 LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags
));
157 EXPECT_TRUE(ranges2
.Equals(histogram2
->bucket_ranges()));
160 TEST_F(HistogramTest
, ArrayToCustomRangesTest
) {
161 const HistogramBase::Sample ranges
[3] = {5, 10, 20};
162 vector
<HistogramBase::Sample
> ranges_vec
=
163 CustomHistogram::ArrayToCustomRanges(ranges
, 3);
164 ASSERT_EQ(6u, ranges_vec
.size());
165 EXPECT_EQ(5, ranges_vec
[0]);
166 EXPECT_EQ(6, ranges_vec
[1]);
167 EXPECT_EQ(10, ranges_vec
[2]);
168 EXPECT_EQ(11, ranges_vec
[3]);
169 EXPECT_EQ(20, ranges_vec
[4]);
170 EXPECT_EQ(21, ranges_vec
[5]);
173 TEST_F(HistogramTest
, CustomHistogramTest
) {
174 // A well prepared custom ranges.
175 vector
<HistogramBase::Sample
> custom_ranges
;
176 custom_ranges
.push_back(1);
177 custom_ranges
.push_back(2);
179 Histogram
* histogram
= static_cast<Histogram
*>(
180 CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges
,
181 HistogramBase::kNoFlags
));
182 const BucketRanges
* ranges
= histogram
->bucket_ranges();
183 ASSERT_EQ(4u, ranges
->size());
184 EXPECT_EQ(0, ranges
->range(0)); // Auto added.
185 EXPECT_EQ(1, ranges
->range(1));
186 EXPECT_EQ(2, ranges
->range(2));
187 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3)); // Auto added.
189 // A unordered custom ranges.
190 custom_ranges
.clear();
191 custom_ranges
.push_back(2);
192 custom_ranges
.push_back(1);
193 histogram
= static_cast<Histogram
*>(
194 CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges
,
195 HistogramBase::kNoFlags
));
196 ranges
= histogram
->bucket_ranges();
197 ASSERT_EQ(4u, ranges
->size());
198 EXPECT_EQ(0, ranges
->range(0));
199 EXPECT_EQ(1, ranges
->range(1));
200 EXPECT_EQ(2, ranges
->range(2));
201 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3));
203 // A custom ranges with duplicated values.
204 custom_ranges
.clear();
205 custom_ranges
.push_back(4);
206 custom_ranges
.push_back(1);
207 custom_ranges
.push_back(4);
208 histogram
= static_cast<Histogram
*>(
209 CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges
,
210 HistogramBase::kNoFlags
));
211 ranges
= histogram
->bucket_ranges();
212 ASSERT_EQ(4u, ranges
->size());
213 EXPECT_EQ(0, ranges
->range(0));
214 EXPECT_EQ(1, ranges
->range(1));
215 EXPECT_EQ(4, ranges
->range(2));
216 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(3));
219 TEST_F(HistogramTest
, CustomHistogramWithOnly2Buckets
) {
220 // This test exploits the fact that the CustomHistogram can have 2 buckets,
221 // while the base class Histogram is *supposed* to have at least 3 buckets.
222 // We should probably change the restriction on the base class (or not inherit
225 vector
<HistogramBase::Sample
> custom_ranges
;
226 custom_ranges
.push_back(4);
228 Histogram
* histogram
= static_cast<Histogram
*>(
229 CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges
,
230 HistogramBase::kNoFlags
));
231 const BucketRanges
* ranges
= histogram
->bucket_ranges();
232 ASSERT_EQ(3u, ranges
->size());
233 EXPECT_EQ(0, ranges
->range(0));
234 EXPECT_EQ(4, ranges
->range(1));
235 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(2));
238 // Make sure histogram handles out-of-bounds data gracefully.
239 TEST_F(HistogramTest
, BoundsTest
) {
240 const size_t kBucketCount
= 50;
241 Histogram
* histogram
= static_cast<Histogram
*>(
242 Histogram::FactoryGet("Bounded", 10, 100, kBucketCount
,
243 HistogramBase::kNoFlags
));
245 // Put two samples "out of bounds" above and below.
250 histogram
->Add(10000);
252 // Verify they landed in the underflow, and overflow buckets.
253 scoped_ptr
<SampleVector
> samples
= histogram
->SnapshotSampleVector();
254 EXPECT_EQ(2, samples
->GetCountAtIndex(0));
255 EXPECT_EQ(0, samples
->GetCountAtIndex(1));
256 size_t array_size
= histogram
->bucket_count();
257 EXPECT_EQ(kBucketCount
, array_size
);
258 EXPECT_EQ(0, samples
->GetCountAtIndex(array_size
- 2));
259 EXPECT_EQ(2, samples
->GetCountAtIndex(array_size
- 1));
261 vector
<int> custom_ranges
;
262 custom_ranges
.push_back(10);
263 custom_ranges
.push_back(50);
264 custom_ranges
.push_back(100);
265 Histogram
* test_custom_histogram
= static_cast<Histogram
*>(
266 CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
267 custom_ranges
, HistogramBase::kNoFlags
));
269 // Put two samples "out of bounds" above and below.
270 test_custom_histogram
->Add(5);
271 test_custom_histogram
->Add(-50);
272 test_custom_histogram
->Add(100);
273 test_custom_histogram
->Add(1000);
274 test_custom_histogram
->Add(INT_MAX
);
276 // Verify they landed in the underflow, and overflow buckets.
277 scoped_ptr
<SampleVector
> custom_samples
=
278 test_custom_histogram
->SnapshotSampleVector();
279 EXPECT_EQ(2, custom_samples
->GetCountAtIndex(0));
280 EXPECT_EQ(0, custom_samples
->GetCountAtIndex(1));
281 size_t bucket_count
= test_custom_histogram
->bucket_count();
282 EXPECT_EQ(0, custom_samples
->GetCountAtIndex(bucket_count
- 2));
283 EXPECT_EQ(3, custom_samples
->GetCountAtIndex(bucket_count
- 1));
286 // Check to be sure samples land as expected is "correct" buckets.
287 TEST_F(HistogramTest
, BucketPlacementTest
) {
288 Histogram
* histogram
= static_cast<Histogram
*>(
289 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
291 // Add i+1 samples to the i'th bucket.
294 for (int i
= 1; i
< 8; i
++) {
295 for (int j
= 0; j
<= i
; j
++)
296 histogram
->Add(power_of_2
);
300 // Check to see that the bucket counts reflect our additions.
301 scoped_ptr
<SampleVector
> samples
= histogram
->SnapshotSampleVector();
302 for (int i
= 0; i
< 8; i
++)
303 EXPECT_EQ(i
+ 1, samples
->GetCountAtIndex(i
));
306 TEST_F(HistogramTest
, CorruptSampleCounts
) {
307 Histogram
* histogram
= static_cast<Histogram
*>(
308 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
314 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
315 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
316 histogram
->FindCorruption(*snapshot
));
317 EXPECT_EQ(2, snapshot
->redundant_count());
318 EXPECT_EQ(2, snapshot
->TotalCount());
320 snapshot
->counts_
[3] += 100; // Sample count won't match redundant count.
321 EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR
,
322 histogram
->FindCorruption(*snapshot
));
323 snapshot
->counts_
[2] -= 200;
324 EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR
,
325 histogram
->FindCorruption(*snapshot
));
327 // But we can't spot a corruption if it is compensated for.
328 snapshot
->counts_
[1] += 100;
329 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
330 histogram
->FindCorruption(*snapshot
));
333 TEST_F(HistogramTest
, CorruptBucketBounds
) {
334 Histogram
* histogram
= static_cast<Histogram
*>(
335 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags
));
337 scoped_ptr
<SampleVector
> snapshot
= histogram
->SnapshotSampleVector();
338 EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES
,
339 histogram
->FindCorruption(*snapshot
));
341 BucketRanges
* bucket_ranges
=
342 const_cast<BucketRanges
*>(histogram
->bucket_ranges());
343 HistogramBase::Sample tmp
= bucket_ranges
->range(1);
344 bucket_ranges
->set_range(1, bucket_ranges
->range(2));
345 bucket_ranges
->set_range(2, tmp
);
347 HistogramBase::BUCKET_ORDER_ERROR
| HistogramBase::RANGE_CHECKSUM_ERROR
,
348 histogram
->FindCorruption(*snapshot
));
350 bucket_ranges
->set_range(2, bucket_ranges
->range(1));
351 bucket_ranges
->set_range(1, tmp
);
352 EXPECT_EQ(0, histogram
->FindCorruption(*snapshot
));
354 // Show that two simple changes don't offset each other
355 bucket_ranges
->set_range(3, bucket_ranges
->range(3) + 1);
356 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR
,
357 histogram
->FindCorruption(*snapshot
));
359 bucket_ranges
->set_range(4, bucket_ranges
->range(4) - 1);
360 EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR
,
361 histogram
->FindCorruption(*snapshot
));
363 // Repair histogram so that destructor won't DCHECK().
364 bucket_ranges
->set_range(3, bucket_ranges
->range(3) - 1);
365 bucket_ranges
->set_range(4, bucket_ranges
->range(4) + 1);
368 TEST_F(HistogramTest
, HistogramSerializeInfo
) {
369 Histogram
* histogram
= static_cast<Histogram
*>(
370 Histogram::FactoryGet("Histogram", 1, 64, 8,
371 HistogramBase::kIPCSerializationSourceFlag
));
373 histogram
->SerializeInfo(&pickle
);
375 PickleIterator
iter(pickle
);
378 EXPECT_TRUE(iter
.ReadInt(&type
));
379 EXPECT_EQ(HISTOGRAM
, type
);
382 EXPECT_TRUE(iter
.ReadString(&name
));
383 EXPECT_EQ("Histogram", name
);
386 EXPECT_TRUE(iter
.ReadInt(&flag
));
387 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag
, flag
);
390 EXPECT_TRUE(iter
.ReadInt(&min
));
394 EXPECT_TRUE(iter
.ReadInt(&max
));
398 EXPECT_TRUE(iter
.ReadInt64(&bucket_count
));
399 EXPECT_EQ(8, bucket_count
);
402 EXPECT_TRUE(iter
.ReadUInt32(&checksum
));
403 EXPECT_EQ(histogram
->bucket_ranges()->checksum(), checksum
);
405 // No more data in the pickle.
406 EXPECT_FALSE(iter
.SkipBytes(1));
409 TEST_F(HistogramTest
, CustomHistogramSerializeInfo
) {
410 vector
<int> custom_ranges
;
411 custom_ranges
.push_back(10);
412 custom_ranges
.push_back(100);
414 HistogramBase
* custom_histogram
= CustomHistogram::FactoryGet(
415 "TestCustomRangeBoundedHistogram",
417 HistogramBase::kNoFlags
);
419 custom_histogram
->SerializeInfo(&pickle
);
421 // Validate the pickle.
422 PickleIterator
iter(pickle
);
428 EXPECT_TRUE(iter
.ReadInt(&i
) && iter
.ReadString(&s
) && iter
.ReadInt(&i
) &&
429 iter
.ReadInt(&i
) && iter
.ReadInt(&i
) &&
430 iter
.ReadInt64(&bucket_count
) && iter
.ReadUInt32(&ui32
));
431 EXPECT_EQ(3, bucket_count
);
434 EXPECT_TRUE(iter
.ReadInt(&range
));
435 EXPECT_EQ(10, range
);
436 EXPECT_TRUE(iter
.ReadInt(&range
));
437 EXPECT_EQ(100, range
);
439 // No more data in the pickle.
440 EXPECT_FALSE(iter
.SkipBytes(1));
443 TEST_F(HistogramTest
, BadConstruction
) {
444 HistogramBase
* histogram
= Histogram::FactoryGet(
445 "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags
);
446 EXPECT_TRUE(histogram
->HasConstructionArguments(1, 100, 8));
448 // Try to get the same histogram name with different arguments.
449 HistogramBase
* bad_histogram
= Histogram::FactoryGet(
450 "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags
);
451 EXPECT_EQ(NULL
, bad_histogram
);
452 bad_histogram
= Histogram::FactoryGet(
453 "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags
);
454 EXPECT_EQ(NULL
, bad_histogram
);
456 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
457 "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags
);
458 EXPECT_TRUE(linear_histogram
->HasConstructionArguments(1, 100, 8));
460 // Try to get the same histogram name with different arguments.
461 bad_histogram
= LinearHistogram::FactoryGet(
462 "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags
);
463 EXPECT_EQ(NULL
, bad_histogram
);
464 bad_histogram
= LinearHistogram::FactoryGet(
465 "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags
);
466 EXPECT_EQ(NULL
, bad_histogram
);
469 #if GTEST_HAS_DEATH_TEST
470 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a
471 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
472 // 1). But we accept ranges exceeding those limits, and silently clamped to
473 // those limits. This is for backwards compatibility.
474 TEST(HistogramDeathTest
, BadRangesTest
) {
475 HistogramBase
* histogram
= Histogram::FactoryGet(
476 "BadRanges", 0, HistogramBase::kSampleType_MAX
, 8,
477 HistogramBase::kNoFlags
);
479 histogram
->HasConstructionArguments(
480 1, HistogramBase::kSampleType_MAX
- 1, 8));
482 HistogramBase
* linear_histogram
= LinearHistogram::FactoryGet(
483 "BadRangesLinear", 0, HistogramBase::kSampleType_MAX
, 8,
484 HistogramBase::kNoFlags
);
486 linear_histogram
->HasConstructionArguments(
487 1, HistogramBase::kSampleType_MAX
- 1, 8));
489 vector
<int> custom_ranges
;
490 custom_ranges
.push_back(0);
491 custom_ranges
.push_back(5);
492 Histogram
* custom_histogram
= static_cast<Histogram
*>(
493 CustomHistogram::FactoryGet(
494 "BadRangesCustom", custom_ranges
, HistogramBase::kNoFlags
));
495 const BucketRanges
* ranges
= custom_histogram
->bucket_ranges();
496 ASSERT_EQ(3u, ranges
->size());
497 EXPECT_EQ(0, ranges
->range(0));
498 EXPECT_EQ(5, ranges
->range(1));
499 EXPECT_EQ(HistogramBase::kSampleType_MAX
, ranges
->range(2));
501 // CustomHistogram does not accepts kSampleType_MAX as range.
502 custom_ranges
.push_back(HistogramBase::kSampleType_MAX
);
503 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges
,
504 HistogramBase::kNoFlags
),
507 // CustomHistogram needs at least 1 valid range.
508 custom_ranges
.clear();
509 custom_ranges
.push_back(0);
510 EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges
,
511 HistogramBase::kNoFlags
),