| OLD | NEW |
| 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/atomicops.h" |
| 7 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
| 8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 11 #include "base/metrics/histogram_base.h" | 12 #include "base/metrics/histogram_base.h" |
| 12 #include "base/metrics/histogram_samples.h" | 13 #include "base/metrics/histogram_samples.h" |
| 13 #include "base/metrics/statistics_recorder.h" | 14 #include "base/metrics/statistics_recorder.h" |
| 14 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
| 15 | 16 |
| 16 namespace base { | 17 namespace base { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 PersistentMemoryAllocator::Reference counts_ref; | 81 PersistentMemoryAllocator::Reference counts_ref; |
| 81 HistogramSamples::Metadata samples_metadata; | 82 HistogramSamples::Metadata samples_metadata; |
| 82 HistogramSamples::Metadata logged_metadata; | 83 HistogramSamples::Metadata logged_metadata; |
| 83 | 84 |
| 84 // Space for the histogram name will be added during the actual allocation | 85 // Space for the histogram name will be added during the actual allocation |
| 85 // request. This must be the last field of the structure. A zero-size array | 86 // request. This must be the last field of the structure. A zero-size array |
| 86 // or a "flexible" array would be preferred but is not (yet) valid C++. | 87 // or a "flexible" array would be preferred but is not (yet) valid C++. |
| 87 char name[1]; | 88 char name[1]; |
| 88 }; | 89 }; |
| 89 | 90 |
| 91 // This is the offset of the last histogram that was created. It is used to |
| 92 // avoid trying to import the same thing just to have it rejected because |
| 93 // it already exists. |
| 94 subtle::AtomicWord g_last_created_histogram = 0; |
| 95 |
| 90 // The object held here will obviously not be destructed at process exit | 96 // The object held here will obviously not be destructed at process exit |
| 91 // but that's okay since PersistentMemoryAllocator objects are explicitly | 97 // but that's okay since PersistentMemoryAllocator objects are explicitly |
| 92 // forbidden from doing anything essential at exit anyway due to the fact | 98 // forbidden from doing anything essential at exit anyway due to the fact |
| 93 // that they depend on data managed elsewhere and which could be destructed | 99 // that they depend on data managed elsewhere and which could be destructed |
| 94 // first. | 100 // first. |
| 95 PersistentMemoryAllocator* g_allocator = nullptr; | 101 PersistentMemoryAllocator* g_allocator = nullptr; |
| 96 | 102 |
| 97 // Take an array of range boundaries and create a proper BucketRanges object | 103 // Take an array of range boundaries and create a proper BucketRanges object |
| 98 // which is returned to the caller. A return of nullptr indicates that the | 104 // which is returned to the caller. A return of nullptr indicates that the |
| 99 // passed boundaries are invalid. | 105 // passed boundaries are invalid. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 // If that memory segment were to be deleted, future calls to create | 224 // If that memory segment were to be deleted, future calls to create |
| 219 // persistent histograms would crash. To avoid this, have the test call | 225 // persistent histograms would crash. To avoid this, have the test call |
| 220 // the method GetCreateHistogramResultHistogram() *before* setting the | 226 // the method GetCreateHistogramResultHistogram() *before* setting the |
| 221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so | 227 // (temporary) memory allocator via SetPersistentMemoryAllocator() so |
| 222 // that the histogram is instead allocated from the process heap. | 228 // that the histogram is instead allocated from the process heap. |
| 223 DCHECK_NE(kResultHistogram, histogram_data->name); | 229 DCHECK_NE(kResultHistogram, histogram_data->name); |
| 224 } | 230 } |
| 225 } | 231 } |
| 226 | 232 |
| 227 g_allocator = nullptr; | 233 g_allocator = nullptr; |
| 234 subtle::NoBarrier_Store(&g_last_created_histogram, 0); |
| 228 return allocator; | 235 return allocator; |
| 229 }; | 236 }; |
| 230 | 237 |
| 231 HistogramBase* CreatePersistentHistogram( | 238 HistogramBase* CreatePersistentHistogram( |
| 232 PersistentMemoryAllocator* allocator, | 239 PersistentMemoryAllocator* allocator, |
| 233 PersistentHistogramData* histogram_data_ptr) { | 240 PersistentHistogramData* histogram_data_ptr) { |
| 234 if (!histogram_data_ptr) { | 241 if (!histogram_data_ptr) { |
| 235 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); | 242 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); |
| 236 NOTREACHED(); | 243 NOTREACHED(); |
| 237 return nullptr; | 244 return nullptr; |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 // Create the histogram using resources in persistent memory. This ends up | 470 // Create the histogram using resources in persistent memory. This ends up |
| 464 // resolving the "ref" values stored in histogram_data instad of just | 471 // resolving the "ref" values stored in histogram_data instad of just |
| 465 // using what is already known above but avoids duplicating the switch | 472 // using what is already known above but avoids duplicating the switch |
| 466 // statement here and serves as a double-check that everything is | 473 // statement here and serves as a double-check that everything is |
| 467 // correct before commiting the new histogram to persistent space. | 474 // correct before commiting the new histogram to persistent space. |
| 468 HistogramBase* histogram = | 475 HistogramBase* histogram = |
| 469 CreatePersistentHistogram(allocator, histogram_data); | 476 CreatePersistentHistogram(allocator, histogram_data); |
| 470 DCHECK(histogram); | 477 DCHECK(histogram); |
| 471 if (ref_ptr != nullptr) | 478 if (ref_ptr != nullptr) |
| 472 *ref_ptr = histogram_ref; | 479 *ref_ptr = histogram_ref; |
| 480 subtle::NoBarrier_Store(&g_last_created_histogram, histogram_ref); |
| 473 return histogram; | 481 return histogram; |
| 474 } | 482 } |
| 475 | 483 |
| 476 CreateHistogramResultType result; | 484 CreateHistogramResultType result; |
| 477 if (allocator->IsCorrupt()) { | 485 if (allocator->IsCorrupt()) { |
| 478 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT); | 486 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT); |
| 479 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT; | 487 result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT; |
| 480 } else if (allocator->IsFull()) { | 488 } else if (allocator->IsFull()) { |
| 481 result = CREATE_HISTOGRAM_ALLOCATOR_FULL; | 489 result = CREATE_HISTOGRAM_ALLOCATOR_FULL; |
| 482 } else { | 490 } else { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 496 if (g_allocator) { | 504 if (g_allocator) { |
| 497 base::AutoLock auto_lock(lock.Get()); | 505 base::AutoLock auto_lock(lock.Get()); |
| 498 | 506 |
| 499 // Each call resumes from where it last left off so need persistant | 507 // Each call resumes from where it last left off so need persistant |
| 500 // iterator. This class has a constructor so even the definition has | 508 // iterator. This class has a constructor so even the definition has |
| 501 // to be protected by the lock in order to be thread-safe. | 509 // to be protected by the lock in order to be thread-safe. |
| 502 static PersistentMemoryAllocator::Iterator iter; | 510 static PersistentMemoryAllocator::Iterator iter; |
| 503 if (iter.is_clear()) | 511 if (iter.is_clear()) |
| 504 g_allocator->CreateIterator(&iter); | 512 g_allocator->CreateIterator(&iter); |
| 505 | 513 |
| 506 while (true) { | 514 PersistentMemoryAllocator::Reference last_created = |
| 507 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); | 515 subtle::NoBarrier_Load(&g_last_created_histogram); |
| 508 if (!histogram) | 516 |
| 509 break; | 517 PersistentMemoryAllocator::Reference ref; |
| 510 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); | 518 uint32_t type_id; |
| 519 while ((ref = g_allocator->GetNextIterable(&iter, &type_id)) != 0) { |
| 520 // Ignore any other type of objects in the allocator. |
| 521 if (type_id != kTypeIdHistogram) |
| 522 continue; |
| 523 |
| 524 // Skip the import if it's the histogram that was last created. |
| 525 // Should a race condition cause the "last created" to be overwritten |
| 526 // before it is recognized here then the histogram will be created |
| 527 // and be ignored when it is detected as a duplicate by the |
| 528 // statistics-recorder. |
| 529 if (ref == last_created) |
| 530 continue; |
| 531 |
| 532 // Create the histogram from contents in persistent memory and add it |
| 533 // to the set of known ones. |
| 534 HistogramBase* histogram = GetPersistentHistogram(g_allocator, ref); |
| 535 if (histogram) |
| 536 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); |
| 511 } | 537 } |
| 512 } | 538 } |
| 513 } | 539 } |
| 514 | 540 |
| 515 } // namespace base | 541 } // namespace base |
| OLD | NEW |