1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/metrics/statistics_recorder.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/json/json_reader.h"
14 #include "base/logging.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/metrics/persistent_histogram_allocator.h"
18 #include "base/metrics/sparse_histogram.h"
19 #include "base/values.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace {
23
24 // Class to make sure any manipulations we do to the min log level are
25 // contained (i.e., do not affect other unit tests).
26 class LogStateSaver {
27 public:
LogStateSaver()28 LogStateSaver() : old_min_log_level_(logging::GetMinLogLevel()) {}
29
~LogStateSaver()30 ~LogStateSaver() {
31 logging::SetMinLogLevel(old_min_log_level_);
32 logging::SetLogAssertHandler(nullptr);
33 }
34
35 private:
36 int old_min_log_level_;
37
38 DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
39 };
40
41 } // namespace
42
43 namespace base {
44
45 class StatisticsRecorderTest : public testing::TestWithParam<bool> {
46 protected:
47 const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB
48
StatisticsRecorderTest()49 StatisticsRecorderTest() : use_persistent_histogram_allocator_(GetParam()) {
50 // Get this first so it never gets created in persistent storage and will
51 // not appear in the StatisticsRecorder after it is re-initialized.
52 PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
53
54 // Each test will have a clean state (no Histogram / BucketRanges
55 // registered).
56 InitializeStatisticsRecorder();
57
58 // Use persistent memory for histograms if so indicated by test parameter.
59 if (use_persistent_histogram_allocator_) {
60 GlobalHistogramAllocator::CreateWithLocalMemory(
61 kAllocatorMemorySize, 0, "StatisticsRecorderTest");
62 }
63 }
64
~StatisticsRecorderTest()65 ~StatisticsRecorderTest() override {
66 GlobalHistogramAllocator::ReleaseForTesting();
67 UninitializeStatisticsRecorder();
68 }
69
InitializeStatisticsRecorder()70 void InitializeStatisticsRecorder() {
71 DCHECK(!statistics_recorder_);
72 StatisticsRecorder::UninitializeForTesting();
73 statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
74 }
75
UninitializeStatisticsRecorder()76 void UninitializeStatisticsRecorder() {
77 statistics_recorder_.reset();
78 StatisticsRecorder::UninitializeForTesting();
79 }
80
CreateHistogram(const std::string & name,HistogramBase::Sample min,HistogramBase::Sample max,size_t bucket_count)81 Histogram* CreateHistogram(const std::string& name,
82 HistogramBase::Sample min,
83 HistogramBase::Sample max,
84 size_t bucket_count) {
85 BucketRanges* ranges = new BucketRanges(bucket_count + 1);
86 Histogram::InitializeBucketRanges(min, max, ranges);
87 const BucketRanges* registered_ranges =
88 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
89 return new Histogram(name, min, max, registered_ranges);
90 }
91
DeleteHistogram(HistogramBase * histogram)92 void DeleteHistogram(HistogramBase* histogram) {
93 delete histogram;
94 }
95
CountIterableHistograms(StatisticsRecorder::HistogramIterator * iter)96 int CountIterableHistograms(StatisticsRecorder::HistogramIterator* iter) {
97 int count = 0;
98 for (; *iter != StatisticsRecorder::end(); ++*iter) {
99 ++count;
100 }
101 return count;
102 }
103
InitLogOnShutdown()104 void InitLogOnShutdown() {
105 DCHECK(statistics_recorder_);
106 statistics_recorder_->InitLogOnShutdownWithoutLock();
107 }
108
VLogInitialized()109 bool VLogInitialized() {
110 DCHECK(statistics_recorder_);
111 return statistics_recorder_->vlog_initialized_;
112 }
113
114 const bool use_persistent_histogram_allocator_;
115
116 std::unique_ptr<StatisticsRecorder> statistics_recorder_;
117 std::unique_ptr<GlobalHistogramAllocator> old_global_allocator_;
118
119 private:
120 LogStateSaver log_state_saver_;
121
122 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorderTest);
123 };
124
125 // Run all HistogramTest cases with both heap and persistent memory.
126 INSTANTIATE_TEST_CASE_P(Allocator, StatisticsRecorderTest, testing::Bool());
127
TEST_P(StatisticsRecorderTest,NotInitialized)128 TEST_P(StatisticsRecorderTest, NotInitialized) {
129 UninitializeStatisticsRecorder();
130
131 ASSERT_FALSE(StatisticsRecorder::IsActive());
132
133 StatisticsRecorder::Histograms registered_histograms;
134 std::vector<const BucketRanges*> registered_ranges;
135
136 StatisticsRecorder::GetHistograms(®istered_histograms);
137 EXPECT_EQ(0u, registered_histograms.size());
138
139 Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
140
141 // When StatisticsRecorder is not initialized, register is a noop.
142 EXPECT_EQ(histogram,
143 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
144 // Manually delete histogram that was not registered.
145 DeleteHistogram(histogram);
146
147 // RegisterOrDeleteDuplicateRanges is a no-op.
148 BucketRanges* ranges = new BucketRanges(3);
149 ranges->ResetChecksum();
150 EXPECT_EQ(ranges,
151 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
152 StatisticsRecorder::GetBucketRanges(®istered_ranges);
153 EXPECT_EQ(0u, registered_ranges.size());
154 }
155
TEST_P(StatisticsRecorderTest,RegisterBucketRanges)156 TEST_P(StatisticsRecorderTest, RegisterBucketRanges) {
157 std::vector<const BucketRanges*> registered_ranges;
158
159 BucketRanges* ranges1 = new BucketRanges(3);
160 ranges1->ResetChecksum();
161 BucketRanges* ranges2 = new BucketRanges(4);
162 ranges2->ResetChecksum();
163
164 // Register new ranges.
165 EXPECT_EQ(ranges1,
166 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
167 EXPECT_EQ(ranges2,
168 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
169 StatisticsRecorder::GetBucketRanges(®istered_ranges);
170 ASSERT_EQ(2u, registered_ranges.size());
171
172 // Register some ranges again.
173 EXPECT_EQ(ranges1,
174 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
175 registered_ranges.clear();
176 StatisticsRecorder::GetBucketRanges(®istered_ranges);
177 ASSERT_EQ(2u, registered_ranges.size());
178 // Make sure the ranges is still the one we know.
179 ASSERT_EQ(3u, ranges1->size());
180 EXPECT_EQ(0, ranges1->range(0));
181 EXPECT_EQ(0, ranges1->range(1));
182 EXPECT_EQ(0, ranges1->range(2));
183
184 // Register ranges with same values.
185 BucketRanges* ranges3 = new BucketRanges(3);
186 ranges3->ResetChecksum();
187 EXPECT_EQ(ranges1, // returning ranges1
188 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
189 registered_ranges.clear();
190 StatisticsRecorder::GetBucketRanges(®istered_ranges);
191 ASSERT_EQ(2u, registered_ranges.size());
192 }
193
TEST_P(StatisticsRecorderTest,RegisterHistogram)194 TEST_P(StatisticsRecorderTest, RegisterHistogram) {
195 // Create a Histogram that was not registered.
196 Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
197
198 StatisticsRecorder::Histograms registered_histograms;
199 StatisticsRecorder::GetHistograms(®istered_histograms);
200 EXPECT_EQ(0u, registered_histograms.size());
201
202 // Register the Histogram.
203 EXPECT_EQ(histogram,
204 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
205 StatisticsRecorder::GetHistograms(®istered_histograms);
206 EXPECT_EQ(1u, registered_histograms.size());
207
208 // Register the same Histogram again.
209 EXPECT_EQ(histogram,
210 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
211 registered_histograms.clear();
212 StatisticsRecorder::GetHistograms(®istered_histograms);
213 EXPECT_EQ(1u, registered_histograms.size());
214 }
215
TEST_P(StatisticsRecorderTest,FindHistogram)216 TEST_P(StatisticsRecorderTest, FindHistogram) {
217 HistogramBase* histogram1 = Histogram::FactoryGet(
218 "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
219 HistogramBase* histogram2 = Histogram::FactoryGet(
220 "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags);
221
222 EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
223 EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
224 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
225
226 // Create a new global allocator using the same memory as the old one. Any
227 // old one is kept around so the memory doesn't get released.
228 old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting();
229 if (use_persistent_histogram_allocator_) {
230 GlobalHistogramAllocator::CreateWithPersistentMemory(
231 const_cast<void*>(old_global_allocator_->data()),
232 old_global_allocator_->length(), 0, old_global_allocator_->Id(),
233 old_global_allocator_->Name());
234 }
235
236 // Reset statistics-recorder to validate operation from a clean start.
237 UninitializeStatisticsRecorder();
238 InitializeStatisticsRecorder();
239
240 if (use_persistent_histogram_allocator_) {
241 EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram1"));
242 EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram2"));
243 } else {
244 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram1"));
245 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram2"));
246 }
247 EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
248 }
249
TEST_P(StatisticsRecorderTest,GetSnapshot)250 TEST_P(StatisticsRecorderTest, GetSnapshot) {
251 Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
252 Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
253 Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
254
255 StatisticsRecorder::Histograms snapshot;
256 StatisticsRecorder::GetSnapshot("Test", &snapshot);
257 EXPECT_EQ(3u, snapshot.size());
258
259 snapshot.clear();
260 StatisticsRecorder::GetSnapshot("1", &snapshot);
261 EXPECT_EQ(1u, snapshot.size());
262
263 snapshot.clear();
264 StatisticsRecorder::GetSnapshot("hello", &snapshot);
265 EXPECT_EQ(0u, snapshot.size());
266 }
267
TEST_P(StatisticsRecorderTest,RegisterHistogramWithFactoryGet)268 TEST_P(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
269 StatisticsRecorder::Histograms registered_histograms;
270
271 StatisticsRecorder::GetHistograms(®istered_histograms);
272 ASSERT_EQ(0u, registered_histograms.size());
273
274 // Create a histogram.
275 HistogramBase* histogram = Histogram::FactoryGet(
276 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
277 registered_histograms.clear();
278 StatisticsRecorder::GetHistograms(®istered_histograms);
279 EXPECT_EQ(1u, registered_histograms.size());
280
281 // Get an existing histogram.
282 HistogramBase* histogram2 = Histogram::FactoryGet(
283 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
284 registered_histograms.clear();
285 StatisticsRecorder::GetHistograms(®istered_histograms);
286 EXPECT_EQ(1u, registered_histograms.size());
287 EXPECT_EQ(histogram, histogram2);
288
289 // Create a LinearHistogram.
290 histogram = LinearHistogram::FactoryGet(
291 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
292 registered_histograms.clear();
293 StatisticsRecorder::GetHistograms(®istered_histograms);
294 EXPECT_EQ(2u, registered_histograms.size());
295
296 // Create a BooleanHistogram.
297 histogram = BooleanHistogram::FactoryGet(
298 "TestBooleanHistogram", HistogramBase::kNoFlags);
299 registered_histograms.clear();
300 StatisticsRecorder::GetHistograms(®istered_histograms);
301 EXPECT_EQ(3u, registered_histograms.size());
302
303 // Create a CustomHistogram.
304 std::vector<int> custom_ranges;
305 custom_ranges.push_back(1);
306 custom_ranges.push_back(5);
307 histogram = CustomHistogram::FactoryGet(
308 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
309 registered_histograms.clear();
310 StatisticsRecorder::GetHistograms(®istered_histograms);
311 EXPECT_EQ(4u, registered_histograms.size());
312 }
313
TEST_P(StatisticsRecorderTest,RegisterHistogramWithMacros)314 TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
315 // Macros cache pointers and so tests that use them can only be run once.
316 // Stop immediately if this test has run previously.
317 static bool already_run = false;
318 if (already_run)
319 return;
320 already_run = true;
321
322 StatisticsRecorder::Histograms registered_histograms;
323
324 HistogramBase* histogram = Histogram::FactoryGet(
325 "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags);
326
327 // The histogram we got from macro is the same as from FactoryGet.
328 LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
329 registered_histograms.clear();
330 StatisticsRecorder::GetHistograms(®istered_histograms);
331 ASSERT_EQ(1u, registered_histograms.size());
332 EXPECT_EQ(histogram, registered_histograms[0]);
333
334 LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
335 LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
336
337 registered_histograms.clear();
338 StatisticsRecorder::GetHistograms(®istered_histograms);
339 EXPECT_EQ(3u, registered_histograms.size());
340 }
341
TEST_P(StatisticsRecorderTest,BucketRangesSharing)342 TEST_P(StatisticsRecorderTest, BucketRangesSharing) {
343 std::vector<const BucketRanges*> ranges;
344 StatisticsRecorder::GetBucketRanges(&ranges);
345 EXPECT_EQ(0u, ranges.size());
346
347 Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
348 Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
349
350 StatisticsRecorder::GetBucketRanges(&ranges);
351 EXPECT_EQ(1u, ranges.size());
352
353 Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
354
355 ranges.clear();
356 StatisticsRecorder::GetBucketRanges(&ranges);
357 EXPECT_EQ(2u, ranges.size());
358 }
359
TEST_P(StatisticsRecorderTest,ToJSON)360 TEST_P(StatisticsRecorderTest, ToJSON) {
361 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
362 ->Add(30);
363 Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
364 ->Add(40);
365 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
366 ->Add(30);
367 Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
368 ->Add(40);
369
370 std::string json(StatisticsRecorder::ToJSON(std::string()));
371
372 // Check for valid JSON.
373 std::unique_ptr<Value> root = JSONReader::Read(json);
374 ASSERT_TRUE(root.get());
375
376 DictionaryValue* root_dict = NULL;
377 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
378
379 // No query should be set.
380 ASSERT_FALSE(root_dict->HasKey("query"));
381
382 ListValue* histogram_list = NULL;
383 ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
384 ASSERT_EQ(2u, histogram_list->GetSize());
385
386 // Examine the first histogram.
387 DictionaryValue* histogram_dict = NULL;
388 ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
389
390 int sample_count;
391 ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
392 EXPECT_EQ(2, sample_count);
393
394 // Test the query filter.
395 std::string query("TestHistogram2");
396 json = StatisticsRecorder::ToJSON(query);
397
398 root = JSONReader::Read(json);
399 ASSERT_TRUE(root.get());
400 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
401
402 std::string query_value;
403 ASSERT_TRUE(root_dict->GetString("query", &query_value));
404 EXPECT_EQ(query, query_value);
405
406 ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
407 ASSERT_EQ(1u, histogram_list->GetSize());
408
409 ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
410
411 std::string histogram_name;
412 ASSERT_TRUE(histogram_dict->GetString("name", &histogram_name));
413 EXPECT_EQ("TestHistogram2", histogram_name);
414
415 json.clear();
416 UninitializeStatisticsRecorder();
417
418 // No data should be returned.
419 json = StatisticsRecorder::ToJSON(query);
420 EXPECT_TRUE(json.empty());
421 }
422
TEST_P(StatisticsRecorderTest,IterationTest)423 TEST_P(StatisticsRecorderTest, IterationTest) {
424 Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags);
425 Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags);
426
427 StatisticsRecorder::HistogramIterator i1 = StatisticsRecorder::begin(true);
428 EXPECT_EQ(2, CountIterableHistograms(&i1));
429
430 StatisticsRecorder::HistogramIterator i2 = StatisticsRecorder::begin(false);
431 EXPECT_EQ(use_persistent_histogram_allocator_ ? 0 : 2,
432 CountIterableHistograms(&i2));
433
434 // Create a new global allocator using the same memory as the old one. Any
435 // old one is kept around so the memory doesn't get released.
436 old_global_allocator_ = 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 StatisticsRecorder::HistogramIterator i3 = StatisticsRecorder::begin(true);
449 EXPECT_EQ(use_persistent_histogram_allocator_ ? 2 : 0,
450 CountIterableHistograms(&i3));
451
452 StatisticsRecorder::HistogramIterator i4 = StatisticsRecorder::begin(false);
453 EXPECT_EQ(0, CountIterableHistograms(&i4));
454 }
455
456 namespace {
457
458 // CallbackCheckWrapper is simply a convenient way to check and store that
459 // a callback was actually run.
460 struct CallbackCheckWrapper {
CallbackCheckWrapperbase::__anon3d7c4c580211::CallbackCheckWrapper461 CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
462
OnHistogramChangedbase::__anon3d7c4c580211::CallbackCheckWrapper463 void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
464 called = true;
465 last_histogram_value = histogram_value;
466 }
467
468 bool called;
469 base::HistogramBase::Sample last_histogram_value;
470 };
471
472 } // namespace
473
474 // Check that you can't overwrite the callback with another.
TEST_P(StatisticsRecorderTest,SetCallbackFailsWithoutHistogramTest)475 TEST_P(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
476 CallbackCheckWrapper callback_wrapper;
477
478 bool result = base::StatisticsRecorder::SetCallback(
479 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
480 base::Unretained(&callback_wrapper)));
481 EXPECT_TRUE(result);
482
483 result = base::StatisticsRecorder::SetCallback(
484 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
485 base::Unretained(&callback_wrapper)));
486 EXPECT_FALSE(result);
487 }
488
489 // Check that you can't overwrite the callback with another.
TEST_P(StatisticsRecorderTest,SetCallbackFailsWithHistogramTest)490 TEST_P(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
491 HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
492 HistogramBase::kNoFlags);
493 EXPECT_TRUE(histogram);
494
495 CallbackCheckWrapper callback_wrapper;
496
497 bool result = base::StatisticsRecorder::SetCallback(
498 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
499 base::Unretained(&callback_wrapper)));
500 EXPECT_TRUE(result);
501 EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
502 base::HistogramBase::kCallbackExists);
503
504 result = base::StatisticsRecorder::SetCallback(
505 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
506 base::Unretained(&callback_wrapper)));
507 EXPECT_FALSE(result);
508 EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
509 base::HistogramBase::kCallbackExists);
510
511 histogram->Add(1);
512
513 EXPECT_TRUE(callback_wrapper.called);
514 }
515
516 // Check that you can't overwrite the callback with another.
TEST_P(StatisticsRecorderTest,ClearCallbackSuceedsWithHistogramTest)517 TEST_P(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
518 HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
519 HistogramBase::kNoFlags);
520 EXPECT_TRUE(histogram);
521
522 CallbackCheckWrapper callback_wrapper;
523
524 bool result = base::StatisticsRecorder::SetCallback(
525 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
526 base::Unretained(&callback_wrapper)));
527 EXPECT_TRUE(result);
528 EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
529 base::HistogramBase::kCallbackExists);
530
531 base::StatisticsRecorder::ClearCallback("TestHistogram");
532 EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
533
534 histogram->Add(1);
535
536 EXPECT_FALSE(callback_wrapper.called);
537 }
538
539 // Check that callback is used.
TEST_P(StatisticsRecorderTest,CallbackUsedTest)540 TEST_P(StatisticsRecorderTest, CallbackUsedTest) {
541 {
542 HistogramBase* histogram = Histogram::FactoryGet(
543 "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
544 EXPECT_TRUE(histogram);
545
546 CallbackCheckWrapper callback_wrapper;
547
548 base::StatisticsRecorder::SetCallback(
549 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
550 base::Unretained(&callback_wrapper)));
551
552 histogram->Add(1);
553
554 EXPECT_TRUE(callback_wrapper.called);
555 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
556 }
557
558 {
559 HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
560 "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
561
562 CallbackCheckWrapper callback_wrapper;
563
564 base::StatisticsRecorder::SetCallback(
565 "TestLinearHistogram",
566 base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
567 base::Unretained(&callback_wrapper)));
568
569 linear_histogram->Add(1);
570
571 EXPECT_TRUE(callback_wrapper.called);
572 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
573 }
574
575 {
576 std::vector<int> custom_ranges;
577 custom_ranges.push_back(1);
578 custom_ranges.push_back(5);
579 HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
580 "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
581
582 CallbackCheckWrapper callback_wrapper;
583
584 base::StatisticsRecorder::SetCallback(
585 "TestCustomHistogram",
586 base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
587 base::Unretained(&callback_wrapper)));
588
589 custom_histogram->Add(1);
590
591 EXPECT_TRUE(callback_wrapper.called);
592 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
593 }
594
595 {
596 HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
597 "TestSparseHistogram", HistogramBase::kNoFlags);
598
599 CallbackCheckWrapper callback_wrapper;
600
601 base::StatisticsRecorder::SetCallback(
602 "TestSparseHistogram",
603 base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
604 base::Unretained(&callback_wrapper)));
605
606 custom_histogram->Add(1);
607
608 EXPECT_TRUE(callback_wrapper.called);
609 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
610 }
611 }
612
613 // Check that setting a callback before the histogram exists works.
TEST_P(StatisticsRecorderTest,CallbackUsedBeforeHistogramCreatedTest)614 TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
615 CallbackCheckWrapper callback_wrapper;
616
617 base::StatisticsRecorder::SetCallback(
618 "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
619 base::Unretained(&callback_wrapper)));
620
621 HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
622 HistogramBase::kNoFlags);
623 EXPECT_TRUE(histogram);
624 histogram->Add(1);
625
626 EXPECT_TRUE(callback_wrapper.called);
627 EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
628 }
629
TEST_P(StatisticsRecorderTest,LogOnShutdownNotInitialized)630 TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) {
631 UninitializeStatisticsRecorder();
632 logging::SetMinLogLevel(logging::LOG_WARNING);
633 InitializeStatisticsRecorder();
634 EXPECT_FALSE(VLOG_IS_ON(1));
635 EXPECT_FALSE(VLogInitialized());
636 InitLogOnShutdown();
637 EXPECT_FALSE(VLogInitialized());
638 }
639
TEST_P(StatisticsRecorderTest,LogOnShutdownInitializedExplicitly)640 TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) {
641 UninitializeStatisticsRecorder();
642 logging::SetMinLogLevel(logging::LOG_WARNING);
643 InitializeStatisticsRecorder();
644 EXPECT_FALSE(VLOG_IS_ON(1));
645 EXPECT_FALSE(VLogInitialized());
646 logging::SetMinLogLevel(logging::LOG_VERBOSE);
647 EXPECT_TRUE(VLOG_IS_ON(1));
648 InitLogOnShutdown();
649 EXPECT_TRUE(VLogInitialized());
650 }
651
TEST_P(StatisticsRecorderTest,LogOnShutdownInitialized)652 TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) {
653 UninitializeStatisticsRecorder();
654 logging::SetMinLogLevel(logging::LOG_VERBOSE);
655 InitializeStatisticsRecorder();
656 EXPECT_TRUE(VLOG_IS_ON(1));
657 EXPECT_TRUE(VLogInitialized());
658 }
659
660 class TestHistogramProvider : public StatisticsRecorder::HistogramProvider {
661 public:
TestHistogramProvider(std::unique_ptr<PersistentHistogramAllocator> allocator)662 TestHistogramProvider(std::unique_ptr<PersistentHistogramAllocator> allocator)
663 : allocator_(std::move(allocator)), weak_factory_(this) {
664 StatisticsRecorder::RegisterHistogramProvider(weak_factory_.GetWeakPtr());
665 }
666
MergeHistogramDeltas()667 void MergeHistogramDeltas() override {
668 PersistentHistogramAllocator::Iterator hist_iter(allocator_.get());
669 while (true) {
670 std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext();
671 if (!histogram)
672 break;
673 allocator_->MergeHistogramDeltaToStatisticsRecorder(histogram.get());
674 }
675 }
676
677 private:
678 std::unique_ptr<PersistentHistogramAllocator> allocator_;
679 WeakPtrFactory<TestHistogramProvider> weak_factory_;
680
681 DISALLOW_COPY_AND_ASSIGN(TestHistogramProvider);
682 };
683
TEST_P(StatisticsRecorderTest,ImportHistogramsTest)684 TEST_P(StatisticsRecorderTest, ImportHistogramsTest) {
685 // Create a second SR to create some histograms for later import.
686 std::unique_ptr<StatisticsRecorder> temp_sr =
687 StatisticsRecorder::CreateTemporaryForTesting();
688
689 // Extract any existing global allocator so a new one can be created.
690 std::unique_ptr<GlobalHistogramAllocator> old_allocator =
691 GlobalHistogramAllocator::ReleaseForTesting();
692
693 // Create a histogram inside a new allocator for testing.
694 GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
695 HistogramBase* histogram = LinearHistogram::FactoryGet("Foo", 1, 10, 11, 0);
696 histogram->Add(3);
697
698 // Undo back to the starting point.
699 std::unique_ptr<GlobalHistogramAllocator> new_allocator =
700 GlobalHistogramAllocator::ReleaseForTesting();
701 GlobalHistogramAllocator::Set(std::move(old_allocator));
702 temp_sr.reset();
703
704 // Create a provider that can supply histograms to the current SR.
705 TestHistogramProvider provider(std::move(new_allocator));
706
707 // Verify that the created histogram is no longer known.
708 ASSERT_FALSE(StatisticsRecorder::FindHistogram(histogram->histogram_name()));
709
710 // Now test that it merges.
711 StatisticsRecorder::ImportProvidedHistograms();
712 HistogramBase* found =
713 StatisticsRecorder::FindHistogram(histogram->histogram_name());
714 ASSERT_TRUE(found);
715 EXPECT_NE(histogram, found);
716 std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples();
717 EXPECT_EQ(1, snapshot->TotalCount());
718 EXPECT_EQ(1, snapshot->GetCount(3));
719
720 // Finally, verify that updates can also be merged.
721 histogram->Add(3);
722 histogram->Add(5);
723 StatisticsRecorder::ImportProvidedHistograms();
724 snapshot = found->SnapshotSamples();
725 EXPECT_EQ(3, snapshot->TotalCount());
726 EXPECT_EQ(2, snapshot->GetCount(3));
727 EXPECT_EQ(1, snapshot->GetCount(5));
728 }
729
730 } // namespace base
731