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