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

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

Issue 1840843004: Improve efficiency of persistent sparse histograms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@improved-pma-iterator
Patch Set: added comment clarifying loop behavior Created 4 years, 8 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 <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"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/metrics/histogram_base.h" 13 #include "base/metrics/histogram_base.h"
14 #include "base/metrics/histogram_samples.h" 14 #include "base/metrics/histogram_samples.h"
15 #include "base/metrics/persistent_sample_map.h"
15 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
16 #include "base/metrics/statistics_recorder.h" 17 #include "base/metrics/statistics_recorder.h"
17 #include "base/synchronization/lock.h" 18 #include "base/synchronization/lock.h"
18 19
19 // TODO(bcwhite): Order these methods to match the header file. The current 20 // TODO(bcwhite): Order these methods to match the header file. The current
20 // order is only temporary in order to aid review of the transition from 21 // order is only temporary in order to aid review of the transition from
21 // a non-class implementation. 22 // a non-class implementation.
22 23
23 namespace base { 24 namespace base {
24 25
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 85
85 return bucket_count * kBytesPerBucket; 86 return bucket_count * kBytesPerBucket;
86 } 87 }
87 88
88 } // namespace 89 } // namespace
89 90
90 const Feature kPersistentHistogramsFeature{ 91 const Feature kPersistentHistogramsFeature{
91 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT 92 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
92 }; 93 };
93 94
95
96 PersistentSparseHistogramDataManager::PersistentSparseHistogramDataManager(
97 PersistentMemoryAllocator* allocator)
98 : allocator_(allocator), record_iterator_(allocator) {}
99
100 PersistentSparseHistogramDataManager::~PersistentSparseHistogramDataManager() {}
101
102 PersistentSampleMapRecords*
103 PersistentSparseHistogramDataManager::UseSampleMapRecords(uint64_t id,
104 const void* user) {
105 base::AutoLock auto_lock(lock_);
106 return GetSampleMapRecordsWhileLocked(id)->Acquire(user);
107 }
108
109 PersistentSampleMapRecords*
110 PersistentSparseHistogramDataManager::GetSampleMapRecordsWhileLocked(
111 uint64_t id) {
112 lock_.AssertAcquired();
113
114 auto found = sample_records_.find(id);
115 if (found != sample_records_.end())
116 return found->second.get();
117
118 std::unique_ptr<PersistentSampleMapRecords>& samples = sample_records_[id];
119 samples = WrapUnique(new PersistentSampleMapRecords(this, id));
120 return samples.get();
121 }
122
123 bool PersistentSparseHistogramDataManager::LoadRecords(
124 PersistentSampleMapRecords* sample_map_records) {
125 // DataManager must be locked in order to access the found_ field of any
126 // PersistentSampleMapRecords object.
127 base::AutoLock auto_lock(lock_);
128 bool found = false;
129
130 // If there are already "found" entries for the passed object, move them.
131 if (!sample_map_records->found_.empty()) {
132 sample_map_records->records_.reserve(sample_map_records->records_.size() +
133 sample_map_records->found_.size());
134 sample_map_records->records_.insert(sample_map_records->records_.end(),
135 sample_map_records->found_.begin(),
136 sample_map_records->found_.end());
137 sample_map_records->found_.clear();
138 found = true;
139 }
140
141 // Acquiring a lock is a semi-expensive operation so load some records with
142 // each call. More than this number may be loaded if it takes longer to
143 // find at least one matching record for the passed object.
144 const int kMinimumNumberToLoad = 10;
145 const uint64_t match_id = sample_map_records->sample_map_id_;
146
147 // Loop while no enty is found OR we haven't yet loaded the minimum number.
148 // This will continue reading even after a match is found.
149 for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
150 // Get the next sample-record. The iterator will always resume from where
151 // it left off even if it previously had nothing further to return.
152 uint64_t found_id;
153 PersistentMemoryAllocator::Reference ref =
154 PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
155 &found_id);
156
157 // Stop immediately if there are none.
158 if (!ref)
159 break;
160
161 // The sample-record could be for any sparse histogram. Add the reference
162 // to the appropriate collection for later use.
163 if (found_id == match_id) {
164 sample_map_records->records_.push_back(ref);
165 found = true;
166 } else {
167 PersistentSampleMapRecords* samples =
168 GetSampleMapRecordsWhileLocked(found_id);
169 DCHECK(samples);
170 samples->found_.push_back(ref);
171 }
172 }
173
174 return found;
175 }
176
177
178 PersistentSampleMapRecords::PersistentSampleMapRecords(
179 PersistentSparseHistogramDataManager* data_manager,
180 uint64_t sample_map_id)
181 : data_manager_(data_manager), sample_map_id_(sample_map_id) {}
182
183 PersistentSampleMapRecords::~PersistentSampleMapRecords() {}
184
185 PersistentSampleMapRecords* PersistentSampleMapRecords::Acquire(
186 const void* user) {
187 DCHECK(!user_);
188 user_ = user;
189 seen_ = 0;
190 return this;
191 }
192
193 void PersistentSampleMapRecords::Release(const void* user) {
194 DCHECK_EQ(user_, user);
195 user_ = nullptr;
196 }
197
198 PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
199 DCHECK(user_);
200
201 // If there are no unseen records, lock and swap in all the found ones.
202 if (records_.size() == seen_) {
203 if (!data_manager_->LoadRecords(this))
204 return false;
205 }
206
207 // Return the next record. Records *must* be returned in the same order
208 // they are found in the persistent memory in order to ensure that all
209 // objects using this data always have the same state. Race conditions
210 // can cause duplicate records so using the "first found" is the only
211 // guarantee that all objects always access the same one.
212 DCHECK_LT(seen_, records_.size());
213 return records_[seen_++];
214 }
215
216 PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
217 HistogramBase::Sample value) {
218 return PersistentSampleMap::CreatePersistentRecord(data_manager_->allocator_,
219 sample_map_id_, value);
220 }
221
222
94 // This data will be held in persistent memory in order for processes to 223 // This data will be held in persistent memory in order for processes to
95 // locate and use histograms created elsewhere. 224 // locate and use histograms created elsewhere.
96 struct PersistentHistogramAllocator::PersistentHistogramData { 225 struct PersistentHistogramAllocator::PersistentHistogramData {
97 int32_t histogram_type; 226 int32_t histogram_type;
98 int32_t flags; 227 int32_t flags;
99 int32_t minimum; 228 int32_t minimum;
100 int32_t maximum; 229 int32_t maximum;
101 uint32_t bucket_count; 230 uint32_t bucket_count;
102 PersistentMemoryAllocator::Reference ranges_ref; 231 PersistentMemoryAllocator::Reference ranges_ref;
103 uint32_t ranges_checksum; 232 uint32_t ranges_checksum;
(...skipping 14 matching lines...) Expand all
118 std::unique_ptr<HistogramBase> 247 std::unique_ptr<HistogramBase>
119 PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) { 248 PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
120 PersistentMemoryAllocator::Reference ref; 249 PersistentMemoryAllocator::Reference ref;
121 while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) { 250 while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) {
122 if (ref != ignore) 251 if (ref != ignore)
123 return allocator_->GetHistogram(ref); 252 return allocator_->GetHistogram(ref);
124 } 253 }
125 return nullptr; 254 return nullptr;
126 } 255 }
127 256
257
128 PersistentHistogramAllocator::PersistentHistogramAllocator( 258 PersistentHistogramAllocator::PersistentHistogramAllocator(
129 std::unique_ptr<PersistentMemoryAllocator> memory) 259 std::unique_ptr<PersistentMemoryAllocator> memory)
130 : memory_allocator_(std::move(memory)) {} 260 : memory_allocator_(std::move(memory)),
261 sparse_histogram_data_manager_(memory_allocator_.get()) {}
131 262
132 PersistentHistogramAllocator::~PersistentHistogramAllocator() {} 263 PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
133 264
134 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) { 265 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
135 memory_allocator_->CreateTrackingHistograms(name); 266 memory_allocator_->CreateTrackingHistograms(name);
136 } 267 }
137 268
138 void PersistentHistogramAllocator::UpdateTrackingHistograms() { 269 void PersistentHistogramAllocator::UpdateTrackingHistograms() {
139 memory_allocator_->UpdateTrackingHistograms(); 270 memory_allocator_->UpdateTrackingHistograms();
140 } 271 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 PersistentHistogramData* histogram_data_ptr) { 320 PersistentHistogramData* histogram_data_ptr) {
190 if (!histogram_data_ptr) { 321 if (!histogram_data_ptr) {
191 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); 322 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER);
192 NOTREACHED(); 323 NOTREACHED();
193 return nullptr; 324 return nullptr;
194 } 325 }
195 326
196 // Sparse histograms are quite different so handle them as a special case. 327 // Sparse histograms are quite different so handle them as a special case.
197 if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) { 328 if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
198 std::unique_ptr<HistogramBase> histogram = 329 std::unique_ptr<HistogramBase> histogram =
199 SparseHistogram::PersistentCreate(memory_allocator(), 330 SparseHistogram::PersistentCreate(this, histogram_data_ptr->name,
200 histogram_data_ptr->name,
201 &histogram_data_ptr->samples_metadata, 331 &histogram_data_ptr->samples_metadata,
202 &histogram_data_ptr->logged_metadata); 332 &histogram_data_ptr->logged_metadata);
203 DCHECK(histogram); 333 DCHECK(histogram);
204 histogram->SetFlags(histogram_data_ptr->flags); 334 histogram->SetFlags(histogram_data_ptr->flags);
205 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); 335 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
206 return histogram; 336 return histogram;
207 } 337 }
208 338
209 // Copy the histogram_data to local storage because anything in persistent 339 // Copy the histogram_data to local storage because anything in persistent
210 // memory cannot be trusted as it could be changed at any moment by a 340 // memory cannot be trusted as it could be changed at any moment by a
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 // be marked as "iterable" in order to be found by other processes. 466 // be marked as "iterable" in order to be found by other processes.
337 if (registered) 467 if (registered)
338 memory_allocator_->MakeIterable(ref); 468 memory_allocator_->MakeIterable(ref);
339 // If it wasn't registered then a race condition must have caused 469 // If it wasn't registered then a race condition must have caused
340 // two to be created. The allocator does not support releasing the 470 // two to be created. The allocator does not support releasing the
341 // acquired memory so just change the type to be empty. 471 // acquired memory so just change the type to be empty.
342 else 472 else
343 memory_allocator_->SetType(ref, 0); 473 memory_allocator_->SetType(ref, 0);
344 } 474 }
345 475
476 PersistentSampleMapRecords* PersistentHistogramAllocator::UseSampleMapRecords(
477 uint64_t id,
478 const void* user) {
479 return sparse_histogram_data_manager_.UseSampleMapRecords(id, user);
480 }
481
346 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram( 482 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
347 HistogramType histogram_type, 483 HistogramType histogram_type,
348 const std::string& name, 484 const std::string& name,
349 int minimum, 485 int minimum,
350 int maximum, 486 int maximum,
351 const BucketRanges* bucket_ranges, 487 const BucketRanges* bucket_ranges,
352 int32_t flags, 488 int32_t flags,
353 Reference* ref_ptr) { 489 Reference* ref_ptr) {
354 // If the allocator is corrupt, don't waste time trying anything else. 490 // If the allocator is corrupt, don't waste time trying anything else.
355 // This also allows differentiating on the dashboard between allocations 491 // This also allows differentiating on the dashboard between allocations
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 while (true) { 719 while (true) {
584 std::unique_ptr<HistogramBase> histogram = 720 std::unique_ptr<HistogramBase> histogram =
585 import_iterator_.GetNextWithIgnore(record_to_ignore); 721 import_iterator_.GetNextWithIgnore(record_to_ignore);
586 if (!histogram) 722 if (!histogram)
587 break; 723 break;
588 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); 724 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
589 } 725 }
590 } 726 }
591 727
592 } // namespace base 728 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/persistent_histogram_allocator.h ('k') | base/metrics/persistent_memory_allocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698