• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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