| 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/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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 // Histogram was of unknown type. | 46 // Histogram was of unknown type. |
| 47 CREATE_HISTOGRAM_UNKNOWN_TYPE, | 47 CREATE_HISTOGRAM_UNKNOWN_TYPE, |
| 48 | 48 |
| 49 // Instance has detected a corrupt allocator (recorded only once). | 49 // Instance has detected a corrupt allocator (recorded only once). |
| 50 CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT, | 50 CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT, |
| 51 | 51 |
| 52 // Always keep this at the end. | 52 // Always keep this at the end. |
| 53 CREATE_HISTOGRAM_MAX | 53 CREATE_HISTOGRAM_MAX |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 // Name of histogram for storing results of local operations. |
| 57 const char kResultHistogram[] = "UMA.CreatePersistentHistogram.Result"; |
| 58 |
| 56 // Type identifiers used when storing in persistent memory so they can be | 59 // Type identifiers used when storing in persistent memory so they can be |
| 57 // identified during extraction; the first 4 bytes of the SHA1 of the name | 60 // identified during extraction; the first 4 bytes of the SHA1 of the name |
| 58 // is used as a unique integer. A "version number" is added to the base | 61 // is used as a unique integer. A "version number" is added to the base |
| 59 // so that, if the structure of that object changes, stored older versions | 62 // so that, if the structure of that object changes, stored older versions |
| 60 // will be safely ignored. | 63 // will be safely ignored. |
| 61 enum : uint32_t { | 64 enum : uint32_t { |
| 62 kTypeIdHistogram = 0xF1645910 + 1, // SHA1(Histogram) v1 | 65 kTypeIdHistogram = 0xF1645910 + 1, // SHA1(Histogram) v1 |
| 63 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 | 66 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 |
| 64 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 | 67 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 |
| 65 }; | 68 }; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 static bool initialized = false; | 155 static bool initialized = false; |
| 153 if (!initialized) { | 156 if (!initialized) { |
| 154 initialized = true; | 157 initialized = true; |
| 155 if (g_allocator) { | 158 if (g_allocator) { |
| 156 DLOG(WARNING) << "Creating the results-histogram inside persistent" | 159 DLOG(WARNING) << "Creating the results-histogram inside persistent" |
| 157 << " memory can cause future allocations to crash if" | 160 << " memory can cause future allocations to crash if" |
| 158 << " that memory is ever released (for testing)."; | 161 << " that memory is ever released (for testing)."; |
| 159 } | 162 } |
| 160 | 163 |
| 161 histogram_pointer = LinearHistogram::FactoryGet( | 164 histogram_pointer = LinearHistogram::FactoryGet( |
| 162 "UMA.CreatePersistentHistogram.Result", | 165 kResultHistogram, 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1, |
| 163 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1, | |
| 164 HistogramBase::kUmaTargetedHistogramFlag); | 166 HistogramBase::kUmaTargetedHistogramFlag); |
| 165 base::subtle::Release_Store( | 167 base::subtle::Release_Store( |
| 166 &atomic_histogram_pointer, | 168 &atomic_histogram_pointer, |
| 167 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); | 169 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); |
| 168 } | 170 } |
| 169 } | 171 } |
| 170 return histogram_pointer; | 172 return histogram_pointer; |
| 171 } | 173 } |
| 172 | 174 |
| 173 // Record the result of a histogram creation. | 175 // Record the result of a histogram creation. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 203 PersistentMemoryAllocator::Reference ref; | 205 PersistentMemoryAllocator::Reference ref; |
| 204 uint32_t type_id; | 206 uint32_t type_id; |
| 205 allocator->CreateIterator(&iter); | 207 allocator->CreateIterator(&iter); |
| 206 while ((ref = allocator->GetNextIterable(&iter, &type_id)) != 0) { | 208 while ((ref = allocator->GetNextIterable(&iter, &type_id)) != 0) { |
| 207 if (type_id == kTypeIdHistogram) { | 209 if (type_id == kTypeIdHistogram) { |
| 208 PersistentHistogramData* histogram_data = | 210 PersistentHistogramData* histogram_data = |
| 209 allocator->GetAsObject<PersistentHistogramData>( | 211 allocator->GetAsObject<PersistentHistogramData>( |
| 210 ref, kTypeIdHistogram); | 212 ref, kTypeIdHistogram); |
| 211 DCHECK(histogram_data); | 213 DCHECK(histogram_data); |
| 212 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); | 214 StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name); |
| 215 |
| 216 // If a test breaks here then a memory region containing a histogram |
| 217 // actively used by this code is being released back to the test. |
| 218 // If that memory segment were to be deleted, future calls to create |
| 219 // persistent histograms would crash. To avoid this, have the test call |
| 220 // the method GetCreateHistogramResultHistogram() *before* setting the |
| 221 // (temporary) memory allocator via SetPersistentMemoryAllocator() so |
| 222 // that the histogram is instead allocated from the process heap. |
| 223 DCHECK_NE(kResultHistogram, histogram_data->name); |
| 213 } | 224 } |
| 214 } | 225 } |
| 215 | 226 |
| 216 g_allocator = nullptr; | 227 g_allocator = nullptr; |
| 217 return allocator; | 228 return allocator; |
| 218 }; | 229 }; |
| 219 | 230 |
| 220 HistogramBase* CreatePersistentHistogram( | 231 HistogramBase* CreatePersistentHistogram( |
| 221 PersistentMemoryAllocator* allocator, | 232 PersistentMemoryAllocator* allocator, |
| 222 PersistentHistogramData* histogram_data_ptr) { | 233 PersistentHistogramData* histogram_data_ptr) { |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 } | 484 } |
| 474 RecordCreateHistogramResult(result); | 485 RecordCreateHistogramResult(result); |
| 475 NOTREACHED() << "error=" << result; | 486 NOTREACHED() << "error=" << result; |
| 476 | 487 |
| 477 return nullptr; | 488 return nullptr; |
| 478 } | 489 } |
| 479 | 490 |
| 480 void ImportPersistentHistograms() { | 491 void ImportPersistentHistograms() { |
| 481 // The lock protects against concurrent access to the iterator and is created | 492 // The lock protects against concurrent access to the iterator and is created |
| 482 // in a thread-safe manner when needed. | 493 // in a thread-safe manner when needed. |
| 483 static base::LazyInstance<base::Lock> lock = LAZY_INSTANCE_INITIALIZER; | 494 static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER; |
| 484 | 495 |
| 485 if (g_allocator) { | 496 if (g_allocator) { |
| 486 base::AutoLock auto_lock(lock.Get()); | 497 base::AutoLock auto_lock(lock.Get()); |
| 487 | 498 |
| 488 // Each call resumes from where it last left off so need persistant | 499 // Each call resumes from where it last left off so need persistant |
| 489 // iterator. This class has a constructor so even the definition has | 500 // iterator. This class has a constructor so even the definition has |
| 490 // to be protected by the lock in order to be thread-safe. | 501 // to be protected by the lock in order to be thread-safe. |
| 491 static PersistentMemoryAllocator::Iterator iter; | 502 static PersistentMemoryAllocator::Iterator iter; |
| 492 if (iter.is_clear()) | 503 if (iter.is_clear()) |
| 493 g_allocator->CreateIterator(&iter); | 504 g_allocator->CreateIterator(&iter); |
| 494 | 505 |
| 495 for (;;) { | 506 while (true) { |
| 496 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); | 507 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); |
| 497 if (!histogram) | 508 if (!histogram) |
| 498 break; | 509 break; |
| 499 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); | 510 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); |
| 500 } | 511 } |
| 501 } | 512 } |
| 502 } | 513 } |
| 503 | 514 |
| 504 } // namespace base | 515 } // namespace base |
| OLD | NEW |