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