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