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 |