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

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

Issue 1909673002: Support negative sample values in PersistentHistogramMap. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: use separate flag to indicate 'import all' 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
« no previous file with comments | « base/metrics/persistent_sample_map.h ('k') | base/metrics/persistent_sample_map_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_sample_map.h" 5 #include "base/metrics/persistent_sample_map.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h" 8 #include "base/memory/ptr_util.h"
9 #include "base/metrics/persistent_histogram_allocator.h" 9 #include "base/metrics/persistent_histogram_allocator.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 // Have to override "const" to make sure all samples have been loaded before 124 // Have to override "const" to make sure all samples have been loaded before
125 // being able to know what value to return. 125 // being able to know what value to return.
126 Count* count_pointer = 126 Count* count_pointer =
127 const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value); 127 const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value);
128 return count_pointer ? *count_pointer : 0; 128 return count_pointer ? *count_pointer : 0;
129 } 129 }
130 130
131 Count PersistentSampleMap::TotalCount() const { 131 Count PersistentSampleMap::TotalCount() const {
132 // Have to override "const" in order to make sure all samples have been 132 // Have to override "const" in order to make sure all samples have been
133 // loaded before trying to iterate over the map. 133 // loaded before trying to iterate over the map.
134 const_cast<PersistentSampleMap*>(this)->ImportSamples(kAllSamples); 134 const_cast<PersistentSampleMap*>(this)->ImportSamples(-1, true);
135 135
136 Count count = 0; 136 Count count = 0;
137 for (const auto& entry : sample_counts_) { 137 for (const auto& entry : sample_counts_) {
138 count += *entry.second; 138 count += *entry.second;
139 } 139 }
140 return count; 140 return count;
141 } 141 }
142 142
143 std::unique_ptr<SampleCountIterator> PersistentSampleMap::Iterator() const { 143 std::unique_ptr<SampleCountIterator> PersistentSampleMap::Iterator() const {
144 // Have to override "const" in order to make sure all samples have been 144 // Have to override "const" in order to make sure all samples have been
145 // loaded before trying to iterate over the map. 145 // loaded before trying to iterate over the map.
146 const_cast<PersistentSampleMap*>(this)->ImportSamples(kAllSamples); 146 const_cast<PersistentSampleMap*>(this)->ImportSamples(-1, true);
147 return WrapUnique(new PersistentSampleMapIterator(sample_counts_)); 147 return WrapUnique(new PersistentSampleMapIterator(sample_counts_));
148 } 148 }
149 149
150 // static 150 // static
151 PersistentMemoryAllocator::Reference 151 PersistentMemoryAllocator::Reference
152 PersistentSampleMap::GetNextPersistentRecord( 152 PersistentSampleMap::GetNextPersistentRecord(
153 PersistentMemoryAllocator::Iterator& iterator, 153 PersistentMemoryAllocator::Iterator& iterator,
154 uint64_t* sample_map_id) { 154 uint64_t* sample_map_id) {
155 PersistentMemoryAllocator::Reference ref = 155 PersistentMemoryAllocator::Reference ref =
156 iterator.GetNextOfType(kTypeIdSampleRecord); 156 iterator.GetNextOfType(kTypeIdSampleRecord);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 if (min + 1 != max) 197 if (min + 1 != max)
198 return false; // SparseHistogram only supports bucket with size 1. 198 return false; // SparseHistogram only supports bucket with size 1.
199 199
200 *GetOrCreateSampleCountStorage(min) += 200 *GetOrCreateSampleCountStorage(min) +=
201 (op == HistogramSamples::ADD) ? count : -count; 201 (op == HistogramSamples::ADD) ? count : -count;
202 } 202 }
203 return true; 203 return true;
204 } 204 }
205 205
206 Count* PersistentSampleMap::GetSampleCountStorage(Sample value) { 206 Count* PersistentSampleMap::GetSampleCountStorage(Sample value) {
207 DCHECK_LE(0, value);
208
209 // If |value| is already in the map, just return that. 207 // If |value| is already in the map, just return that.
210 auto it = sample_counts_.find(value); 208 auto it = sample_counts_.find(value);
211 if (it != sample_counts_.end()) 209 if (it != sample_counts_.end())
212 return it->second; 210 return it->second;
213 211
214 // Import any new samples from persistent memory looking for the value. 212 // Import any new samples from persistent memory looking for the value.
215 return ImportSamples(value); 213 return ImportSamples(value, false);
216 } 214 }
217 215
218 Count* PersistentSampleMap::GetOrCreateSampleCountStorage(Sample value) { 216 Count* PersistentSampleMap::GetOrCreateSampleCountStorage(Sample value) {
219 // Get any existing count storage. 217 // Get any existing count storage.
220 Count* count_pointer = GetSampleCountStorage(value); 218 Count* count_pointer = GetSampleCountStorage(value);
221 if (count_pointer) 219 if (count_pointer)
222 return count_pointer; 220 return count_pointer;
223 221
224 // Create a new record in persistent memory for the value. 222 // Create a new record in persistent memory for the value.
225 PersistentMemoryAllocator::Reference ref = records_->CreateNew(value); 223 PersistentMemoryAllocator::Reference ref = records_->CreateNew(value);
226 if (!ref) { 224 if (!ref) {
227 // If a new record could not be created then the underlying allocator is 225 // If a new record could not be created then the underlying allocator is
228 // full or corrupt. Instead, allocate the counter from the heap. This 226 // full or corrupt. Instead, allocate the counter from the heap. This
229 // sample will not be persistent, will not be shared, and will leak... 227 // sample will not be persistent, will not be shared, and will leak...
230 // but it's better than crashing. 228 // but it's better than crashing.
231 count_pointer = new Count(0); 229 count_pointer = new Count(0);
232 sample_counts_[value] = count_pointer; 230 sample_counts_[value] = count_pointer;
233 return count_pointer; 231 return count_pointer;
234 } 232 }
235 233
236 // A race condition between two independent processes (i.e. two independent 234 // A race condition between two independent processes (i.e. two independent
237 // histogram objects sharing the same sample data) could cause two of the 235 // histogram objects sharing the same sample data) could cause two of the
238 // above records to be created. The allocator, however, forces a strict 236 // above records to be created. The allocator, however, forces a strict
239 // ordering on iterable objects so use the import method to actually add the 237 // ordering on iterable objects so use the import method to actually add the
240 // just-created record. This ensures that all PersistentSampleMap objects 238 // just-created record. This ensures that all PersistentSampleMap objects
241 // will always use the same record, whichever was first made iterable. 239 // will always use the same record, whichever was first made iterable.
242 // Thread-safety within a process where multiple threads use the same 240 // Thread-safety within a process where multiple threads use the same
243 // histogram object is delegated to the controlling histogram object which, 241 // histogram object is delegated to the controlling histogram object which,
244 // for sparse histograms, is a lock object. 242 // for sparse histograms, is a lock object.
245 count_pointer = ImportSamples(value); 243 count_pointer = ImportSamples(value, false);
246 DCHECK(count_pointer); 244 DCHECK(count_pointer);
247 return count_pointer; 245 return count_pointer;
248 } 246 }
249 247
250 Count* PersistentSampleMap::ImportSamples(Sample until_value) { 248 Count* PersistentSampleMap::ImportSamples(Sample until_value,
249 bool import_everything) {
250 Count* found_count = nullptr;
251 PersistentMemoryAllocator::Reference ref; 251 PersistentMemoryAllocator::Reference ref;
252 while ((ref = records_->GetNext()) != 0) { 252 while ((ref = records_->GetNext()) != 0) {
253 SampleRecord* record = 253 SampleRecord* record =
254 records_->GetAsObject<SampleRecord>(ref, kTypeIdSampleRecord); 254 records_->GetAsObject<SampleRecord>(ref, kTypeIdSampleRecord);
255 if (!record) 255 if (!record)
256 continue; 256 continue;
257 257
258 DCHECK_EQ(id(), record->id); 258 DCHECK_EQ(id(), record->id);
259 259
260 // Check if the record's value is already known. 260 // Check if the record's value is already known.
261 if (!ContainsKey(sample_counts_, record->value)) { 261 if (!ContainsKey(sample_counts_, record->value)) {
262 // No: Add it to map of known values if the value is valid. 262 // No: Add it to map of known values.
263 if (record->value >= 0) 263 sample_counts_[record->value] = &record->count;
264 sample_counts_[record->value] = &record->count;
265 } else { 264 } else {
266 // Yes: Ignore it; it's a duplicate caused by a race condition -- see 265 // Yes: Ignore it; it's a duplicate caused by a race condition -- see
267 // code & comment in GetOrCreateSampleCountStorage() for details. 266 // code & comment in GetOrCreateSampleCountStorage() for details.
268 // Check that nothing ever operated on the duplicate record. 267 // Check that nothing ever operated on the duplicate record.
269 DCHECK_EQ(0, record->count); 268 DCHECK_EQ(0, record->count);
270 } 269 }
271 270
272 // Stop if it's the value being searched for. 271 // Check if it's the value being searched for and, if so, keep a pointer
273 if (record->value == until_value) 272 // to return later. Stop here unless everything is being imported.
274 return &record->count; 273 // Because race conditions can cause multiple records for a single value,
274 // be sure to return the first one found.
275 if (record->value == until_value) {
276 if (!found_count)
277 found_count = &record->count;
278 if (!import_everything)
279 break;
280 }
275 } 281 }
276 282
277 return nullptr; 283 return found_count;
278 } 284 }
279 285
280 } // namespace base 286 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/persistent_sample_map.h ('k') | base/metrics/persistent_sample_map_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698