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

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

Issue 1689833002: Add ownership-transfer to histogram management calls. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 10 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/histogram_persistence.h ('k') | base/metrics/histogram_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 (c) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 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/histogram_persistence.h" 5 #include "base/metrics/histogram_persistence.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 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so 221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so
222 // that the histogram is instead allocated from the process heap. 222 // that the histogram is instead allocated from the process heap.
223 DCHECK_NE(kResultHistogram, histogram_data->name); 223 DCHECK_NE(kResultHistogram, histogram_data->name);
224 } 224 }
225 } 225 }
226 226
227 g_allocator = nullptr; 227 g_allocator = nullptr;
228 return allocator; 228 return allocator;
229 }; 229 };
230 230
231 HistogramBase* CreatePersistentHistogram( 231 scoped_ptr<HistogramBase> CreatePersistentHistogram(
232 PersistentMemoryAllocator* allocator, 232 PersistentMemoryAllocator* allocator,
233 PersistentHistogramData* histogram_data_ptr) { 233 PersistentHistogramData* histogram_data_ptr) {
234 if (!histogram_data_ptr) { 234 if (!histogram_data_ptr) {
235 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); 235 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER);
236 NOTREACHED(); 236 NOTREACHED();
237 return nullptr; 237 return nullptr;
238 } 238 }
239 239
240 // Copy the histogram_data to local storage because anything in persistent 240 // Copy the histogram_data to local storage because anything in persistent
241 // memory cannot be trusted as it could be changed at any moment by a 241 // memory cannot be trusted as it could be changed at any moment by a
242 // malicious actor that shares access. The contents of histogram_data are 242 // malicious actor that shares access. The contents of histogram_data are
243 // validated below; the local copy is to ensure that the contents cannot 243 // validated below; the local copy is to ensure that the contents cannot
244 // be externally changed between validation and use. 244 // be externally changed between validation and use.
245 PersistentHistogramData histogram_data = *histogram_data_ptr; 245 PersistentHistogramData histogram_data = *histogram_data_ptr;
246 246
247 HistogramBase::Sample* ranges_data = 247 HistogramBase::Sample* ranges_data =
248 allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref, 248 allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref,
249 kTypeIdRangesArray); 249 kTypeIdRangesArray);
250 if (!ranges_data || histogram_data.bucket_count < 2 || 250 if (!ranges_data || histogram_data.bucket_count < 2 ||
251 histogram_data.bucket_count + 1 > 251 histogram_data.bucket_count + 1 >
252 std::numeric_limits<uint32_t>::max() / 252 std::numeric_limits<uint32_t>::max() /
253 sizeof(HistogramBase::Sample) || 253 sizeof(HistogramBase::Sample) ||
254 allocator->GetAllocSize(histogram_data.ranges_ref) < 254 allocator->GetAllocSize(histogram_data.ranges_ref) <
255 (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample)) { 255 (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample)) {
256 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); 256 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
257 NOTREACHED(); 257 NOTREACHED();
258 return nullptr; 258 return nullptr;
259 } 259 }
260 // To avoid racy destruction at shutdown, the following will be leaked. 260
261 const BucketRanges* ranges = CreateRangesFromData( 261 scoped_ptr<const BucketRanges> created_ranges(CreateRangesFromData(
262 ranges_data, 262 ranges_data,
263 histogram_data.ranges_checksum, 263 histogram_data.ranges_checksum,
264 histogram_data.bucket_count + 1); 264 histogram_data.bucket_count + 1));
265 if (!ranges) { 265 if (!created_ranges) {
266 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); 266 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
267 NOTREACHED(); 267 NOTREACHED();
268 return nullptr; 268 return nullptr;
269 } 269 }
270 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); 270 const BucketRanges* ranges =
271 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
272 std::move(created_ranges));
271 273
272 HistogramBase::AtomicCount* counts_data = 274 HistogramBase::AtomicCount* counts_data =
273 allocator->GetAsObject<HistogramBase::AtomicCount>( 275 allocator->GetAsObject<HistogramBase::AtomicCount>(
274 histogram_data.counts_ref, kTypeIdCountsArray); 276 histogram_data.counts_ref, kTypeIdCountsArray);
275 size_t counts_bytes = 277 size_t counts_bytes =
276 CalculateRequiredCountsBytes(histogram_data.bucket_count); 278 CalculateRequiredCountsBytes(histogram_data.bucket_count);
277 if (!counts_data || !counts_bytes || 279 if (!counts_data || !counts_bytes ||
278 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) { 280 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) {
279 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); 281 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
280 NOTREACHED(); 282 NOTREACHED();
281 return nullptr; 283 return nullptr;
282 } 284 }
283 285
284 // After the main "counts" array is a second array using for storing what 286 // After the main "counts" array is a second array using for storing what
285 // was previously logged. This is used to calculate the "delta" during 287 // was previously logged. This is used to calculate the "delta" during
286 // snapshot operations. 288 // snapshot operations.
287 HistogramBase::AtomicCount* logged_data = 289 HistogramBase::AtomicCount* logged_data =
288 counts_data + histogram_data.bucket_count; 290 counts_data + histogram_data.bucket_count;
289 291
290 std::string name(histogram_data_ptr->name); 292 std::string name(histogram_data_ptr->name);
291 HistogramBase* histogram = nullptr; 293 scoped_ptr<HistogramBase> histogram;
292 switch (histogram_data.histogram_type) { 294 switch (histogram_data.histogram_type) {
293 case HISTOGRAM: 295 case HISTOGRAM:
294 histogram = Histogram::PersistentGet( 296 histogram.reset(Histogram::PersistentGet(
295 name, 297 name,
296 histogram_data.minimum, 298 histogram_data.minimum,
297 histogram_data.maximum, 299 histogram_data.maximum,
298 ranges, 300 ranges,
299 counts_data, 301 counts_data,
300 logged_data, 302 logged_data,
301 histogram_data.bucket_count, 303 histogram_data.bucket_count,
302 &histogram_data_ptr->samples_metadata, 304 &histogram_data_ptr->samples_metadata,
303 &histogram_data_ptr->logged_metadata); 305 &histogram_data_ptr->logged_metadata));
304 DCHECK(histogram); 306 DCHECK(histogram);
305 break; 307 break;
306 case LINEAR_HISTOGRAM: 308 case LINEAR_HISTOGRAM:
307 histogram = LinearHistogram::PersistentGet( 309 histogram.reset(LinearHistogram::PersistentGet(
308 name, 310 name,
309 histogram_data.minimum, 311 histogram_data.minimum,
310 histogram_data.maximum, 312 histogram_data.maximum,
311 ranges, 313 ranges,
312 counts_data, 314 counts_data,
313 logged_data, 315 logged_data,
314 histogram_data.bucket_count, 316 histogram_data.bucket_count,
315 &histogram_data_ptr->samples_metadata, 317 &histogram_data_ptr->samples_metadata,
316 &histogram_data_ptr->logged_metadata); 318 &histogram_data_ptr->logged_metadata));
317 DCHECK(histogram); 319 DCHECK(histogram);
318 break; 320 break;
319 case BOOLEAN_HISTOGRAM: 321 case BOOLEAN_HISTOGRAM:
320 histogram = BooleanHistogram::PersistentGet( 322 histogram.reset(BooleanHistogram::PersistentGet(
321 name, 323 name,
322 ranges, 324 ranges,
323 counts_data, 325 counts_data,
324 logged_data, 326 logged_data,
325 &histogram_data_ptr->samples_metadata, 327 &histogram_data_ptr->samples_metadata,
326 &histogram_data_ptr->logged_metadata); 328 &histogram_data_ptr->logged_metadata));
327 DCHECK(histogram); 329 DCHECK(histogram);
328 break; 330 break;
329 case CUSTOM_HISTOGRAM: 331 case CUSTOM_HISTOGRAM:
330 histogram = CustomHistogram::PersistentGet( 332 histogram.reset(CustomHistogram::PersistentGet(
331 name, 333 name,
332 ranges, 334 ranges,
333 counts_data, 335 counts_data,
334 logged_data, 336 logged_data,
335 histogram_data.bucket_count, 337 histogram_data.bucket_count,
336 &histogram_data_ptr->samples_metadata, 338 &histogram_data_ptr->samples_metadata,
337 &histogram_data_ptr->logged_metadata); 339 &histogram_data_ptr->logged_metadata));
338 DCHECK(histogram); 340 DCHECK(histogram);
339 break; 341 break;
340 default: 342 default:
341 NOTREACHED(); 343 NOTREACHED();
342 } 344 }
343 345
344 if (histogram) { 346 if (histogram) {
345 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); 347 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType());
346 histogram->SetFlags(histogram_data.flags); 348 histogram->SetFlags(histogram_data.flags);
347 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); 349 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
348 } else { 350 } else {
349 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE); 351 RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE);
350 } 352 }
351 353
352 return histogram; 354 return histogram;
353 } 355 }
354 356
355 HistogramBase* GetPersistentHistogram( 357 scoped_ptr<HistogramBase> GetPersistentHistogram(
356 PersistentMemoryAllocator* allocator, 358 PersistentMemoryAllocator* allocator,
357 int32_t ref) { 359 int32_t ref) {
358 // Unfortunately, the above "pickle" methods cannot be used as part of the 360 // Unfortunately, the above "pickle" methods cannot be used as part of the
359 // persistance because the deserialization methods always create local 361 // persistance because the deserialization methods always create local
360 // count data (these must referenced the persistent counts) and always add 362 // count data (these must referenced the persistent counts) and always add
361 // it to the local list of known histograms (these may be simple references 363 // it to the local list of known histograms (these may be simple references
362 // to histograms in other processes). 364 // to histograms in other processes).
363 PersistentHistogramData* histogram_data = 365 PersistentHistogramData* histogram_data =
364 allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram); 366 allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram);
365 size_t length = allocator->GetAllocSize(ref); 367 size_t length = allocator->GetAllocSize(ref);
366 if (!histogram_data || 368 if (!histogram_data ||
367 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') { 369 reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') {
368 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA); 370 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA);
369 NOTREACHED(); 371 NOTREACHED();
370 return nullptr; 372 return nullptr;
371 } 373 }
372 return CreatePersistentHistogram(allocator, histogram_data); 374 return CreatePersistentHistogram(allocator, histogram_data);
373 } 375 }
374 376
375 HistogramBase* GetNextPersistentHistogram( 377 scoped_ptr<HistogramBase> GetNextPersistentHistogram(
376 PersistentMemoryAllocator* allocator, 378 PersistentMemoryAllocator* allocator,
377 PersistentMemoryAllocator::Iterator* iter) { 379 PersistentMemoryAllocator::Iterator* iter) {
378 PersistentMemoryAllocator::Reference ref; 380 PersistentMemoryAllocator::Reference ref;
379 uint32_t type_id; 381 uint32_t type_id;
380 while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) { 382 while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) {
381 if (type_id == kTypeIdHistogram) 383 if (type_id == kTypeIdHistogram)
382 return GetPersistentHistogram(allocator, ref); 384 return GetPersistentHistogram(allocator, ref);
383 } 385 }
384 return nullptr; 386 return nullptr;
385 } 387 }
386 388
387 void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref, 389 void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref,
388 bool registered) { 390 bool registered) {
389 // If the created persistent histogram was registered then it needs to 391 // If the created persistent histogram was registered then it needs to
390 // be marked as "iterable" in order to be found by other processes. 392 // be marked as "iterable" in order to be found by other processes.
391 if (registered) 393 if (registered)
392 GetPersistentHistogramMemoryAllocator()->MakeIterable(ref); 394 GetPersistentHistogramMemoryAllocator()->MakeIterable(ref);
393 // If it wasn't registered then a race condition must have caused 395 // If it wasn't registered then a race condition must have caused
394 // two to be created. The allocator does not support releasing the 396 // two to be created. The allocator does not support releasing the
395 // acquired memory so just change the type to be empty. 397 // acquired memory so just change the type to be empty.
396 else 398 else
397 GetPersistentHistogramMemoryAllocator()->SetType(ref, 0); 399 GetPersistentHistogramMemoryAllocator()->SetType(ref, 0);
398 } 400 }
399 401
400 HistogramBase* AllocatePersistentHistogram( 402 scoped_ptr<HistogramBase> AllocatePersistentHistogram(
401 PersistentMemoryAllocator* allocator, 403 PersistentMemoryAllocator* allocator,
402 HistogramType histogram_type, 404 HistogramType histogram_type,
403 const std::string& name, 405 const std::string& name,
404 int minimum, 406 int minimum,
405 int maximum, 407 int maximum,
406 const BucketRanges* bucket_ranges, 408 const BucketRanges* bucket_ranges,
407 int32_t flags, 409 int32_t flags,
408 PersistentMemoryAllocator::Reference* ref_ptr) { 410 PersistentMemoryAllocator::Reference* ref_ptr) {
409 if (!allocator) 411 if (!allocator)
410 return nullptr; 412 return nullptr;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); 460 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count);
459 histogram_data->ranges_ref = ranges_ref; 461 histogram_data->ranges_ref = ranges_ref;
460 histogram_data->ranges_checksum = bucket_ranges->checksum(); 462 histogram_data->ranges_checksum = bucket_ranges->checksum();
461 histogram_data->counts_ref = counts_ref; 463 histogram_data->counts_ref = counts_ref;
462 464
463 // Create the histogram using resources in persistent memory. This ends up 465 // Create the histogram using resources in persistent memory. This ends up
464 // resolving the "ref" values stored in histogram_data instad of just 466 // resolving the "ref" values stored in histogram_data instad of just
465 // using what is already known above but avoids duplicating the switch 467 // using what is already known above but avoids duplicating the switch
466 // statement here and serves as a double-check that everything is 468 // statement here and serves as a double-check that everything is
467 // correct before commiting the new histogram to persistent space. 469 // correct before commiting the new histogram to persistent space.
468 HistogramBase* histogram = 470 scoped_ptr<HistogramBase> histogram(
469 CreatePersistentHistogram(allocator, histogram_data); 471 CreatePersistentHistogram(allocator, histogram_data));
470 DCHECK(histogram); 472 DCHECK(histogram);
471 if (ref_ptr != nullptr) 473 if (ref_ptr != nullptr)
472 *ref_ptr = histogram_ref; 474 *ref_ptr = histogram_ref;
473 return histogram; 475 return histogram;
474 } 476 }
475 477
476 CreateHistogramResultType result; 478 CreateHistogramResultType result;
477 if (allocator->IsCorrupt()) { 479 if (allocator->IsCorrupt()) {
478 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT); 480 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT);
479 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT; 481 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT;
(...skipping 17 matching lines...) Expand all
497 base::AutoLock auto_lock(lock.Get()); 499 base::AutoLock auto_lock(lock.Get());
498 500
499 // Each call resumes from where it last left off so need persistant 501 // Each call resumes from where it last left off so need persistant
500 // iterator. This class has a constructor so even the definition has 502 // iterator. This class has a constructor so even the definition has
501 // to be protected by the lock in order to be thread-safe. 503 // to be protected by the lock in order to be thread-safe.
502 static PersistentMemoryAllocator::Iterator iter; 504 static PersistentMemoryAllocator::Iterator iter;
503 if (iter.is_clear()) 505 if (iter.is_clear())
504 g_allocator->CreateIterator(&iter); 506 g_allocator->CreateIterator(&iter);
505 507
506 while (true) { 508 while (true) {
507 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); 509 scoped_ptr<HistogramBase> histogram(
510 GetNextPersistentHistogram(g_allocator, &iter));
508 if (!histogram) 511 if (!histogram)
509 break; 512 break;
510 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); 513 StatisticsRecorder::RegisterOrDeleteDuplicate(std::move(histogram));
511 } 514 }
512 } 515 }
513 } 516 }
514 517
515 } // namespace base 518 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/histogram_persistence.h ('k') | base/metrics/histogram_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698