OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/persistent_histogram_allocator.h" | 5 #include "base/metrics/persistent_histogram_allocator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 PersistentMemoryAllocator::Reference counts_ref; | 104 PersistentMemoryAllocator::Reference counts_ref; |
105 HistogramSamples::Metadata samples_metadata; | 105 HistogramSamples::Metadata samples_metadata; |
106 HistogramSamples::Metadata logged_metadata; | 106 HistogramSamples::Metadata logged_metadata; |
107 | 107 |
108 // Space for the histogram name will be added during the actual allocation | 108 // Space for the histogram name will be added during the actual allocation |
109 // request. This must be the last field of the structure. A zero-size array | 109 // request. This must be the last field of the structure. A zero-size array |
110 // or a "flexible" array would be preferred but is not (yet) valid C++. | 110 // or a "flexible" array would be preferred but is not (yet) valid C++. |
111 char name[1]; | 111 char name[1]; |
112 }; | 112 }; |
113 | 113 |
| 114 PersistentHistogramAllocator::Iterator::Iterator( |
| 115 PersistentHistogramAllocator* allocator) |
| 116 : allocator_(allocator), memory_iter_(allocator->memory_allocator()) {} |
| 117 |
| 118 std::unique_ptr<HistogramBase> |
| 119 PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) { |
| 120 PersistentMemoryAllocator::Reference ref; |
| 121 while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) { |
| 122 if (ref != ignore) |
| 123 return allocator_->GetHistogram(ref); |
| 124 } |
| 125 return nullptr; |
| 126 } |
| 127 |
114 PersistentHistogramAllocator::PersistentHistogramAllocator( | 128 PersistentHistogramAllocator::PersistentHistogramAllocator( |
115 std::unique_ptr<PersistentMemoryAllocator> memory) | 129 std::unique_ptr<PersistentMemoryAllocator> memory) |
116 : memory_allocator_(std::move(memory)) {} | 130 : memory_allocator_(std::move(memory)) {} |
117 | 131 |
118 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} | 132 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} |
119 | 133 |
120 void PersistentHistogramAllocator::CreateIterator(Iterator* iter) { | |
121 memory_allocator_->CreateIterator(&iter->memory_iter); | |
122 } | |
123 | |
124 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { | 134 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { |
125 memory_allocator_->CreateTrackingHistograms(name); | 135 memory_allocator_->CreateTrackingHistograms(name); |
126 } | 136 } |
127 | 137 |
128 void PersistentHistogramAllocator::UpdateTrackingHistograms() { | 138 void PersistentHistogramAllocator::UpdateTrackingHistograms() { |
129 memory_allocator_->UpdateTrackingHistograms(); | 139 memory_allocator_->UpdateTrackingHistograms(); |
130 } | 140 } |
131 | 141 |
132 // static | 142 // static |
133 HistogramBase* | 143 HistogramBase* |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 size_t length = memory_allocator_->GetAllocSize(ref); | 323 size_t length = memory_allocator_->GetAllocSize(ref); |
314 if (!histogram_data || | 324 if (!histogram_data || |
315 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { | 325 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { |
316 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); | 326 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); |
317 NOTREACHED(); | 327 NOTREACHED(); |
318 return nullptr; | 328 return nullptr; |
319 } | 329 } |
320 return CreateHistogram(histogram_data); | 330 return CreateHistogram(histogram_data); |
321 } | 331 } |
322 | 332 |
323 std::unique_ptr<HistogramBase> | |
324 PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter, | |
325 Reference ignore) { | |
326 PersistentMemoryAllocator::Reference ref; | |
327 uint32_t type_id; | |
328 while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter, | |
329 &type_id)) != 0) { | |
330 if (ref == ignore) | |
331 continue; | |
332 if (type_id == kTypeIdHistogram) | |
333 return GetHistogram(ref); | |
334 } | |
335 return nullptr; | |
336 } | |
337 | |
338 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, | 333 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, |
339 bool registered) { | 334 bool registered) { |
340 // If the created persistent histogram was registered then it needs to | 335 // If the created persistent histogram was registered then it needs to |
341 // be marked as "iterable" in order to be found by other processes. | 336 // be marked as "iterable" in order to be found by other processes. |
342 if (registered) | 337 if (registered) |
343 memory_allocator_->MakeIterable(ref); | 338 memory_allocator_->MakeIterable(ref); |
344 // If it wasn't registered then a race condition must have caused | 339 // If it wasn't registered then a race condition must have caused |
345 // two to be created. The allocator does not support releasing the | 340 // two to be created. The allocator does not support releasing the |
346 // acquired memory so just change the type to be empty. | 341 // acquired memory so just change the type to be empty. |
347 else | 342 else |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 GlobalHistogramAllocator::ReleaseForTesting() { | 531 GlobalHistogramAllocator::ReleaseForTesting() { |
537 GlobalHistogramAllocator* histogram_allocator = g_allocator; | 532 GlobalHistogramAllocator* histogram_allocator = g_allocator; |
538 if (!histogram_allocator) | 533 if (!histogram_allocator) |
539 return nullptr; | 534 return nullptr; |
540 PersistentMemoryAllocator* memory_allocator = | 535 PersistentMemoryAllocator* memory_allocator = |
541 histogram_allocator->memory_allocator(); | 536 histogram_allocator->memory_allocator(); |
542 | 537 |
543 // Before releasing the memory, it's necessary to have the Statistics- | 538 // Before releasing the memory, it's necessary to have the Statistics- |
544 // Recorder forget about the histograms contained therein; otherwise, | 539 // Recorder forget about the histograms contained therein; otherwise, |
545 // some operations will try to access them and the released memory. | 540 // some operations will try to access them and the released memory. |
546 PersistentMemoryAllocator::Iterator iter; | 541 PersistentMemoryAllocator::Iterator iter(memory_allocator); |
547 PersistentMemoryAllocator::Reference ref; | 542 PersistentMemoryAllocator::Reference ref; |
548 uint32_t type_id; | 543 while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) { |
549 memory_allocator->CreateIterator(&iter); | 544 PersistentHistogramData* histogram_data = |
550 while ((ref = memory_allocator->GetNextIterable(&iter, &type_id)) != 0) { | 545 memory_allocator->GetAsObject<PersistentHistogramData>( |
551 if (type_id == kTypeIdHistogram) { | 546 ref, kTypeIdHistogram); |
552 PersistentHistogramData* histogram_data = | 547 DCHECK(histogram_data); |
553 memory_allocator->GetAsObject<PersistentHistogramData>( | 548 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); |
554 ref, kTypeIdHistogram); | |
555 DCHECK(histogram_data); | |
556 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); | |
557 | 549 |
558 // If a test breaks here then a memory region containing a histogram | 550 // If a test breaks here then a memory region containing a histogram |
559 // actively used by this code is being released back to the test. | 551 // actively used by this code is being released back to the test. |
560 // If that memory segment were to be deleted, future calls to create | 552 // If that memory segment were to be deleted, future calls to create |
561 // persistent histograms would crash. To avoid this, have the test call | 553 // persistent histograms would crash. To avoid this, have the test call |
562 // the method GetCreateHistogramResultHistogram() *before* setting | 554 // the method GetCreateHistogramResultHistogram() *before* setting |
563 // the (temporary) memory allocator via SetGlobalAllocator() so that | 555 // the (temporary) memory allocator via SetGlobalAllocator() so that |
564 // histogram is instead allocated from the process heap. | 556 // histogram is instead allocated from the process heap. |
565 DCHECK_NE(kResultHistogram, histogram_data->name); | 557 DCHECK_NE(kResultHistogram, histogram_data->name); |
566 } | |
567 } | 558 } |
568 | 559 |
569 g_allocator = nullptr; | 560 g_allocator = nullptr; |
570 return WrapUnique(histogram_allocator); | 561 return WrapUnique(histogram_allocator); |
571 }; | 562 }; |
572 | 563 |
573 GlobalHistogramAllocator::GlobalHistogramAllocator( | 564 GlobalHistogramAllocator::GlobalHistogramAllocator( |
574 std::unique_ptr<PersistentMemoryAllocator> memory) | 565 std::unique_ptr<PersistentMemoryAllocator> memory) |
575 : PersistentHistogramAllocator(std::move(memory)) { | 566 : PersistentHistogramAllocator(std::move(memory)), |
576 CreateIterator(&import_iterator_); | 567 import_iterator_(this) {} |
577 } | |
578 | 568 |
579 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { | 569 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() { |
580 // Skip the import if it's the histogram that was last created. Should a | 570 // Skip the import if it's the histogram that was last created. Should a |
581 // race condition cause the "last created" to be overwritten before it | 571 // race condition cause the "last created" to be overwritten before it |
582 // is recognized here then the histogram will be created and be ignored | 572 // is recognized here then the histogram will be created and be ignored |
583 // when it is detected as a duplicate by the statistics-recorder. This | 573 // when it is detected as a duplicate by the statistics-recorder. This |
584 // simple check reduces the time of creating persistent histograms by | 574 // simple check reduces the time of creating persistent histograms by |
585 // about 40%. | 575 // about 40%. |
586 Reference record_to_ignore = last_created(); | 576 Reference record_to_ignore = last_created(); |
587 | 577 |
588 // There is no lock on this because it's expected to be called only by | 578 // There is no lock on this because it's expected to be called only by |
589 // the StatisticsRecorder which has its own lock. | 579 // the StatisticsRecorder which has its own lock. |
590 while (true) { | 580 while (true) { |
591 std::unique_ptr<HistogramBase> histogram = | 581 std::unique_ptr<HistogramBase> histogram = |
592 GetNextHistogramWithIgnore(&import_iterator_, record_to_ignore); | 582 import_iterator_.GetNextWithIgnore(record_to_ignore); |
593 if (!histogram) | 583 if (!histogram) |
594 break; | 584 break; |
595 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 585 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
596 } | 586 } |
597 } | 587 } |
598 | 588 |
599 } // namespace base | 589 } // namespace base |
OLD | NEW |