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