• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/metrics/histogram.h"
8 #include "base/scoped_ptr.h"
9 #include "base/time.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace base {
13 namespace {
14 
15 class HistogramTest : public testing::Test {
16 };
17 
18 // Check for basic syntax and use.
TEST(HistogramTest,StartupShutdownTest)19 TEST(HistogramTest, StartupShutdownTest) {
20   // Try basic construction
21   Histogram* histogram(Histogram::FactoryGet(
22       "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
23   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
24   Histogram* histogram1(Histogram::FactoryGet(
25       "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
26   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
27   EXPECT_NE(histogram, histogram1);
28 
29 
30   Histogram* linear_histogram(LinearHistogram::FactoryGet(
31       "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
32   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
33   Histogram* linear_histogram1(LinearHistogram::FactoryGet(
34       "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
35   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
36   EXPECT_NE(linear_histogram, linear_histogram1);
37 
38   std::vector<int> custom_ranges;
39   custom_ranges.push_back(1);
40   custom_ranges.push_back(5);
41   custom_ranges.push_back(10);
42   custom_ranges.push_back(20);
43   custom_ranges.push_back(30);
44   Histogram* custom_histogram(CustomHistogram::FactoryGet(
45       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
46   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
47   Histogram* custom_histogram1(CustomHistogram::FactoryGet(
48       "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags));
49   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
50 
51   // Use standard macros (but with fixed samples)
52   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
53   HISTOGRAM_COUNTS("Test3Histogram", 30);
54 
55   DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
56   DHISTOGRAM_COUNTS("Test5Histogram", 30);
57 
58   HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
59 
60   // Try to construct samples.
61   Histogram::SampleSet sample1;
62   Histogram::SampleSet sample2;
63 
64   // Use copy constructor of SampleSet
65   sample1 = sample2;
66   Histogram::SampleSet sample3(sample1);
67 
68   // Finally test a statistics recorder, without really using it.
69   StatisticsRecorder recorder;
70 }
71 
72 // Repeat with a recorder present to register with.
TEST(HistogramTest,RecordedStartupTest)73 TEST(HistogramTest, RecordedStartupTest) {
74   // Test a statistics recorder, by letting histograms register.
75   StatisticsRecorder recorder;  // This initializes the global state.
76 
77   StatisticsRecorder::Histograms histograms;
78   EXPECT_EQ(0U, histograms.size());
79   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
80   EXPECT_EQ(0U, histograms.size());
81 
82   // Try basic construction
83   Histogram* histogram(Histogram::FactoryGet(
84       "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
85   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
86   histograms.clear();
87   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
88   EXPECT_EQ(1U, histograms.size());
89   Histogram* histogram1(Histogram::FactoryGet(
90       "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
91   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
92   histograms.clear();
93   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
94   EXPECT_EQ(2U, histograms.size());
95 
96   Histogram* linear_histogram(LinearHistogram::FactoryGet(
97       "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
98   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
99   histograms.clear();
100   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
101   EXPECT_EQ(3U, histograms.size());
102 
103   Histogram* linear_histogram1(LinearHistogram::FactoryGet(
104       "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
105   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
106   histograms.clear();
107   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
108   EXPECT_EQ(4U, histograms.size());
109 
110   std::vector<int> custom_ranges;
111   custom_ranges.push_back(1);
112   custom_ranges.push_back(5);
113   custom_ranges.push_back(10);
114   custom_ranges.push_back(20);
115   custom_ranges.push_back(30);
116   Histogram* custom_histogram(CustomHistogram::FactoryGet(
117       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
118   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
119   Histogram* custom_histogram1(CustomHistogram::FactoryGet(
120       "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
121   EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
122 
123   histograms.clear();
124   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
125   EXPECT_EQ(5U, histograms.size());
126 
127   // Use standard macros (but with fixed samples)
128   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
129   HISTOGRAM_COUNTS("Test3Histogram", 30);
130   histograms.clear();
131   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
132   EXPECT_EQ(7U, histograms.size());
133 
134   HISTOGRAM_ENUMERATION("TestEnumerationHistogram", 20, 200);
135   histograms.clear();
136   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
137   EXPECT_EQ(8U, histograms.size());
138 
139   DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1));
140   DHISTOGRAM_COUNTS("Test5Histogram", 30);
141   histograms.clear();
142   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
143 #ifndef NDEBUG
144   EXPECT_EQ(10U, histograms.size());
145 #else
146   EXPECT_EQ(8U, histograms.size());
147 #endif
148 }
149 
TEST(HistogramTest,RangeTest)150 TEST(HistogramTest, RangeTest) {
151   StatisticsRecorder recorder;
152   StatisticsRecorder::Histograms histograms;
153 
154   recorder.GetHistograms(&histograms);
155   EXPECT_EQ(0U, histograms.size());
156 
157   Histogram* histogram(Histogram::FactoryGet(
158       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
159   // Check that we got a nice exponential when there was enough rooom.
160   EXPECT_EQ(0, histogram->ranges(0));
161   int power_of_2 = 1;
162   for (int i = 1; i < 8; i++) {
163     EXPECT_EQ(power_of_2, histogram->ranges(i));
164     power_of_2 *= 2;
165   }
166   EXPECT_EQ(INT_MAX, histogram->ranges(8));
167 
168   Histogram* short_histogram(Histogram::FactoryGet(
169       "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags));
170   // Check that when the number of buckets is short, we get a linear histogram
171   // for lack of space to do otherwise.
172   for (int i = 0; i < 8; i++)
173     EXPECT_EQ(i, short_histogram->ranges(i));
174   EXPECT_EQ(INT_MAX, short_histogram->ranges(8));
175 
176   Histogram* linear_histogram(LinearHistogram::FactoryGet(
177       "Linear", 1, 7, 8, Histogram::kNoFlags));
178   // We also get a nice linear set of bucket ranges when we ask for it
179   for (int i = 0; i < 8; i++)
180     EXPECT_EQ(i, linear_histogram->ranges(i));
181   EXPECT_EQ(INT_MAX, linear_histogram->ranges(8));
182 
183   Histogram* linear_broad_histogram(LinearHistogram::FactoryGet(
184       "Linear widened", 2, 14, 8, Histogram::kNoFlags));
185   // ...but when the list has more space, then the ranges naturally spread out.
186   for (int i = 0; i < 8; i++)
187     EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i));
188   EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8));
189 
190   Histogram* transitioning_histogram(Histogram::FactoryGet(
191       "LinearAndExponential", 1, 32, 15, Histogram::kNoFlags));
192   // When space is a little tight, we transition from linear to exponential.
193   EXPECT_EQ(0, transitioning_histogram->ranges(0));
194   EXPECT_EQ(1, transitioning_histogram->ranges(1));
195   EXPECT_EQ(2, transitioning_histogram->ranges(2));
196   EXPECT_EQ(3, transitioning_histogram->ranges(3));
197   EXPECT_EQ(4, transitioning_histogram->ranges(4));
198   EXPECT_EQ(5, transitioning_histogram->ranges(5));
199   EXPECT_EQ(6, transitioning_histogram->ranges(6));
200   EXPECT_EQ(7, transitioning_histogram->ranges(7));
201   EXPECT_EQ(9, transitioning_histogram->ranges(8));
202   EXPECT_EQ(11, transitioning_histogram->ranges(9));
203   EXPECT_EQ(14, transitioning_histogram->ranges(10));
204   EXPECT_EQ(17, transitioning_histogram->ranges(11));
205   EXPECT_EQ(21, transitioning_histogram->ranges(12));
206   EXPECT_EQ(26, transitioning_histogram->ranges(13));
207   EXPECT_EQ(32, transitioning_histogram->ranges(14));
208   EXPECT_EQ(INT_MAX, transitioning_histogram->ranges(15));
209 
210   std::vector<int> custom_ranges;
211   custom_ranges.push_back(0);
212   custom_ranges.push_back(9);
213   custom_ranges.push_back(10);
214   custom_ranges.push_back(11);
215   custom_ranges.push_back(300);
216   Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
217       "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
218 
219   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(0));
220   EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(1));
221   EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(2));
222   EXPECT_EQ(custom_ranges[3], test_custom_histogram->ranges(3));
223   EXPECT_EQ(custom_ranges[4], test_custom_histogram->ranges(4));
224 
225   recorder.GetHistograms(&histograms);
226   EXPECT_EQ(6U, histograms.size());
227 }
228 
TEST(HistogramTest,CustomRangeTest)229 TEST(HistogramTest, CustomRangeTest) {
230   StatisticsRecorder recorder;
231   StatisticsRecorder::Histograms histograms;
232 
233   // Check that missing leading zero is handled by an auto-insertion.
234   std::vector<int> custom_ranges;
235   // Don't include a zero.
236   custom_ranges.push_back(9);
237   custom_ranges.push_back(10);
238   custom_ranges.push_back(11);
239   Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
240       "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
241 
242   EXPECT_EQ(0, test_custom_histogram->ranges(0));  // Auto added
243   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(1));
244   EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(2));
245   EXPECT_EQ(custom_ranges[2], test_custom_histogram->ranges(3));
246 
247   // Check that unsorted data with dups is handled gracefully.
248   const int kSmall = 7;
249   const int kMid = 8;
250   const int kBig = 9;
251   custom_ranges.clear();
252   custom_ranges.push_back(kBig);
253   custom_ranges.push_back(kMid);
254   custom_ranges.push_back(kSmall);
255   custom_ranges.push_back(kSmall);
256   custom_ranges.push_back(kMid);
257   custom_ranges.push_back(0);  // Push an explicit zero.
258   custom_ranges.push_back(kBig);
259 
260   Histogram* unsorted_histogram(CustomHistogram::FactoryGet(
261       "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags));
262   EXPECT_EQ(0, unsorted_histogram->ranges(0));
263   EXPECT_EQ(kSmall, unsorted_histogram->ranges(1));
264   EXPECT_EQ(kMid, unsorted_histogram->ranges(2));
265   EXPECT_EQ(kBig, unsorted_histogram->ranges(3));
266 }
267 
268 
269 // Make sure histogram handles out-of-bounds data gracefully.
TEST(HistogramTest,BoundsTest)270 TEST(HistogramTest, BoundsTest) {
271   const size_t kBucketCount = 50;
272   Histogram* histogram(Histogram::FactoryGet(
273       "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
274 
275   // Put two samples "out of bounds" above and below.
276   histogram->Add(5);
277   histogram->Add(-50);
278 
279   histogram->Add(100);
280   histogram->Add(10000);
281 
282   // Verify they landed in the underflow, and overflow buckets.
283   Histogram::SampleSet sample;
284   histogram->SnapshotSample(&sample);
285   EXPECT_EQ(2, sample.counts(0));
286   EXPECT_EQ(0, sample.counts(1));
287   size_t array_size = histogram->bucket_count();
288   EXPECT_EQ(kBucketCount, array_size);
289   EXPECT_EQ(0, sample.counts(array_size - 2));
290   EXPECT_EQ(2, sample.counts(array_size - 1));
291 }
292 
293 // Check to be sure samples land as expected is "correct" buckets.
TEST(HistogramTest,BucketPlacementTest)294 TEST(HistogramTest, BucketPlacementTest) {
295   Histogram* histogram(Histogram::FactoryGet(
296       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
297 
298   // Check that we got a nice exponential since there was enough rooom.
299   EXPECT_EQ(0, histogram->ranges(0));
300   int power_of_2 = 1;
301   for (int i = 1; i < 8; i++) {
302     EXPECT_EQ(power_of_2, histogram->ranges(i));
303     power_of_2 *= 2;
304   }
305   EXPECT_EQ(INT_MAX, histogram->ranges(8));
306 
307   // Add i+1 samples to the i'th bucket.
308   histogram->Add(0);
309   power_of_2 = 1;
310   for (int i = 1; i < 8; i++) {
311     for (int j = 0; j <= i; j++)
312       histogram->Add(power_of_2);
313     power_of_2 *= 2;
314   }
315   // Leave overflow bucket empty.
316 
317   // Check to see that the bucket counts reflect our additions.
318   Histogram::SampleSet sample;
319   histogram->SnapshotSample(&sample);
320   EXPECT_EQ(INT_MAX, histogram->ranges(8));
321   for (int i = 0; i < 8; i++)
322     EXPECT_EQ(i + 1, sample.counts(i));
323 }
324 
325 }  // namespace
326 
327 //------------------------------------------------------------------------------
328 // We can't be an an anonymous namespace while being friends, so we pop back
329 // out to the base namespace here.  We need to be friends to corrupt the
330 // internals of the histogram and/or sampleset.
TEST(HistogramTest,CorruptSampleCounts)331 TEST(HistogramTest, CorruptSampleCounts) {
332   Histogram* histogram(Histogram::FactoryGet(
333       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
334 
335   EXPECT_EQ(0, histogram->sample_.redundant_count());
336   histogram->Add(20);  // Add some samples.
337   histogram->Add(40);
338   EXPECT_EQ(2, histogram->sample_.redundant_count());
339 
340   Histogram::SampleSet snapshot;
341   histogram->SnapshotSample(&snapshot);
342   EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
343   EXPECT_EQ(0, histogram->FindCorruption(snapshot));  // No default corruption.
344   EXPECT_EQ(2, snapshot.redundant_count());
345 
346   snapshot.counts_[3] += 100;  // Sample count won't match redundant count.
347   EXPECT_EQ(Histogram::COUNT_LOW_ERROR, histogram->FindCorruption(snapshot));
348   snapshot.counts_[2] -= 200;
349   EXPECT_EQ(Histogram::COUNT_HIGH_ERROR, histogram->FindCorruption(snapshot));
350 
351   // But we can't spot a corruption if it is compensated for.
352   snapshot.counts_[1] += 100;
353   EXPECT_EQ(0, histogram->FindCorruption(snapshot));
354 }
355 
TEST(HistogramTest,CorruptBucketBounds)356 TEST(HistogramTest, CorruptBucketBounds) {
357   Histogram* histogram(Histogram::FactoryGet(
358       "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
359 
360   Histogram::SampleSet snapshot;
361   histogram->SnapshotSample(&snapshot);
362   EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
363   EXPECT_EQ(0, histogram->FindCorruption(snapshot));  // No default corruption.
364 
365   std::swap(histogram->ranges_[1], histogram->ranges_[2]);
366   EXPECT_EQ(Histogram::BUCKET_ORDER_ERROR | Histogram::RANGE_CHECKSUM_ERROR,
367             histogram->FindCorruption(snapshot));
368 
369   std::swap(histogram->ranges_[1], histogram->ranges_[2]);
370   EXPECT_EQ(0, histogram->FindCorruption(snapshot));
371 
372   ++histogram->ranges_[3];
373   EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
374             histogram->FindCorruption(snapshot));
375 
376   // Show that two simple changes don't offset each other
377   --histogram->ranges_[4];
378   EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
379             histogram->FindCorruption(snapshot));
380 
381   // Repair histogram so that destructor won't DCHECK().
382   --histogram->ranges_[3];
383   ++histogram->ranges_[4];
384 }
385 
386 // Table was generated similarly to sample code for CRC-32 given on:
387 // http://www.w3.org/TR/PNG/#D-CRCAppendix.
TEST(HistogramTest,Crc32TableTest)388 TEST(HistogramTest, Crc32TableTest) {
389   for (int i = 0; i < 256; ++i) {
390     uint32 checksum = i;
391     for (int j = 0; j < 8; ++j) {
392       const uint32 kReversedPolynomial = 0xedb88320L;
393       if (checksum & 1)
394         checksum = kReversedPolynomial ^ (checksum >> 1);
395       else
396         checksum >>= 1;
397     }
398     EXPECT_EQ(Histogram::kCrcTable[i], checksum);
399   }
400 }
401 
402 }  // namespace base
403