Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / base / metrics / histogram_unittest.cc
blobdf43e65fdef27841af2de2cdeec4bc755c5607cd
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
7 #include <climits>
8 #include <algorithm>
9 #include <vector>
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"
21 using std::vector;
23 namespace base {
25 class HistogramTest : public testing::Test {
26 protected:
27 void SetUp() override {
28 // Each test will have a clean state (no Histogram / BucketRanges
29 // registered).
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
73 // data together.
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));
90 int power_of_2 = 1;
91 for (int i = 1; i < 8; i++) {
92 EXPECT_EQ(power_of_2, ranges.range(i));
93 power_of_2 *= 2;
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
103 // linear.
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
221 // the base class!).
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.
244 histogram->Add(5);
245 histogram->Add(-50);
247 histogram->Add(100);
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.
290 histogram->Add(0);
291 int power_of_2 = 1;
292 for (int i = 1; i < 8; i++) {
293 for (int j = 0; j <= i; j++)
294 histogram->Add(power_of_2);
295 power_of_2 *= 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));
308 // Add some samples.
309 histogram->Add(20);
310 histogram->Add(40);
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);
344 EXPECT_EQ(
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));
370 Pickle pickle;
371 histogram->SerializeInfo(&pickle);
373 PickleIterator iter(pickle);
375 int type;
376 EXPECT_TRUE(iter.ReadInt(&type));
377 EXPECT_EQ(HISTOGRAM, type);
379 std::string name;
380 EXPECT_TRUE(iter.ReadString(&name));
381 EXPECT_EQ("Histogram", name);
383 int flag;
384 EXPECT_TRUE(iter.ReadInt(&flag));
385 EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
387 int min;
388 EXPECT_TRUE(iter.ReadInt(&min));
389 EXPECT_EQ(1, min);
391 int max;
392 EXPECT_TRUE(iter.ReadInt(&max));
393 EXPECT_EQ(64, max);
395 int64 bucket_count;
396 EXPECT_TRUE(iter.ReadInt64(&bucket_count));
397 EXPECT_EQ(8, bucket_count);
399 uint32 checksum;
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",
414 custom_ranges,
415 HistogramBase::kNoFlags);
416 Pickle pickle;
417 custom_histogram->SerializeInfo(&pickle);
419 // Validate the pickle.
420 PickleIterator iter(pickle);
422 int i;
423 std::string s;
424 int64 bucket_count;
425 uint32 ui32;
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);
431 int range;
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);
476 EXPECT_TRUE(
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);
483 EXPECT_TRUE(
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),
503 "");
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),
510 "");
512 #endif
514 } // namespace base