• 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 #include "base/metrics/histogram.h"
6 
7 #include <limits.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <climits>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #include "base/logging.h"
17 #include "base/metrics/bucket_ranges.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/metrics/persistent_histogram_allocator.h"
20 #include "base/metrics/persistent_memory_allocator.h"
21 #include "base/metrics/sample_vector.h"
22 #include "base/metrics/statistics_recorder.h"
23 #include "base/pickle.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/time/time.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 
28 namespace base {
29 
30 // Test parameter indicates if a persistent memory allocator should be used
31 // for histogram allocation. False will allocate histograms from the process
32 // heap.
33 class HistogramTest : public testing::TestWithParam<bool> {
34  protected:
35   const int32_t kAllocatorMemorySize = 8 << 20;  // 8 MiB
36 
HistogramTest()37   HistogramTest() : use_persistent_histogram_allocator_(GetParam()) {}
38 
SetUp()39   void SetUp() override {
40     if (use_persistent_histogram_allocator_)
41       CreatePersistentHistogramAllocator();
42 
43     // Each test will have a clean state (no Histogram / BucketRanges
44     // registered).
45     InitializeStatisticsRecorder();
46   }
47 
TearDown()48   void TearDown() override {
49     if (allocator_) {
50       ASSERT_FALSE(allocator_->IsFull());
51       ASSERT_FALSE(allocator_->IsCorrupt());
52     }
53     UninitializeStatisticsRecorder();
54     DestroyPersistentHistogramAllocator();
55   }
56 
InitializeStatisticsRecorder()57   void InitializeStatisticsRecorder() {
58     DCHECK(!statistics_recorder_);
59     statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
60   }
61 
UninitializeStatisticsRecorder()62   void UninitializeStatisticsRecorder() {
63     statistics_recorder_.reset();
64   }
65 
CreatePersistentHistogramAllocator()66   void CreatePersistentHistogramAllocator() {
67     // By getting the results-histogram before any persistent allocator
68     // is attached, that histogram is guaranteed not to be stored in
69     // any persistent memory segment (which simplifies some tests).
70     GlobalHistogramAllocator::GetCreateHistogramResultHistogram();
71 
72     GlobalHistogramAllocator::CreateWithLocalMemory(
73         kAllocatorMemorySize, 0, "HistogramAllocatorTest");
74     allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
75   }
76 
DestroyPersistentHistogramAllocator()77   void DestroyPersistentHistogramAllocator() {
78     allocator_ = nullptr;
79     GlobalHistogramAllocator::ReleaseForTesting();
80   }
81 
82   const bool use_persistent_histogram_allocator_;
83 
84   std::unique_ptr<StatisticsRecorder> statistics_recorder_;
85   std::unique_ptr<char[]> allocator_memory_;
86   PersistentMemoryAllocator* allocator_ = nullptr;
87 
88  private:
89   DISALLOW_COPY_AND_ASSIGN(HistogramTest);
90 };
91 
92 // Run all HistogramTest cases with both heap and persistent memory.
93 INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest, testing::Bool());
94 
95 
96 // Check for basic syntax and use.
TEST_P(HistogramTest,BasicTest)97 TEST_P(HistogramTest, BasicTest) {
98   // Try basic construction
99   HistogramBase* histogram = Histogram::FactoryGet(
100       "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
101   EXPECT_TRUE(histogram);
102 
103   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
104       "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
105   EXPECT_TRUE(linear_histogram);
106 
107   std::vector<int> custom_ranges;
108   custom_ranges.push_back(1);
109   custom_ranges.push_back(5);
110   HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
111       "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
112   EXPECT_TRUE(custom_histogram);
113 
114   // Macros that create hitograms have an internal static variable which will
115   // continue to point to those from the very first run of this method even
116   // during subsequent runs.
117   static bool already_run = false;
118   if (already_run)
119     return;
120   already_run = true;
121 
122   // Use standard macros (but with fixed samples)
123   LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
124   LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
125 
126   LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
127 }
128 
129 // Check that the macro correctly matches histograms by name and records their
130 // data together.
TEST_P(HistogramTest,NameMatchTest)131 TEST_P(HistogramTest, NameMatchTest) {
132   // Macros that create hitograms have an internal static variable which will
133   // continue to point to those from the very first run of this method even
134   // during subsequent runs.
135   static bool already_run = false;
136   if (already_run)
137     return;
138   already_run = true;
139 
140   LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
141   LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
142   HistogramBase* histogram = LinearHistogram::FactoryGet(
143       "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags);
144 
145   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
146   EXPECT_EQ(2, samples->TotalCount());
147   EXPECT_EQ(2, samples->GetCount(10));
148 }
149 
150 // Check that delta calculations work correctly.
TEST_P(HistogramTest,DeltaTest)151 TEST_P(HistogramTest, DeltaTest) {
152   HistogramBase* histogram =
153       Histogram::FactoryGet("DeltaHistogram", 1, 64, 8,
154                             HistogramBase::kNoFlags);
155   histogram->Add(1);
156   histogram->Add(10);
157   histogram->Add(50);
158 
159   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
160   EXPECT_EQ(3, samples->TotalCount());
161   EXPECT_EQ(1, samples->GetCount(1));
162   EXPECT_EQ(1, samples->GetCount(10));
163   EXPECT_EQ(1, samples->GetCount(50));
164   EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
165 
166   samples = histogram->SnapshotDelta();
167   EXPECT_EQ(0, samples->TotalCount());
168 
169   histogram->Add(10);
170   histogram->Add(10);
171   samples = histogram->SnapshotDelta();
172   EXPECT_EQ(2, samples->TotalCount());
173   EXPECT_EQ(2, samples->GetCount(10));
174 
175   samples = histogram->SnapshotDelta();
176   EXPECT_EQ(0, samples->TotalCount());
177 }
178 
179 // Check that final-delta calculations work correctly.
TEST_P(HistogramTest,FinalDeltaTest)180 TEST_P(HistogramTest, FinalDeltaTest) {
181   HistogramBase* histogram =
182       Histogram::FactoryGet("FinalDeltaHistogram", 1, 64, 8,
183                             HistogramBase::kNoFlags);
184   histogram->Add(1);
185   histogram->Add(10);
186   histogram->Add(50);
187 
188   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
189   EXPECT_EQ(3, samples->TotalCount());
190   EXPECT_EQ(1, samples->GetCount(1));
191   EXPECT_EQ(1, samples->GetCount(10));
192   EXPECT_EQ(1, samples->GetCount(50));
193   EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
194 
195   histogram->Add(2);
196   histogram->Add(50);
197 
198   samples = histogram->SnapshotFinalDelta();
199   EXPECT_EQ(2, samples->TotalCount());
200   EXPECT_EQ(1, samples->GetCount(2));
201   EXPECT_EQ(1, samples->GetCount(50));
202   EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
203 }
204 
TEST_P(HistogramTest,ExponentialRangesTest)205 TEST_P(HistogramTest, ExponentialRangesTest) {
206   // Check that we got a nice exponential when there was enough room.
207   BucketRanges ranges(9);
208   Histogram::InitializeBucketRanges(1, 64, &ranges);
209   EXPECT_EQ(0, ranges.range(0));
210   int power_of_2 = 1;
211   for (int i = 1; i < 8; i++) {
212     EXPECT_EQ(power_of_2, ranges.range(i));
213     power_of_2 *= 2;
214   }
215   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
216 
217   // Check the corresponding Histogram will use the correct ranges.
218   Histogram* histogram = static_cast<Histogram*>(
219       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
220   EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
221 
222   // When bucket count is limited, exponential ranges will partially look like
223   // linear.
224   BucketRanges ranges2(16);
225   Histogram::InitializeBucketRanges(1, 32, &ranges2);
226 
227   EXPECT_EQ(0, ranges2.range(0));
228   EXPECT_EQ(1, ranges2.range(1));
229   EXPECT_EQ(2, ranges2.range(2));
230   EXPECT_EQ(3, ranges2.range(3));
231   EXPECT_EQ(4, ranges2.range(4));
232   EXPECT_EQ(5, ranges2.range(5));
233   EXPECT_EQ(6, ranges2.range(6));
234   EXPECT_EQ(7, ranges2.range(7));
235   EXPECT_EQ(9, ranges2.range(8));
236   EXPECT_EQ(11, ranges2.range(9));
237   EXPECT_EQ(14, ranges2.range(10));
238   EXPECT_EQ(17, ranges2.range(11));
239   EXPECT_EQ(21, ranges2.range(12));
240   EXPECT_EQ(26, ranges2.range(13));
241   EXPECT_EQ(32, ranges2.range(14));
242   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15));
243 
244   // Check the corresponding Histogram will use the correct ranges.
245   Histogram* histogram2 = static_cast<Histogram*>(
246       Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags));
247   EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
248 }
249 
TEST_P(HistogramTest,LinearRangesTest)250 TEST_P(HistogramTest, LinearRangesTest) {
251   BucketRanges ranges(9);
252   LinearHistogram::InitializeBucketRanges(1, 7, &ranges);
253   // Gets a nice linear set of bucket ranges.
254   for (int i = 0; i < 8; i++)
255     EXPECT_EQ(i, ranges.range(i));
256   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
257 
258   // The correspoding LinearHistogram should use the correct ranges.
259   Histogram* histogram = static_cast<Histogram*>(
260       LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags));
261   EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
262 
263   // Linear ranges are not divisible.
264   BucketRanges ranges2(6);
265   LinearHistogram::InitializeBucketRanges(1, 6, &ranges2);
266   EXPECT_EQ(0, ranges2.range(0));
267   EXPECT_EQ(1, ranges2.range(1));
268   EXPECT_EQ(3, ranges2.range(2));
269   EXPECT_EQ(4, ranges2.range(3));
270   EXPECT_EQ(6, ranges2.range(4));
271   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5));
272   // The correspoding LinearHistogram should use the correct ranges.
273   Histogram* histogram2 = static_cast<Histogram*>(
274       LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags));
275   EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
276 }
277 
TEST_P(HistogramTest,ArrayToCustomRangesTest)278 TEST_P(HistogramTest, ArrayToCustomRangesTest) {
279   const HistogramBase::Sample ranges[3] = {5, 10, 20};
280   std::vector<HistogramBase::Sample> ranges_vec =
281       CustomHistogram::ArrayToCustomRanges(ranges, 3);
282   ASSERT_EQ(6u, ranges_vec.size());
283   EXPECT_EQ(5, ranges_vec[0]);
284   EXPECT_EQ(6, ranges_vec[1]);
285   EXPECT_EQ(10, ranges_vec[2]);
286   EXPECT_EQ(11, ranges_vec[3]);
287   EXPECT_EQ(20, ranges_vec[4]);
288   EXPECT_EQ(21, ranges_vec[5]);
289 }
290 
TEST_P(HistogramTest,CustomHistogramTest)291 TEST_P(HistogramTest, CustomHistogramTest) {
292   // A well prepared custom ranges.
293   std::vector<HistogramBase::Sample> custom_ranges;
294   custom_ranges.push_back(1);
295   custom_ranges.push_back(2);
296 
297   Histogram* histogram = static_cast<Histogram*>(
298       CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges,
299                                   HistogramBase::kNoFlags));
300   const BucketRanges* ranges = histogram->bucket_ranges();
301   ASSERT_EQ(4u, ranges->size());
302   EXPECT_EQ(0, ranges->range(0));  // Auto added.
303   EXPECT_EQ(1, ranges->range(1));
304   EXPECT_EQ(2, ranges->range(2));
305   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));  // Auto added.
306 
307   // A unordered custom ranges.
308   custom_ranges.clear();
309   custom_ranges.push_back(2);
310   custom_ranges.push_back(1);
311   histogram = static_cast<Histogram*>(
312       CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges,
313                                   HistogramBase::kNoFlags));
314   ranges = histogram->bucket_ranges();
315   ASSERT_EQ(4u, ranges->size());
316   EXPECT_EQ(0, ranges->range(0));
317   EXPECT_EQ(1, ranges->range(1));
318   EXPECT_EQ(2, ranges->range(2));
319   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
320 
321   // A custom ranges with duplicated values.
322   custom_ranges.clear();
323   custom_ranges.push_back(4);
324   custom_ranges.push_back(1);
325   custom_ranges.push_back(4);
326   histogram = static_cast<Histogram*>(
327       CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges,
328                                   HistogramBase::kNoFlags));
329   ranges = histogram->bucket_ranges();
330   ASSERT_EQ(4u, ranges->size());
331   EXPECT_EQ(0, ranges->range(0));
332   EXPECT_EQ(1, ranges->range(1));
333   EXPECT_EQ(4, ranges->range(2));
334   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
335 }
336 
TEST_P(HistogramTest,CustomHistogramWithOnly2Buckets)337 TEST_P(HistogramTest, CustomHistogramWithOnly2Buckets) {
338   // This test exploits the fact that the CustomHistogram can have 2 buckets,
339   // while the base class Histogram is *supposed* to have at least 3 buckets.
340   // We should probably change the restriction on the base class (or not inherit
341   // the base class!).
342 
343   std::vector<HistogramBase::Sample> custom_ranges;
344   custom_ranges.push_back(4);
345 
346   Histogram* histogram = static_cast<Histogram*>(
347       CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges,
348                                   HistogramBase::kNoFlags));
349   const BucketRanges* ranges = histogram->bucket_ranges();
350   ASSERT_EQ(3u, ranges->size());
351   EXPECT_EQ(0, ranges->range(0));
352   EXPECT_EQ(4, ranges->range(1));
353   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
354 }
355 
TEST_P(HistogramTest,AddCountTest)356 TEST_P(HistogramTest, AddCountTest) {
357   const size_t kBucketCount = 50;
358   Histogram* histogram = static_cast<Histogram*>(
359       Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount,
360                             HistogramBase::kNoFlags));
361 
362   histogram->AddCount(20, 15);
363   histogram->AddCount(30, 14);
364 
365   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
366   EXPECT_EQ(29, samples->TotalCount());
367   EXPECT_EQ(15, samples->GetCount(20));
368   EXPECT_EQ(14, samples->GetCount(30));
369 
370   histogram->AddCount(20, 25);
371   histogram->AddCount(30, 24);
372 
373   std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples();
374   EXPECT_EQ(78, samples2->TotalCount());
375   EXPECT_EQ(40, samples2->GetCount(20));
376   EXPECT_EQ(38, samples2->GetCount(30));
377 }
378 
TEST_P(HistogramTest,AddCount_LargeValuesDontOverflow)379 TEST_P(HistogramTest, AddCount_LargeValuesDontOverflow) {
380   const size_t kBucketCount = 50;
381   Histogram* histogram = static_cast<Histogram*>(
382       Histogram::FactoryGet("AddCountHistogram", 10, 1000000000, kBucketCount,
383                             HistogramBase::kNoFlags));
384 
385   histogram->AddCount(200000000, 15);
386   histogram->AddCount(300000000, 14);
387 
388   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
389   EXPECT_EQ(29, samples->TotalCount());
390   EXPECT_EQ(15, samples->GetCount(200000000));
391   EXPECT_EQ(14, samples->GetCount(300000000));
392 
393   histogram->AddCount(200000000, 25);
394   histogram->AddCount(300000000, 24);
395 
396   std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples();
397   EXPECT_EQ(78, samples2->TotalCount());
398   EXPECT_EQ(40, samples2->GetCount(200000000));
399   EXPECT_EQ(38, samples2->GetCount(300000000));
400   EXPECT_EQ(19400000000LL, samples2->sum());
401 }
402 
403 // Make sure histogram handles out-of-bounds data gracefully.
TEST_P(HistogramTest,BoundsTest)404 TEST_P(HistogramTest, BoundsTest) {
405   const size_t kBucketCount = 50;
406   Histogram* histogram = static_cast<Histogram*>(
407       Histogram::FactoryGet("Bounded", 10, 100, kBucketCount,
408                             HistogramBase::kNoFlags));
409 
410   // Put two samples "out of bounds" above and below.
411   histogram->Add(5);
412   histogram->Add(-50);
413 
414   histogram->Add(100);
415   histogram->Add(10000);
416 
417   // Verify they landed in the underflow, and overflow buckets.
418   std::unique_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
419   EXPECT_EQ(2, samples->GetCountAtIndex(0));
420   EXPECT_EQ(0, samples->GetCountAtIndex(1));
421   size_t array_size = histogram->bucket_count();
422   EXPECT_EQ(kBucketCount, array_size);
423   EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
424   EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
425 
426   std::vector<int> custom_ranges;
427   custom_ranges.push_back(10);
428   custom_ranges.push_back(50);
429   custom_ranges.push_back(100);
430   Histogram* test_custom_histogram = static_cast<Histogram*>(
431       CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
432                                   custom_ranges, HistogramBase::kNoFlags));
433 
434   // Put two samples "out of bounds" above and below.
435   test_custom_histogram->Add(5);
436   test_custom_histogram->Add(-50);
437   test_custom_histogram->Add(100);
438   test_custom_histogram->Add(1000);
439   test_custom_histogram->Add(INT_MAX);
440 
441   // Verify they landed in the underflow, and overflow buckets.
442   std::unique_ptr<SampleVector> custom_samples =
443       test_custom_histogram->SnapshotSampleVector();
444   EXPECT_EQ(2, custom_samples->GetCountAtIndex(0));
445   EXPECT_EQ(0, custom_samples->GetCountAtIndex(1));
446   size_t bucket_count = test_custom_histogram->bucket_count();
447   EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2));
448   EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1));
449 }
450 
451 // Check to be sure samples land as expected is "correct" buckets.
TEST_P(HistogramTest,BucketPlacementTest)452 TEST_P(HistogramTest, BucketPlacementTest) {
453   Histogram* histogram = static_cast<Histogram*>(
454       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
455 
456   // Add i+1 samples to the i'th bucket.
457   histogram->Add(0);
458   int power_of_2 = 1;
459   for (int i = 1; i < 8; i++) {
460     for (int j = 0; j <= i; j++)
461       histogram->Add(power_of_2);
462     power_of_2 *= 2;
463   }
464 
465   // Check to see that the bucket counts reflect our additions.
466   std::unique_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
467   for (int i = 0; i < 8; i++)
468     EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
469 }
470 
TEST_P(HistogramTest,CorruptSampleCounts)471 TEST_P(HistogramTest, CorruptSampleCounts) {
472   // The internal code creates histograms via macros and thus keeps static
473   // pointers to them. If those pointers are to persistent memory which will
474   // be free'd then any following calls to that code will crash with a
475   // segmentation violation.
476   if (use_persistent_histogram_allocator_)
477     return;
478 
479   Histogram* histogram = static_cast<Histogram*>(
480       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
481 
482   // Add some samples.
483   histogram->Add(20);
484   histogram->Add(40);
485 
486   std::unique_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
487   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
488             histogram->FindCorruption(*snapshot));
489   EXPECT_EQ(2, snapshot->redundant_count());
490   EXPECT_EQ(2, snapshot->TotalCount());
491 
492   snapshot->counts_[3] += 100;  // Sample count won't match redundant count.
493   EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR,
494             histogram->FindCorruption(*snapshot));
495   snapshot->counts_[2] -= 200;
496   EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR,
497             histogram->FindCorruption(*snapshot));
498 
499   // But we can't spot a corruption if it is compensated for.
500   snapshot->counts_[1] += 100;
501   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
502             histogram->FindCorruption(*snapshot));
503 }
504 
TEST_P(HistogramTest,CorruptBucketBounds)505 TEST_P(HistogramTest, CorruptBucketBounds) {
506   Histogram* histogram = static_cast<Histogram*>(
507       Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
508 
509   std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples();
510   EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
511             histogram->FindCorruption(*snapshot));
512 
513   BucketRanges* bucket_ranges =
514       const_cast<BucketRanges*>(histogram->bucket_ranges());
515   HistogramBase::Sample tmp = bucket_ranges->range(1);
516   bucket_ranges->set_range(1, bucket_ranges->range(2));
517   bucket_ranges->set_range(2, tmp);
518   EXPECT_EQ(
519       HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR,
520       histogram->FindCorruption(*snapshot));
521 
522   bucket_ranges->set_range(2, bucket_ranges->range(1));
523   bucket_ranges->set_range(1, tmp);
524   EXPECT_EQ(0U, histogram->FindCorruption(*snapshot));
525 
526   // Show that two simple changes don't offset each other
527   bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
528   EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
529             histogram->FindCorruption(*snapshot));
530 
531   bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
532   EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
533             histogram->FindCorruption(*snapshot));
534 
535   // Repair histogram so that destructor won't DCHECK().
536   bucket_ranges->set_range(3, bucket_ranges->range(3) - 1);
537   bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
538 }
539 
TEST_P(HistogramTest,HistogramSerializeInfo)540 TEST_P(HistogramTest, HistogramSerializeInfo) {
541   Histogram* histogram = static_cast<Histogram*>(
542       Histogram::FactoryGet("Histogram", 1, 64, 8,
543                             HistogramBase::kIPCSerializationSourceFlag));
544   Pickle pickle;
545   histogram->SerializeInfo(&pickle);
546 
547   PickleIterator iter(pickle);
548 
549   int type;
550   EXPECT_TRUE(iter.ReadInt(&type));
551   EXPECT_EQ(HISTOGRAM, type);
552 
553   std::string name;
554   EXPECT_TRUE(iter.ReadString(&name));
555   EXPECT_EQ("Histogram", name);
556 
557   int flag;
558   EXPECT_TRUE(iter.ReadInt(&flag));
559   EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag,
560             flag & ~HistogramBase::kIsPersistent);
561 
562   int min;
563   EXPECT_TRUE(iter.ReadInt(&min));
564   EXPECT_EQ(1, min);
565 
566   int max;
567   EXPECT_TRUE(iter.ReadInt(&max));
568   EXPECT_EQ(64, max);
569 
570   uint32_t bucket_count;
571   EXPECT_TRUE(iter.ReadUInt32(&bucket_count));
572   EXPECT_EQ(8u, bucket_count);
573 
574   uint32_t checksum;
575   EXPECT_TRUE(iter.ReadUInt32(&checksum));
576   EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
577 
578   // No more data in the pickle.
579   EXPECT_FALSE(iter.SkipBytes(1));
580 }
581 
TEST_P(HistogramTest,CustomHistogramSerializeInfo)582 TEST_P(HistogramTest, CustomHistogramSerializeInfo) {
583   std::vector<int> custom_ranges;
584   custom_ranges.push_back(10);
585   custom_ranges.push_back(100);
586 
587   HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
588       "TestCustomRangeBoundedHistogram",
589       custom_ranges,
590       HistogramBase::kNoFlags);
591   Pickle pickle;
592   custom_histogram->SerializeInfo(&pickle);
593 
594   // Validate the pickle.
595   PickleIterator iter(pickle);
596 
597   int i;
598   std::string s;
599   uint32_t bucket_count;
600   uint32_t ui32;
601   EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
602               iter.ReadInt(&i) && iter.ReadInt(&i) &&
603               iter.ReadUInt32(&bucket_count) && iter.ReadUInt32(&ui32));
604   EXPECT_EQ(3u, bucket_count);
605 
606   int range;
607   EXPECT_TRUE(iter.ReadInt(&range));
608   EXPECT_EQ(10, range);
609   EXPECT_TRUE(iter.ReadInt(&range));
610   EXPECT_EQ(100, range);
611 
612   // No more data in the pickle.
613   EXPECT_FALSE(iter.SkipBytes(1));
614 }
615 
TEST_P(HistogramTest,BadConstruction)616 TEST_P(HistogramTest, BadConstruction) {
617   HistogramBase* histogram = Histogram::FactoryGet(
618       "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
619   EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8));
620 
621   // Try to get the same histogram name with different arguments.
622   HistogramBase* bad_histogram = Histogram::FactoryGet(
623       "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags);
624   EXPECT_EQ(NULL, bad_histogram);
625   bad_histogram = Histogram::FactoryGet(
626       "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags);
627   EXPECT_EQ(NULL, bad_histogram);
628 
629   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
630       "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags);
631   EXPECT_TRUE(linear_histogram->HasConstructionArguments(1, 100, 8));
632 
633   // Try to get the same histogram name with different arguments.
634   bad_histogram = LinearHistogram::FactoryGet(
635       "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags);
636   EXPECT_EQ(NULL, bad_histogram);
637   bad_histogram = LinearHistogram::FactoryGet(
638       "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags);
639   EXPECT_EQ(NULL, bad_histogram);
640 }
641 
TEST_P(HistogramTest,FactoryTime)642 TEST_P(HistogramTest, FactoryTime) {
643   const int kTestCreateCount = 1 << 14;  // Must be power-of-2.
644   const int kTestLookupCount = 100000;
645   const int kTestAddCount = 1000000;
646 
647   // Create all histogram names in advance for accurate timing below.
648   std::vector<std::string> histogram_names;
649   for (int i = 0; i < kTestCreateCount; ++i) {
650     histogram_names.push_back(
651         StringPrintf("TestHistogram.%d", i % kTestCreateCount));
652   }
653 
654   // Calculate cost of creating histograms.
655   TimeTicks create_start = TimeTicks::Now();
656   for (int i = 0; i < kTestCreateCount; ++i) {
657     Histogram::FactoryGet(histogram_names[i], 1, 100, 10,
658                           HistogramBase::kNoFlags);
659   }
660   TimeDelta create_ticks = TimeTicks::Now() - create_start;
661   int64_t create_ms = create_ticks.InMilliseconds();
662 
663   VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms
664           << "ms or about "
665           << (create_ms * 1000000) / kTestCreateCount
666           << "ns each.";
667 
668   // Calculate cost of looking up existing histograms.
669   TimeTicks lookup_start = TimeTicks::Now();
670   for (int i = 0; i < kTestLookupCount; ++i) {
671     // 6007 is co-prime with kTestCreateCount and so will do lookups in an
672     // order less likely to be cacheable (but still hit them all) should the
673     // underlying storage use the exact histogram name as the key.
674     const int i_mult = 6007;
675     static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big");
676     int index = (i * i_mult) & (kTestCreateCount - 1);
677     Histogram::FactoryGet(histogram_names[index], 1, 100, 10,
678                           HistogramBase::kNoFlags);
679   }
680   TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start;
681   int64_t lookup_ms = lookup_ticks.InMilliseconds();
682 
683   VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms
684           << "ms or about "
685           << (lookup_ms * 1000000) / kTestLookupCount
686           << "ns each.";
687 
688   // Calculate cost of accessing histograms.
689   HistogramBase* histogram = Histogram::FactoryGet(
690       histogram_names[0], 1, 100, 10, HistogramBase::kNoFlags);
691   ASSERT_TRUE(histogram);
692   TimeTicks add_start = TimeTicks::Now();
693   for (int i = 0; i < kTestAddCount; ++i)
694     histogram->Add(i & 127);
695   TimeDelta add_ticks = TimeTicks::Now() - add_start;
696   int64_t add_ms = add_ticks.InMilliseconds();
697 
698   VLOG(1) << kTestAddCount << " histogram adds took " << add_ms
699           << "ms or about "
700           << (add_ms * 1000000) / kTestAddCount
701           << "ns each.";
702 }
703 
704 #if GTEST_HAS_DEATH_TEST
705 // For Histogram, LinearHistogram and CustomHistogram, the minimum for a
706 // declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
707 // 1). But we accept ranges exceeding those limits, and silently clamped to
708 // those limits. This is for backwards compatibility.
TEST(HistogramDeathTest,BadRangesTest)709 TEST(HistogramDeathTest, BadRangesTest) {
710   HistogramBase* histogram = Histogram::FactoryGet(
711       "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
712       HistogramBase::kNoFlags);
713   EXPECT_TRUE(
714       histogram->HasConstructionArguments(
715           1, HistogramBase::kSampleType_MAX - 1, 8));
716 
717   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
718       "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
719       HistogramBase::kNoFlags);
720   EXPECT_TRUE(
721       linear_histogram->HasConstructionArguments(
722           1, HistogramBase::kSampleType_MAX - 1, 8));
723 
724   std::vector<int> custom_ranges;
725   custom_ranges.push_back(0);
726   custom_ranges.push_back(5);
727   Histogram* custom_histogram = static_cast<Histogram*>(
728       CustomHistogram::FactoryGet(
729           "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags));
730   const BucketRanges* ranges = custom_histogram->bucket_ranges();
731   ASSERT_EQ(3u, ranges->size());
732   EXPECT_EQ(0, ranges->range(0));
733   EXPECT_EQ(5, ranges->range(1));
734   EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
735 
736   // CustomHistogram does not accepts kSampleType_MAX as range.
737   custom_ranges.push_back(HistogramBase::kSampleType_MAX);
738   EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
739                                            HistogramBase::kNoFlags),
740                "");
741 
742   // CustomHistogram needs at least 1 valid range.
743   custom_ranges.clear();
744   custom_ranges.push_back(0);
745   EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
746                                            HistogramBase::kNoFlags),
747                "");
748 }
749 #endif
750 
751 }  // namespace base
752