| 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 |