Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1911)

Side by Side Diff: base/metrics/persistent_histogram_allocator.cc

Issue 1803253002: Improved iterator for persistent memory allocator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@refactor-hp
Patch Set: rebased and fixed up a bit Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/lazy_instance.h" 7 #include "base/lazy_instance.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 PersistentMemoryAllocator::Reference counts_ref; 102 PersistentMemoryAllocator::Reference counts_ref;
103 HistogramSamples::Metadata samples_metadata; 103 HistogramSamples::Metadata samples_metadata;
104 HistogramSamples::Metadata logged_metadata; 104 HistogramSamples::Metadata logged_metadata;
105 105
106 // Space for the histogram name will be added during the actual allocation 106 // Space for the histogram name will be added during the actual allocation
107 // request. This must be the last field of the structure. A zero-size array 107 // request. This must be the last field of the structure. A zero-size array
108 // or a "flexible" array would be preferred but is not (yet) valid C++. 108 // or a "flexible" array would be preferred but is not (yet) valid C++.
109 char name[1]; 109 char name[1];
110 }; 110 };
111 111
112 PersistentHistogramAllocator::Iterator::Iterator(
113 PersistentHistogramAllocator* allocator)
114 : allocator_(allocator), memory_iter_(allocator->memory_allocator()) {}
115
116 scoped_ptr<HistogramBase>
117 PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
118 PersistentMemoryAllocator::Reference ref;
Ilya Sherman 2016/03/24 02:03:58 nit: s/PersistentMemoryAllocator::Reference/Refere
bcwhite 2016/03/24 14:22:34 PHA::Reference is implemented as a PMA::Reference
119 while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) {
120 if (ref != ignore)
121 return allocator_->GetHistogram(ref);
122 }
123 return nullptr;
124 }
125
112 PersistentHistogramAllocator::PersistentHistogramAllocator( 126 PersistentHistogramAllocator::PersistentHistogramAllocator(
113 scoped_ptr<PersistentMemoryAllocator> memory) 127 scoped_ptr<PersistentMemoryAllocator> memory)
114 : memory_allocator_(std::move(memory)) {} 128 : memory_allocator_(std::move(memory)) {}
115 129
116 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} 130 PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
117 131
118 void PersistentHistogramAllocator::CreateIterator(Iterator* iter) {
119 memory_allocator_->CreateIterator(&iter->memory_iter);
120 }
121
122 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { 132 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
123 memory_allocator_->CreateTrackingHistograms(name); 133 memory_allocator_->CreateTrackingHistograms(name);
124 } 134 }
125 135
126 void PersistentHistogramAllocator::UpdateTrackingHistograms() { 136 void PersistentHistogramAllocator::UpdateTrackingHistograms() {
127 memory_allocator_->UpdateTrackingHistograms(); 137 memory_allocator_->UpdateTrackingHistograms();
128 } 138 }
129 139
130 // static 140 // static
131 HistogramBase* 141 HistogramBase*
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() { 208 PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() {
199 PersistentHistogramAllocator* histogram_allocator = g_allocator; 209 PersistentHistogramAllocator* histogram_allocator = g_allocator;
200 if (!histogram_allocator) 210 if (!histogram_allocator)
201 return nullptr; 211 return nullptr;
202 PersistentMemoryAllocator* memory_allocator = 212 PersistentMemoryAllocator* memory_allocator =
203 histogram_allocator->memory_allocator(); 213 histogram_allocator->memory_allocator();
204 214
205 // Before releasing the memory, it's necessary to have the Statistics- 215 // Before releasing the memory, it's necessary to have the Statistics-
206 // Recorder forget about the histograms contained therein; otherwise, 216 // Recorder forget about the histograms contained therein; otherwise,
207 // some operations will try to access them and the released memory. 217 // some operations will try to access them and the released memory.
208 PersistentMemoryAllocator::Iterator iter; 218 PersistentMemoryAllocator::Iterator iter(memory_allocator);
209 PersistentMemoryAllocator::Reference ref; 219 PersistentMemoryAllocator::Reference ref;
210 uint32_t type_id; 220 while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) {
211 memory_allocator->CreateIterator(&iter); 221 PersistentHistogramData* histogram_data =
212 while ((ref = memory_allocator->GetNextIterable(&iter, &type_id)) != 0) { 222 memory_allocator->GetAsObject<PersistentHistogramData>(
213 if (type_id == kTypeIdHistogram) { 223 ref, kTypeIdHistogram);
214 PersistentHistogramData* histogram_data = 224 DCHECK(histogram_data);
215 memory_allocator->GetAsObject<PersistentHistogramData>( 225 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name);
216 ref, kTypeIdHistogram);
217 DCHECK(histogram_data);
218 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name);
219 226
220 // If a test breaks here then a memory region containing a histogram 227 // If a test breaks here then a memory region containing a histogram
221 // actively used by this code is being released back to the test. 228 // actively used by this code is being released back to the test.
222 // If that memory segment were to be deleted, future calls to create 229 // If that memory segment were to be deleted, future calls to create
223 // persistent histograms would crash. To avoid this, have the test call 230 // persistent histograms would crash. To avoid this, have the test call
224 // the method GetCreateHistogramResultHistogram() *before* setting 231 // the method GetCreateHistogramResultHistogram() *before* setting
225 // the (temporary) memory allocator via SetGlobalAllocator() so that 232 // the (temporary) memory allocator via SetGlobalAllocator() so that
226 // histogram is instead allocated from the process heap. 233 // histogram is instead allocated from the process heap.
227 DCHECK_NE(kResultHistogram, histogram_data->name); 234 DCHECK_NE(kResultHistogram, histogram_data->name);
228 }
229 } 235 }
230 236
231 g_allocator = nullptr; 237 g_allocator = nullptr;
232 return make_scoped_ptr(histogram_allocator); 238 return make_scoped_ptr(histogram_allocator);
233 }; 239 };
234 240
235 // static 241 // static
236 void PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory( 242 void PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory(
237 void* base, 243 void* base,
238 size_t size, 244 size_t size,
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 size_t length = memory_allocator_->GetAllocSize(ref); 412 size_t length = memory_allocator_->GetAllocSize(ref);
407 if (!histogram_data || 413 if (!histogram_data ||
408 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { 414 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') {
409 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); 415 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA);
410 NOTREACHED(); 416 NOTREACHED();
411 return nullptr; 417 return nullptr;
412 } 418 }
413 return CreateHistogram(histogram_data); 419 return CreateHistogram(histogram_data);
414 } 420 }
415 421
416 scoped_ptr<HistogramBase>
417 PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter,
418 Reference ignore) {
419 PersistentMemoryAllocator::Reference ref;
420 uint32_t type_id;
421 while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter,
422 &type_id)) != 0) {
423 if (ref == ignore)
424 continue;
425 if (type_id == kTypeIdHistogram)
426 return GetHistogram(ref);
427 }
428 return nullptr;
429 }
430
431 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref, 422 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
432 bool registered) { 423 bool registered) {
433 // If the created persistent histogram was registered then it needs to 424 // If the created persistent histogram was registered then it needs to
434 // be marked as "iterable" in order to be found by other processes. 425 // be marked as "iterable" in order to be found by other processes.
435 if (registered) 426 if (registered)
436 memory_allocator_->MakeIterable(ref); 427 memory_allocator_->MakeIterable(ref);
437 // If it wasn't registered then a race condition must have caused 428 // If it wasn't registered then a race condition must have caused
438 // two to be created. The allocator does not support releasing the 429 // two to be created. The allocator does not support releasing the
439 // acquired memory so just change the type to be empty. 430 // acquired memory so just change the type to be empty.
440 else 431 else
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 return nullptr; 539 return nullptr;
549 } 540 }
550 541
551 // static 542 // static
552 void PersistentHistogramAllocator::ImportGlobalHistograms() { 543 void PersistentHistogramAllocator::ImportGlobalHistograms() {
553 // The lock protects against concurrent access to the iterator and is created 544 // The lock protects against concurrent access to the iterator and is created
554 // in a thread-safe manner when needed. 545 // in a thread-safe manner when needed.
555 static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER; 546 static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER;
556 547
557 if (g_allocator) { 548 if (g_allocator) {
558 // TODO(bcwhite): Investigate a lock-free, thread-safe iterator. 549 // Even though the iterator is thread-safe, the rest of this code is not
550 // and has to be protected by a lock. Otherwise, there is no guarantee
551 // that multiple threads would process histograms in the same order
552 // they get returned by the iterator. That is important because it
553 // guarantees all processes will always have the same state.
559 base::AutoLock auto_lock(lock.Get()); 554 base::AutoLock auto_lock(lock.Get());
560 555
561 // Each call resumes from where it last left off so a persistant iterator 556 // Each call resumes from where it last left off so a persistant iterator
562 // is needed. This class has a constructor so even the definition has to 557 // is needed. This class has a constructor so even the definition has to
563 // be protected by the lock in order to be thread-safe. 558 // be protected by the lock in order to be thread-safe.
564 static Iterator iter; 559 static Iterator iter(g_allocator);
565 if (iter.is_clear())
566 g_allocator->CreateIterator(&iter);
567 560
568 // Skip the import if it's the histogram that was last created. Should a 561 // Skip the import if it's the histogram that was last created. Should a
569 // race condition cause the "last created" to be overwritten before it 562 // race condition cause the "last created" to be overwritten before it
570 // is recognized here then the histogram will be created and be ignored 563 // is recognized here then the histogram will be created and be ignored
571 // when it is detected as a duplicate by the statistics-recorder. This 564 // when it is detected as a duplicate by the statistics-recorder. This
572 // simple check reduces the time of creating persistent histograms by 565 // simple check reduces the time of creating persistent histograms by
573 // about 40%. 566 // about 40%.
574 Reference last_created = 567 Reference last_created =
575 subtle::NoBarrier_Load(&g_allocator->last_created_); 568 subtle::NoBarrier_Load(&g_allocator->last_created_);
576 569
577 while (true) { 570 while (true) {
578 scoped_ptr<HistogramBase> histogram = 571 scoped_ptr<HistogramBase> histogram =
579 g_allocator->GetNextHistogramWithIgnore(&iter, last_created); 572 iter.GetNextWithIgnore(last_created);
580 if (!histogram) 573 if (!histogram)
581 break; 574 break;
582 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); 575 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
583 } 576 }
584 } 577 }
585 } 578 }
586 579
587 } // namespace base 580 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698