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/statistics_recorder.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <optional>
11 #include <utility>
12 #include <vector>
13
14 #include "base/functional/bind.h"
15 #include "base/json/json_reader.h"
16 #include "base/logging.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/metrics/histogram_base.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/metrics/metrics_hashes.h"
21 #include "base/metrics/persistent_histogram_allocator.h"
22 #include "base/metrics/record_histogram_checker.h"
23 #include "base/metrics/sparse_histogram.h"
24 #include "base/test/task_environment.h"
25 #include "base/values.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace {
30
31 // Class to make sure any manipulations we do to the min log level are
32 // contained (i.e., do not affect other unit tests).
33 class LogStateSaver {
34 public:
35 LogStateSaver() = default;
36 LogStateSaver(const LogStateSaver&) = delete;
37 LogStateSaver& operator=(const LogStateSaver&) = delete;
~LogStateSaver()38 ~LogStateSaver() { logging::SetMinLogLevel(old_min_log_level_); }
39
40 private:
41 int old_min_log_level_ = logging::GetMinLogLevel();
42 };
43
44 // Test implementation of RecordHistogramChecker interface.
45 class OddRecordHistogramChecker : public base::RecordHistogramChecker {
46 public:
47 ~OddRecordHistogramChecker() override = default;
48
49 // base::RecordHistogramChecker:
ShouldRecord(uint32_t histogram_hash) const50 bool ShouldRecord(uint32_t histogram_hash) const override {
51 return histogram_hash % 2;
52 }
53 };
54
55 } // namespace
56
57 namespace base {
58
59 using testing::IsEmpty;
60 using testing::SizeIs;
61 using testing::UnorderedElementsAre;
62
63 class StatisticsRecorderTest : public testing::TestWithParam<bool> {
64 public:
65 StatisticsRecorderTest(const StatisticsRecorderTest&) = delete;
66 StatisticsRecorderTest& operator=(const StatisticsRecorderTest&) = delete;
67
68 protected:
69 const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB
70
StatisticsRecorderTest()71 StatisticsRecorderTest() : use_persistent_histogram_allocator_(GetParam()) {
72 // Each test will have a clean state (no Histogram / BucketRanges
73 // registered).
74 InitializeStatisticsRecorder();
75
76 // Use persistent memory for histograms if so indicated by test parameter.
77 if (use_persistent_histogram_allocator_) {
78 GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0,
79 "StatisticsRecorderTest");
80 }
81 }
82
~StatisticsRecorderTest()83 ~StatisticsRecorderTest() override {
84 GlobalHistogramAllocator::ReleaseForTesting();
85 UninitializeStatisticsRecorder();
86 }
87
InitializeStatisticsRecorder()88 void InitializeStatisticsRecorder() {
89 DCHECK(!statistics_recorder_);
90 statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
91 }
92
93 // Deletes the global recorder if there is any. This is used by test
94 // NotInitialized to ensure a clean global state.
UninitializeStatisticsRecorder()95 void UninitializeStatisticsRecorder() {
96 statistics_recorder_.reset();
97
98 // Grab the lock, so we can access |top_| to satisfy locking annotations.
99 // Normally, this wouldn't be OK (we're taking a pointer to |top_| and then
100 // freeing it outside the lock), but in this case, it's benign because the
101 // test is single-threaded.
102 //
103 // Note: We can't clear |top_| in the locked block, because the
104 // StatisticsRecorder destructor expects that the lock isn't already held.
105 {
106 const AutoLock auto_lock(StatisticsRecorder::GetLock());
107 statistics_recorder_.reset(StatisticsRecorder::top_);
108 if (statistics_recorder_) {
109 // Prevent releasing ranges in test to avoid dangling pointers in
110 // created histogram objects.
111 statistics_recorder_->ranges_manager_
112 .DoNotReleaseRangesOnDestroyForTesting();
113 }
114 }
115 statistics_recorder_.reset();
116 DCHECK(!HasGlobalRecorder());
117 }
118
HasGlobalRecorder()119 bool HasGlobalRecorder() {
120 const AutoLock auto_lock(StatisticsRecorder::GetLock());
121 return StatisticsRecorder::top_ != nullptr;
122 }
123
CreateHistogram(const char * name,HistogramBase::Sample min,HistogramBase::Sample max,size_t bucket_count)124 Histogram* CreateHistogram(const char* name,
125 HistogramBase::Sample min,
126 HistogramBase::Sample max,
127 size_t bucket_count) {
128 BucketRanges* ranges = new BucketRanges(bucket_count + 1);
129 Histogram::InitializeBucketRanges(min, max, ranges);
130 const BucketRanges* registered_ranges =
131 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
132 return new Histogram(name, registered_ranges);
133 }
134
InitLogOnShutdown()135 void InitLogOnShutdown() { StatisticsRecorder::InitLogOnShutdown(); }
136
IsVLogInitialized()137 bool IsVLogInitialized() { return StatisticsRecorder::is_vlog_initialized_; }
138
ResetVLogInitialized()139 void ResetVLogInitialized() {
140 UninitializeStatisticsRecorder();
141 StatisticsRecorder::is_vlog_initialized_ = false;
142 }
143
144 const bool use_persistent_histogram_allocator_;
145
146 std::unique_ptr<StatisticsRecorder> statistics_recorder_;
147
148 private:
149 LogStateSaver log_state_saver_;
150 };
151
152 // Run all HistogramTest cases with both heap and persistent memory.
153 INSTANTIATE_TEST_SUITE_P(Allocator, StatisticsRecorderTest, testing::Bool());
154
TEST_P(StatisticsRecorderTest,NotInitialized)155 TEST_P(StatisticsRecorderTest, NotInitialized) {
156 UninitializeStatisticsRecorder();
157 EXPECT_FALSE(HasGlobalRecorder());
158
159 HistogramBase* const histogram =
160 CreateHistogram("TestHistogram", 1, 1000, 10);
161 EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicate(histogram),
162 histogram);
163 EXPECT_TRUE(HasGlobalRecorder());
164 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
165 UnorderedElementsAre(histogram));
166
167 UninitializeStatisticsRecorder();
168 EXPECT_FALSE(HasGlobalRecorder());
169
170 BucketRanges* const ranges = new BucketRanges(3);
171 ranges->ResetChecksum();
172 EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges),
173 ranges);
174 EXPECT_TRUE(HasGlobalRecorder());
175 EXPECT_THAT(StatisticsRecorder::GetBucketRanges(),
176 UnorderedElementsAre(ranges));
177 }
178
TEST_P(StatisticsRecorderTest,RegisterHistogram)179 TEST_P(StatisticsRecorderTest, RegisterHistogram) {
180 // Create a Histogram that was not registered.
181 Histogram* const histogram1 = CreateHistogram("TestHistogram1", 1, 1000, 10);
182
183 EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty());
184
185 // Register the Histogram.
186 EXPECT_EQ(histogram1,
187 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1));
188 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
189 UnorderedElementsAre(histogram1));
190
191 // Register the same Histogram again.
192 EXPECT_EQ(histogram1,
193 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1));
194 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
195 UnorderedElementsAre(histogram1));
196
197 // Register another Histogram with the same name.
198 Histogram* const histogram2 = CreateHistogram("TestHistogram1", 1, 1000, 10);
199 EXPECT_NE(histogram1, histogram2);
200 EXPECT_EQ(histogram1,
201 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram2));
202 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
203 UnorderedElementsAre(histogram1));
204
205 // Register another Histogram with a different name.
206 Histogram* const histogram3 = CreateHistogram("TestHistogram0", 1, 1000, 10);
207 EXPECT_NE(histogram1, histogram3);
208 EXPECT_EQ(histogram3,
209 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram3));
210 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
211 UnorderedElementsAre(histogram1, histogram3));
212 }
213
TEST_P(StatisticsRecorderTest,FindHistogram)214 TEST_P(StatisticsRecorderTest, FindHistogram) {
215 HistogramBase* histogram1 = Histogram::FactoryGet(
216 "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
217 HistogramBase* histogram2 = Histogram::FactoryGet(
218 "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags);
219
220 EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
221 EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
222 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
223
224 // Create a new global allocator using the same memory as the old one. Any
225 // old one is kept around so the memory doesn't get released.
226 GlobalHistogramAllocator* old_global_allocator =
227 GlobalHistogramAllocator::ReleaseForTesting();
228 if (use_persistent_histogram_allocator_) {
229 GlobalHistogramAllocator::CreateWithPersistentMemory(
230 const_cast<void*>(old_global_allocator->data()),
231 old_global_allocator->length(), 0, old_global_allocator->Id(),
232 old_global_allocator->Name());
233 }
234
235 // Reset statistics-recorder to validate operation from a clean start.
236 UninitializeStatisticsRecorder();
237 InitializeStatisticsRecorder();
238
239 if (use_persistent_histogram_allocator_) {
240 EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram1"));
241 EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram2"));
242 } else {
243 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram1"));
244 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram2"));
245 }
246 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
247 }
248
TEST_P(StatisticsRecorderTest,WithName)249 TEST_P(StatisticsRecorderTest, WithName) {
250 Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
251 Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
252 Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
253
254 const auto histograms = StatisticsRecorder::GetHistograms();
255 EXPECT_THAT(histograms, SizeIs(3));
256 EXPECT_THAT(
257 StatisticsRecorder::WithName(histograms, "", /*case_sensitive=*/true),
258 SizeIs(3));
259 EXPECT_THAT(
260 StatisticsRecorder::WithName(histograms, "Test", /*case_sensitive=*/true),
261 SizeIs(3));
262 EXPECT_THAT(
263 StatisticsRecorder::WithName(histograms, "1", /*case_sensitive=*/true),
264 SizeIs(1));
265 EXPECT_THAT(StatisticsRecorder::WithName(histograms, "hello",
266 /*case_sensitive=*/true),
267 IsEmpty());
268 EXPECT_THAT(StatisticsRecorder::WithName(histograms, "hello",
269 /*case_sensitive=*/false),
270 IsEmpty());
271 EXPECT_THAT(
272 StatisticsRecorder::WithName(histograms, "test", /*case_sensitive=*/true),
273 IsEmpty());
274 EXPECT_THAT(StatisticsRecorder::WithName(histograms, "test",
275 /*case_sensitive=*/false),
276 SizeIs(3));
277 }
278
TEST_P(StatisticsRecorderTest,RegisterHistogramWithFactoryGet)279 TEST_P(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
280 EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty());
281
282 // Create a histogram.
283 HistogramBase* const histogram1 = Histogram::FactoryGet(
284 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
285 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
286 UnorderedElementsAre(histogram1));
287
288 // Get an existing histogram.
289 HistogramBase* const histogram2 = Histogram::FactoryGet(
290 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
291 EXPECT_EQ(histogram1, histogram2);
292 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
293 UnorderedElementsAre(histogram1));
294
295 // Create a LinearHistogram.
296 HistogramBase* const histogram3 = LinearHistogram::FactoryGet(
297 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
298 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
299 UnorderedElementsAre(histogram1, histogram3));
300
301 // Create a BooleanHistogram.
302 HistogramBase* const histogram4 = BooleanHistogram::FactoryGet(
303 "TestBooleanHistogram", HistogramBase::kNoFlags);
304 EXPECT_THAT(StatisticsRecorder::GetHistograms(),
305 UnorderedElementsAre(histogram1, histogram3, histogram4));
306
307 // Create a CustomHistogram.
308 std::vector<int> custom_ranges;
309 custom_ranges.push_back(1);
310 custom_ranges.push_back(5);
311 HistogramBase* const histogram5 = CustomHistogram::FactoryGet(
312 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
313 EXPECT_THAT(
314 StatisticsRecorder::GetHistograms(),
315 UnorderedElementsAre(histogram1, histogram3, histogram4, histogram5));
316 }
317
TEST_P(StatisticsRecorderTest,RegisterHistogramWithMacros)318 TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
319 // Macros cache pointers and so tests that use them can only be run once.
320 // Stop immediately if this test has run previously.
321 static bool already_run = false;
322 if (already_run)
323 return;
324 already_run = true;
325
326 StatisticsRecorder::Histograms registered_histograms;
327
328 HistogramBase* histogram = Histogram::FactoryGet(
329 "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags);
330
331 // The histogram we got from macro is the same as from FactoryGet.
332 LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
333 registered_histograms = StatisticsRecorder::GetHistograms();
334 ASSERT_EQ(1u, registered_histograms.size());
335 EXPECT_EQ(histogram, registered_histograms[0]);
336
337 LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", Days(1));
338 LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
339
340 EXPECT_THAT(StatisticsRecorder::GetHistograms(), SizeIs(3));
341 }
342
TEST_P(StatisticsRecorderTest,BucketRangesSharing)343 TEST_P(StatisticsRecorderTest, BucketRangesSharing) {
344 EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), IsEmpty());
345
346 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
347 Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
348 EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(1));
349
350 Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
351 EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(2));
352 }
353
TEST_P(StatisticsRecorderTest,ToJSON)354 TEST_P(StatisticsRecorderTest, ToJSON) {
355 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
356 ->Add(30);
357 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
358 ->Add(40);
359 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
360 ->Add(30);
361 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
362 ->Add(40);
363
364 std::string json(StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_FULL));
365
366 // Check for valid JSON.
367 std::optional<Value> root = JSONReader::Read(json);
368 ASSERT_TRUE(root);
369 Value::Dict* root_dict = root->GetIfDict();
370 ASSERT_TRUE(root_dict);
371
372 // No query should be set.
373 ASSERT_FALSE(root_dict->Find("query"));
374
375 const Value::List* histogram_list = root_dict->FindList("histograms");
376
377 ASSERT_TRUE(histogram_list);
378 ASSERT_EQ(2u, histogram_list->size());
379
380 // Examine the first histogram.
381 const Value::Dict* histogram_dict = (*histogram_list)[0].GetIfDict();
382 ASSERT_TRUE(histogram_dict);
383
384 auto sample_count = histogram_dict->FindInt("count");
385 ASSERT_TRUE(sample_count);
386 EXPECT_EQ(2, *sample_count);
387
388 const Value::List* buckets_list = histogram_dict->FindList("buckets");
389 ASSERT_TRUE(buckets_list);
390 EXPECT_EQ(2u, buckets_list->size());
391 }
392
393 // Check the serialized JSON with a different verbosity level.
TEST_P(StatisticsRecorderTest,ToJSONOmitBuckets)394 TEST_P(StatisticsRecorderTest, ToJSONOmitBuckets) {
395 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
396 ->Add(30);
397 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
398 ->Add(40);
399 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
400 ->Add(30);
401 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
402 ->Add(40);
403
404 std::string json =
405 StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_OMIT_BUCKETS);
406 std::optional<Value> root = JSONReader::Read(json);
407 ASSERT_TRUE(root);
408 Value::Dict* root_dict = root->GetIfDict();
409 ASSERT_TRUE(root_dict);
410 const Value::List* histogram_list = root_dict->FindList("histograms");
411 ASSERT_TRUE(histogram_list);
412
413 ASSERT_EQ(2u, histogram_list->size());
414 const Value::Dict* histogram_dict2 = (*histogram_list)[0].GetIfDict();
415 ASSERT_TRUE(histogram_dict2);
416 auto sample_count = histogram_dict2->FindInt("count");
417 ASSERT_TRUE(sample_count);
418 EXPECT_EQ(2, *sample_count);
419 const Value::List* buckets_list = histogram_dict2->FindList("buckets");
420 // Bucket information should be omitted.
421 ASSERT_FALSE(buckets_list);
422 }
423
TEST_P(StatisticsRecorderTest,IterationTest)424 TEST_P(StatisticsRecorderTest, IterationTest) {
425 Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags);
426 Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags);
427
428 auto histograms = StatisticsRecorder::GetHistograms();
429 EXPECT_THAT(histograms, SizeIs(2));
430 histograms = StatisticsRecorder::GetHistograms(/*include_persistent=*/false);
431 EXPECT_THAT(histograms, SizeIs(use_persistent_histogram_allocator_ ? 0 : 2));
432
433 // Create a new global allocator using the same memory as the old one. Any
434 // old one is kept around so the memory doesn't get released.
435 GlobalHistogramAllocator* old_global_allocator =
436 GlobalHistogramAllocator::ReleaseForTesting();
437 if (use_persistent_histogram_allocator_) {
438 GlobalHistogramAllocator::CreateWithPersistentMemory(
439 const_cast<void*>(old_global_allocator->data()),
440 old_global_allocator->length(), 0, old_global_allocator->Id(),
441 old_global_allocator->Name());
442 }
443
444 // Reset statistics-recorder to validate operation from a clean start.
445 UninitializeStatisticsRecorder();
446 InitializeStatisticsRecorder();
447
448 histograms = StatisticsRecorder::GetHistograms();
449 EXPECT_THAT(histograms, SizeIs(use_persistent_histogram_allocator_ ? 2 : 0));
450 histograms = StatisticsRecorder::GetHistograms(/*include_persistent=*/false);
451 EXPECT_THAT(histograms, IsEmpty());
452 }
453
454 namespace {
455
456 // CallbackCheckWrapper is simply a convenient way to check and store that
457 // a callback was actually run.
458 struct CallbackCheckWrapper {
CallbackCheckWrapperbase::__anon32ec9aae0211::CallbackCheckWrapper459 CallbackCheckWrapper()
460 : called(false),
461 last_histogram_name(""),
462 last_name_hash(HashMetricName("")),
463 last_histogram_value(0) {}
464
OnHistogramChangedbase::__anon32ec9aae0211::CallbackCheckWrapper465 void OnHistogramChanged(const char* histogram_name,
466 uint64_t name_hash,
467 base::HistogramBase::Sample histogram_value) {
468 called = true;
469 last_histogram_name = histogram_name;
470 last_name_hash = name_hash;
471 last_histogram_value = histogram_value;
472 }
473
474 bool called;
475 const char* last_histogram_name;
476 uint64_t last_name_hash;
477 base::HistogramBase::Sample last_histogram_value;
478 };
479
480 } // namespace
481
TEST_P(StatisticsRecorderTest,AddHistogramCallbackBeforeHistogramRegistration)482 TEST_P(StatisticsRecorderTest,
483 AddHistogramCallbackBeforeHistogramRegistration) {
484 test::TaskEnvironment task_environment;
485 const char* histogram_name = "TestHistogram";
486 CallbackCheckWrapper callback_wrapper;
487
488 auto callback =
489 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
490 histogram_name,
491 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
492 base::Unretained(&callback_wrapper)));
493 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
494
495 HistogramBase* const histogram = CreateHistogram(histogram_name, 1, 1000, 10);
496 EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicate(histogram),
497 histogram);
498
499 EXPECT_TRUE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
500 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
501 }
502
TEST_P(StatisticsRecorderTest,RemoveHistogramCallbackBeforeHistogramRegistrationWithMultipleClients)503 TEST_P(StatisticsRecorderTest,
504 RemoveHistogramCallbackBeforeHistogramRegistrationWithMultipleClients) {
505 test::TaskEnvironment task_environment;
506 const char* histogram_name = "TestHistogram";
507 CallbackCheckWrapper callback_wrapper1;
508 CallbackCheckWrapper callback_wrapper2;
509
510 auto callback1 =
511 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
512 histogram_name,
513 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
514 base::Unretained(&callback_wrapper1)));
515 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
516
517 auto callback2 =
518 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
519 histogram_name,
520 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
521 base::Unretained(&callback_wrapper2)));
522 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
523
524 callback1.reset();
525 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
526
527 callback2.reset();
528 EXPECT_FALSE(base::StatisticsRecorder::have_active_callbacks());
529
530 HistogramBase* const histogram = CreateHistogram(histogram_name, 1, 1000, 10);
531 EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicate(histogram),
532 histogram);
533
534 EXPECT_FALSE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
535 EXPECT_FALSE(base::StatisticsRecorder::have_active_callbacks());
536 }
537
TEST_P(StatisticsRecorderTest,AddHistogramCallbackWithMultipleClients)538 TEST_P(StatisticsRecorderTest, AddHistogramCallbackWithMultipleClients) {
539 test::TaskEnvironment task_environment;
540 std::string histogram_name = "TestHistogram";
541 HistogramBase* histogram = Histogram::FactoryGet(histogram_name, 1, 1000, 10,
542 HistogramBase::kNoFlags);
543 EXPECT_TRUE(histogram);
544
545 CallbackCheckWrapper callback_wrapper1;
546 CallbackCheckWrapper callback_wrapper2;
547
548 auto callback1 =
549 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
550 histogram_name,
551 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
552 base::Unretained(&callback_wrapper1)));
553
554 EXPECT_TRUE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
555 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
556
557 auto callback2 =
558 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
559 histogram_name,
560 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
561 base::Unretained(&callback_wrapper2)));
562
563 EXPECT_TRUE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
564 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
565
566 histogram->Add(1);
567 base::RunLoop().RunUntilIdle();
568 EXPECT_TRUE(callback_wrapper1.called);
569 histogram->Add(1);
570 EXPECT_TRUE(callback_wrapper2.called);
571 }
572
TEST_P(StatisticsRecorderTest,RemoveHistogramCallbackWithMultipleClients)573 TEST_P(StatisticsRecorderTest, RemoveHistogramCallbackWithMultipleClients) {
574 test::TaskEnvironment task_environment;
575 std::string histogram_name = "TestHistogram";
576 HistogramBase* histogram = Histogram::FactoryGet(histogram_name, 1, 1000, 10,
577 HistogramBase::kNoFlags);
578 EXPECT_TRUE(histogram);
579
580 CallbackCheckWrapper callback_wrapper1;
581 CallbackCheckWrapper callback_wrapper2;
582
583 auto callback1 =
584 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
585 histogram_name,
586 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
587 base::Unretained(&callback_wrapper1)));
588 auto callback2 =
589 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
590 histogram_name,
591 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
592 base::Unretained(&callback_wrapper2)));
593
594 callback1.reset();
595 EXPECT_TRUE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
596 EXPECT_TRUE(base::StatisticsRecorder::have_active_callbacks());
597
598 callback2.reset();
599 EXPECT_FALSE(histogram->HasFlags(base::HistogramBase::kCallbackExists));
600 EXPECT_FALSE(base::StatisticsRecorder::have_active_callbacks());
601
602 histogram->Add(1);
603 base::RunLoop().RunUntilIdle();
604
605 EXPECT_FALSE(callback_wrapper1.called);
606 EXPECT_FALSE(callback_wrapper2.called);
607 }
608
609 // Check that callback is used.
TEST_P(StatisticsRecorderTest,CallbackUsedTest)610 TEST_P(StatisticsRecorderTest, CallbackUsedTest) {
611 test::TaskEnvironment task_environment;
612 {
613 HistogramBase* histogram = Histogram::FactoryGet(
614 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
615 EXPECT_TRUE(histogram);
616
617 CallbackCheckWrapper callback_wrapper;
618
619 auto callback = std::make_unique<
620 base::StatisticsRecorder::ScopedHistogramSampleObserver>(
621 "TestHistogram",
622 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
623 base::Unretained(&callback_wrapper)));
624
625 histogram->Add(1);
626 base::RunLoop().RunUntilIdle();
627
628 EXPECT_TRUE(callback_wrapper.called);
629 EXPECT_STREQ(callback_wrapper.last_histogram_name, "TestHistogram");
630 EXPECT_EQ(callback_wrapper.last_name_hash, HashMetricName("TestHistogram"));
631 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
632 }
633
634 {
635 HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
636 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
637
638 CallbackCheckWrapper callback_wrapper;
639
640 auto callback = std::make_unique<
641 base::StatisticsRecorder::ScopedHistogramSampleObserver>(
642 "TestLinearHistogram",
643 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
644 base::Unretained(&callback_wrapper)));
645
646 linear_histogram->Add(1);
647 base::RunLoop().RunUntilIdle();
648
649 EXPECT_TRUE(callback_wrapper.called);
650 EXPECT_STREQ(callback_wrapper.last_histogram_name, "TestLinearHistogram");
651 EXPECT_EQ(callback_wrapper.last_name_hash,
652 HashMetricName("TestLinearHistogram"));
653 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
654 }
655
656 {
657 std::vector<int> custom_ranges;
658 custom_ranges.push_back(1);
659 custom_ranges.push_back(5);
660 HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
661 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
662
663 CallbackCheckWrapper callback_wrapper;
664
665 auto callback = std::make_unique<
666 base::StatisticsRecorder::ScopedHistogramSampleObserver>(
667 "TestCustomHistogram",
668 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
669 base::Unretained(&callback_wrapper)));
670
671 custom_histogram->Add(1);
672 base::RunLoop().RunUntilIdle();
673
674 EXPECT_TRUE(callback_wrapper.called);
675 EXPECT_STREQ(callback_wrapper.last_histogram_name, "TestCustomHistogram");
676 EXPECT_EQ(callback_wrapper.last_name_hash,
677 HashMetricName("TestCustomHistogram"));
678 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
679 }
680
681 {
682 HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
683 "TestSparseHistogram", HistogramBase::kNoFlags);
684
685 CallbackCheckWrapper callback_wrapper;
686
687 auto callback = std::make_unique<
688 base::StatisticsRecorder::ScopedHistogramSampleObserver>(
689 "TestSparseHistogram",
690 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
691 base::Unretained(&callback_wrapper)));
692
693 custom_histogram->Add(1);
694 base::RunLoop().RunUntilIdle();
695
696 EXPECT_TRUE(callback_wrapper.called);
697 EXPECT_STREQ(callback_wrapper.last_histogram_name, "TestSparseHistogram");
698 EXPECT_EQ(callback_wrapper.last_name_hash,
699 HashMetricName("TestSparseHistogram"));
700 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
701 }
702 }
703
704 // Check that setting a callback before the histogram exists works.
TEST_P(StatisticsRecorderTest,CallbackUsedBeforeHistogramCreatedTest)705 TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
706 test::TaskEnvironment task_environment;
707 CallbackCheckWrapper callback_wrapper;
708
709 auto callback =
710 std::make_unique<base::StatisticsRecorder::ScopedHistogramSampleObserver>(
711 "TestHistogram",
712 base::BindRepeating(&CallbackCheckWrapper::OnHistogramChanged,
713 base::Unretained(&callback_wrapper)));
714
715 HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
716 HistogramBase::kNoFlags);
717 EXPECT_TRUE(histogram);
718 histogram->Add(1);
719 base::RunLoop().RunUntilIdle();
720
721 EXPECT_TRUE(callback_wrapper.called);
722 EXPECT_STREQ(callback_wrapper.last_histogram_name, "TestHistogram");
723 EXPECT_EQ(callback_wrapper.last_name_hash, HashMetricName("TestHistogram"));
724 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
725 }
726
TEST_P(StatisticsRecorderTest,GlobalCallbackCalled)727 TEST_P(StatisticsRecorderTest, GlobalCallbackCalled) {
728 HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
729 HistogramBase::kNoFlags);
730 EXPECT_TRUE(histogram);
731
732 // This is a static rather than passing the variable to the lambda
733 // as a reference capture, as only stateless lambdas can be cast to a raw
734 // function pointer.
735 static size_t callback_callcount;
736 callback_callcount = 0;
737 auto callback = [](const char* histogram_name, uint64_t name_hash,
738 HistogramBase::Sample sample) {
739 EXPECT_STREQ(histogram_name, "TestHistogram");
740 EXPECT_EQ(sample, 1);
741 ++callback_callcount;
742 };
743
744 base::StatisticsRecorder::SetGlobalSampleCallback(callback);
745
746 // Test that adding a histogram sample calls our callback.
747 histogram->Add(1);
748 EXPECT_EQ(callback_callcount, 1u);
749
750 // Test that the callback gets correctly unregistered.
751 base::StatisticsRecorder::SetGlobalSampleCallback(nullptr);
752 histogram->Add(2);
753 EXPECT_EQ(callback_callcount, 1u);
754 }
755
TEST_P(StatisticsRecorderTest,LogOnShutdownNotInitialized)756 TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) {
757 ResetVLogInitialized();
758 logging::SetMinLogLevel(logging::LOGGING_WARNING);
759 InitializeStatisticsRecorder();
760 EXPECT_FALSE(VLOG_IS_ON(1));
761 EXPECT_FALSE(IsVLogInitialized());
762 InitLogOnShutdown();
763 EXPECT_FALSE(IsVLogInitialized());
764 }
765
TEST_P(StatisticsRecorderTest,LogOnShutdownInitializedExplicitly)766 TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) {
767 ResetVLogInitialized();
768 logging::SetMinLogLevel(logging::LOGGING_WARNING);
769 InitializeStatisticsRecorder();
770 EXPECT_FALSE(VLOG_IS_ON(1));
771 EXPECT_FALSE(IsVLogInitialized());
772 logging::SetMinLogLevel(logging::LOGGING_VERBOSE);
773 EXPECT_TRUE(VLOG_IS_ON(1));
774 InitLogOnShutdown();
775 EXPECT_TRUE(IsVLogInitialized());
776 }
777
TEST_P(StatisticsRecorderTest,LogOnShutdownInitialized)778 TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) {
779 ResetVLogInitialized();
780 logging::SetMinLogLevel(logging::LOGGING_VERBOSE);
781 InitializeStatisticsRecorder();
782 EXPECT_TRUE(VLOG_IS_ON(1));
783 EXPECT_TRUE(IsVLogInitialized());
784 }
785
786 class TestHistogramProvider : public StatisticsRecorder::HistogramProvider {
787 public:
TestHistogramProvider(PersistentHistogramAllocator * allocator)788 explicit TestHistogramProvider(PersistentHistogramAllocator* allocator)
789 : allocator_(std::move(allocator)) {
790 StatisticsRecorder::RegisterHistogramProvider(weak_factory_.GetWeakPtr());
791 }
792 TestHistogramProvider(const TestHistogramProvider&) = delete;
793 TestHistogramProvider& operator=(const TestHistogramProvider&) = delete;
794
MergeHistogramDeltas(bool async,OnceClosure done_callback)795 void MergeHistogramDeltas(bool async, OnceClosure done_callback) override {
796 PersistentHistogramAllocator::Iterator hist_iter(allocator_.get());
797 while (true) {
798 std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext();
799 if (!histogram)
800 break;
801 allocator_->MergeHistogramDeltaToStatisticsRecorder(histogram.get());
802 }
803 std::move(done_callback).Run();
804 }
805
806 private:
807 const raw_ptr<PersistentHistogramAllocator> allocator_;
808 WeakPtrFactory<TestHistogramProvider> weak_factory_{this};
809 };
810
TEST_P(StatisticsRecorderTest,ImportHistogramsTest)811 TEST_P(StatisticsRecorderTest, ImportHistogramsTest) {
812 // Create a second SR to create some histograms for later import.
813 std::unique_ptr<StatisticsRecorder> temp_sr =
814 StatisticsRecorder::CreateTemporaryForTesting();
815
816 // Extract any existing global allocator so a new one can be created.
817 GlobalHistogramAllocator* old_allocator =
818 GlobalHistogramAllocator::ReleaseForTesting();
819
820 // Create a histogram inside a new allocator for testing.
821 GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
822 HistogramBase* histogram = LinearHistogram::FactoryGet("Foo", 1, 10, 11, 0);
823 histogram->Add(3);
824
825 // Undo back to the starting point.
826 GlobalHistogramAllocator* new_allocator =
827 GlobalHistogramAllocator::ReleaseForTesting();
828 GlobalHistogramAllocator::Set(old_allocator);
829 temp_sr.reset();
830
831 // Create a provider that can supply histograms to the current SR.
832 TestHistogramProvider provider(new_allocator);
833
834 // Verify that the created histogram is no longer known.
835 ASSERT_FALSE(StatisticsRecorder::FindHistogram(histogram->histogram_name()));
836
837 // Now test that it merges.
838 StatisticsRecorder::ImportProvidedHistogramsSync();
839 HistogramBase* found =
840 StatisticsRecorder::FindHistogram(histogram->histogram_name());
841 ASSERT_TRUE(found);
842 EXPECT_NE(histogram, found);
843 std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples();
844 EXPECT_EQ(1, snapshot->TotalCount());
845 EXPECT_EQ(1, snapshot->GetCount(3));
846
847 // Finally, verify that updates can also be merged.
848 histogram->Add(3);
849 histogram->Add(5);
850 StatisticsRecorder::ImportProvidedHistogramsSync();
851 snapshot = found->SnapshotSamples();
852 EXPECT_EQ(3, snapshot->TotalCount());
853 EXPECT_EQ(2, snapshot->GetCount(3));
854 EXPECT_EQ(1, snapshot->GetCount(5));
855 }
856
TEST_P(StatisticsRecorderTest,RecordHistogramChecker)857 TEST_P(StatisticsRecorderTest, RecordHistogramChecker) {
858 // Before record checker is set all histograms should be recorded.
859 EXPECT_TRUE(StatisticsRecorder::ShouldRecordHistogram(1));
860 EXPECT_TRUE(StatisticsRecorder::ShouldRecordHistogram(2));
861
862 auto record_checker = std::make_unique<OddRecordHistogramChecker>();
863 StatisticsRecorder::SetRecordChecker(std::move(record_checker));
864 EXPECT_TRUE(StatisticsRecorder::ShouldRecordHistogram(1));
865 EXPECT_FALSE(StatisticsRecorder::ShouldRecordHistogram(2));
866 }
867
868 } // namespace base
869