• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 // Test of Histogram class
6 
7 #include <climits>
8 #include <algorithm>
9 #include <vector>
10 
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"
20 
21 using std::vector;
22 
23 namespace base {
24 
25 class HistogramTest : public testing::Test {
26  protected:
SetUp()27   virtual void SetUp() {
28     // Each test will have a clean state (no Histogram / BucketRanges
29     // registered).
30     InitializeStatisticsRecorder();
31   }
32 
TearDown()33   virtual void TearDown() {
34     UninitializeStatisticsRecorder();
35   }
36 
InitializeStatisticsRecorder()37   void InitializeStatisticsRecorder() {
38     statistics_recorder_ = new StatisticsRecorder();
39   }
40 
UninitializeStatisticsRecorder()41   void UninitializeStatisticsRecorder() {
42     delete statistics_recorder_;
43     statistics_recorder_ = NULL;
44   }
45 
46   StatisticsRecorder* statistics_recorder_;
47 };
48 
49 // Check for basic syntax and use.
TEST_F(HistogramTest,BasicTest)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);
55 
56   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
57       "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
58   EXPECT_TRUE(linear_histogram);
59 
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);
66 
67   // Use standard macros (but with fixed samples)
68   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
69   HISTOGRAM_COUNTS("Test3Histogram", 30);
70 
71   DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
72   DHISTOGRAM_COUNTS("Test5Histogram", 30);
73 
74   HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
75 }
76 
77 // Check that the macro correctly matches histograms by name and records their
78 // data together.
TEST_F(HistogramTest,NameMatchTest)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);
84 
85   scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
86   EXPECT_EQ(2, samples->TotalCount());
87   EXPECT_EQ(2, samples->GetCount(10));
88 }
89 
TEST_F(HistogramTest,ExponentialRangesTest)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, &ranges);
94   EXPECT_EQ(0, ranges.range(0));
95   int power_of_2 = 1;
96   for (int i = 1; i < 8; i++) {
97     EXPECT_EQ(power_of_2, ranges.range(i));
98     power_of_2 *= 2;
99   }
100   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
101 
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()));
106 
107   // When bucket count is limited, exponential ranges will partially look like
108   // linear.
109   BucketRanges ranges2(16);
110   Histogram::InitializeBucketRanges(1, 32, &ranges2);
111 
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));
128 
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()));
133 }
134 
TEST_F(HistogramTest,LinearRangesTest)135 TEST_F(HistogramTest, LinearRangesTest) {
136   BucketRanges ranges(9);
137   LinearHistogram::InitializeBucketRanges(1, 7, &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));
142 
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()));
147 
148   // Linear ranges are not divisible.
149   BucketRanges ranges2(6);
150   LinearHistogram::InitializeBucketRanges(1, 6, &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()));
161 }
162 
TEST_F(HistogramTest,ArrayToCustomRangesTest)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]);
174 }
175 
TEST_F(HistogramTest,CustomHistogramTest)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);
181 
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.
191 
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));
205 
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));
220 }
221 
TEST_F(HistogramTest,CustomHistogramWithOnly2Buckets)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
226   // the base class!).
227 
228   vector<HistogramBase::Sample> custom_ranges;
229   custom_ranges.push_back(4);
230 
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));
239 }
240 
241 // Make sure histogram handles out-of-bounds data gracefully.
TEST_F(HistogramTest,BoundsTest)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));
247 
248   // Put two samples "out of bounds" above and below.
249   histogram->Add(5);
250   histogram->Add(-50);
251 
252   histogram->Add(100);
253   histogram->Add(10000);
254 
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));
263 
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));
271 
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);
278 
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));
287 }
288 
289 // Check to be sure samples land as expected is "correct" buckets.
TEST_F(HistogramTest,BucketPlacementTest)290 TEST_F(HistogramTest, BucketPlacementTest) {
291   Histogram* histogram = static_cast<Histogram*>(
292       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
293 
294   // Add i+1 samples to the i'th bucket.
295   histogram->Add(0);
296   int power_of_2 = 1;
297   for (int i = 1; i < 8; i++) {
298     for (int j = 0; j <= i; j++)
299       histogram->Add(power_of_2);
300     power_of_2 *= 2;
301   }
302 
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));
307 }
308 
TEST_F(HistogramTest,CorruptSampleCounts)309 TEST_F(HistogramTest, CorruptSampleCounts) {
310   Histogram* histogram = static_cast<Histogram*>(
311       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
312 
313   // Add some samples.
314   histogram->Add(20);
315   histogram->Add(40);
316 
317   scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
318   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
319             histogram->FindCorruption(*snapshot));
320   EXPECT_EQ(2, snapshot->redundant_count());
321   EXPECT_EQ(2, snapshot->TotalCount());
322 
323   snapshot->counts_[3] += 100;  // Sample count won't match redundant count.
324   EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR,
325             histogram->FindCorruption(*snapshot));
326   snapshot->counts_[2] -= 200;
327   EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR,
328             histogram->FindCorruption(*snapshot));
329 
330   // But we can't spot a corruption if it is compensated for.
331   snapshot->counts_[1] += 100;
332   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
333             histogram->FindCorruption(*snapshot));
334 }
335 
TEST_F(HistogramTest,CorruptBucketBounds)336 TEST_F(HistogramTest, CorruptBucketBounds) {
337   Histogram* histogram = static_cast<Histogram*>(
338       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
339 
340   scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
341   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
342             histogram->FindCorruption(*snapshot));
343 
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(
350       HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR,
351       histogram->FindCorruption(*snapshot));
352 
353   bucket_ranges->set_range(2, bucket_ranges->range(1));
354   bucket_ranges->set_range(1, tmp);
355   EXPECT_EQ(0, histogram->FindCorruption(*snapshot));
356 
357   // Show that two simple changes don't offset each other
358   bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
359   EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
360             histogram->FindCorruption(*snapshot));
361 
362   bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
363   EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
364             histogram->FindCorruption(*snapshot));
365 
366   // Repair histogram so that destructor won't DCHECK().
367   bucket_ranges->set_range(3, bucket_ranges->range(3) - 1);
368   bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
369 }
370 
TEST_F(HistogramTest,HistogramSerializeInfo)371 TEST_F(HistogramTest, HistogramSerializeInfo) {
372   Histogram* histogram = static_cast<Histogram*>(
373       Histogram::FactoryGet("Histogram", 1, 64, 8,
374                             HistogramBase::kIPCSerializationSourceFlag));
375   Pickle pickle;
376   histogram->SerializeInfo(&pickle);
377 
378   PickleIterator iter(pickle);
379 
380   int type;
381   EXPECT_TRUE(iter.ReadInt(&type));
382   EXPECT_EQ(HISTOGRAM, type);
383 
384   std::string name;
385   EXPECT_TRUE(iter.ReadString(&name));
386   EXPECT_EQ("Histogram", name);
387 
388   int flag;
389   EXPECT_TRUE(iter.ReadInt(&flag));
390   EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
391 
392   int min;
393   EXPECT_TRUE(iter.ReadInt(&min));
394   EXPECT_EQ(1, min);
395 
396   int max;
397   EXPECT_TRUE(iter.ReadInt(&max));
398   EXPECT_EQ(64, max);
399 
400   int64 bucket_count;
401   EXPECT_TRUE(iter.ReadInt64(&bucket_count));
402   EXPECT_EQ(8, bucket_count);
403 
404   uint32 checksum;
405   EXPECT_TRUE(iter.ReadUInt32(&checksum));
406   EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
407 
408   // No more data in the pickle.
409   EXPECT_FALSE(iter.SkipBytes(1));
410 }
411 
TEST_F(HistogramTest,CustomHistogramSerializeInfo)412 TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
413   vector<int> custom_ranges;
414   custom_ranges.push_back(10);
415   custom_ranges.push_back(100);
416 
417   HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
418       "TestCustomRangeBoundedHistogram",
419       custom_ranges,
420       HistogramBase::kNoFlags);
421   Pickle pickle;
422   custom_histogram->SerializeInfo(&pickle);
423 
424   // Validate the pickle.
425   PickleIterator iter(pickle);
426 
427   int i;
428   std::string s;
429   int64 bucket_count;
430   uint32 ui32;
431   EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
432               iter.ReadInt(&i) && iter.ReadInt(&i) &&
433               iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
434   EXPECT_EQ(3, bucket_count);
435 
436   int range;
437   EXPECT_TRUE(iter.ReadInt(&range));
438   EXPECT_EQ(10, range);
439   EXPECT_TRUE(iter.ReadInt(&range));
440   EXPECT_EQ(100, range);
441 
442   // No more data in the pickle.
443   EXPECT_FALSE(iter.SkipBytes(1));
444 }
445 
446 #if GTEST_HAS_DEATH_TEST
447 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a
448 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
449 // 1). But we accept ranges exceeding those limits, and silently clamped to
450 // those limits. This is for backwards compatibility.
TEST(HistogramDeathTest,BadRangesTest)451 TEST(HistogramDeathTest, BadRangesTest) {
452   HistogramBase* histogram = Histogram::FactoryGet(
453       "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
454       HistogramBase::kNoFlags);
455   EXPECT_TRUE(
456       histogram->HasConstructionArguments(
457           1, HistogramBase::kSampleType_MAX - 1, 8));
458 
459   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
460       "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
461       HistogramBase::kNoFlags);
462   EXPECT_TRUE(
463       linear_histogram->HasConstructionArguments(
464           1, HistogramBase::kSampleType_MAX - 1, 8));
465 
466   vector<int> custom_ranges;
467   custom_ranges.push_back(0);
468   custom_ranges.push_back(5);
469   Histogram* custom_histogram = static_cast<Histogram*>(
470       CustomHistogram::FactoryGet(
471           "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags));
472   const BucketRanges* ranges = custom_histogram->bucket_ranges();
473   ASSERT_EQ(3u, ranges->size());
474   EXPECT_EQ(0, ranges->range(0));
475   EXPECT_EQ(5, ranges->range(1));
476   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
477 
478   // CustomHistogram does not accepts kSampleType_MAX as range.
479   custom_ranges.push_back(HistogramBase::kSampleType_MAX);
480   EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
481                                            HistogramBase::kNoFlags),
482                "");
483 
484   // CustomHistogram needs at least 1 valid range.
485   custom_ranges.clear();
486   custom_ranges.push_back(0);
487   EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
488                                            HistogramBase::kNoFlags),
489                "");
490 }
491 #endif
492 
493 }  // namespace base
494