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" |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |