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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 // Could not allocate histogram memory due to unknown error. | 43 // Could not allocate histogram memory due to unknown error. |
44 CREATE_HISTOGRAM_ALLOCATOR_ERROR, | 44 CREATE_HISTOGRAM_ALLOCATOR_ERROR, |
45 | 45 |
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 // Always keep this at the end. | 49 // Always keep this at the end. |
50 CREATE_HISTOGRAM_MAX | 50 CREATE_HISTOGRAM_MAX |
51 }; | 51 }; |
52 | 52 |
53 // Name of histogram for storing results of local operations. | |
54 const char kResultHistogram[] = "UMA.CreatePersistentHistogram.Result"; | |
55 | |
53 // Type identifiers used when storing in persistent memory so they can be | 56 // Type identifiers used when storing in persistent memory so they can be |
54 // identified during extraction; the first 4 bytes of the SHA1 of the name | 57 // identified during extraction; the first 4 bytes of the SHA1 of the name |
55 // is used as a unique integer. A "version number" is added to the base | 58 // is used as a unique integer. A "version number" is added to the base |
56 // so that, if the structure of that object changes, stored older versions | 59 // so that, if the structure of that object changes, stored older versions |
57 // will be safely ignored. | 60 // will be safely ignored. |
58 enum : uint32_t { | 61 enum : uint32_t { |
59 kTypeIdHistogram = 0xF1645910 + 1, // SHA1(Histogram) v1 | 62 kTypeIdHistogram = 0xF1645910 + 1, // SHA1(Histogram) v1 |
60 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 | 63 kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1 |
61 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 | 64 kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1 |
62 }; | 65 }; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
142 base::subtle::Acquire_Load(&atomic_histogram_pointer))); | 145 base::subtle::Acquire_Load(&atomic_histogram_pointer))); |
143 if (!histogram_pointer) { | 146 if (!histogram_pointer) { |
144 // It's possible for multiple threads to make it here in parallel but | 147 // It's possible for multiple threads to make it here in parallel but |
145 // they'll always return the same result as there is a mutex in the Get. | 148 // they'll always return the same result as there is a mutex in the Get. |
146 // The purpose of the "initialized" variable is just to ensure that | 149 // The purpose of the "initialized" variable is just to ensure that |
147 // the same thread doesn't recurse which is also why it doesn't have | 150 // the same thread doesn't recurse which is also why it doesn't have |
148 // to be atomic. | 151 // to be atomic. |
149 static bool initialized = false; | 152 static bool initialized = false; |
150 if (!initialized) { | 153 if (!initialized) { |
151 initialized = true; | 154 initialized = true; |
155 if (g_allocator) { | |
156 DLOG(WARNING) << "Creating the results-histogram inside persistent" | |
157 << " memory can cause future allocations to crash if" | |
158 << " that memory is ever released (for testing)."; | |
159 } | |
160 | |
152 histogram_pointer = LinearHistogram::FactoryGet( | 161 histogram_pointer = LinearHistogram::FactoryGet( |
153 "UMA.CreatePersistentHistogram.Result", | 162 kResultHistogram, 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1, |
154 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1, | |
155 HistogramBase::kUmaTargetedHistogramFlag); | 163 HistogramBase::kUmaTargetedHistogramFlag); |
156 base::subtle::Release_Store( | 164 base::subtle::Release_Store( |
157 &atomic_histogram_pointer, | 165 &atomic_histogram_pointer, |
158 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); | 166 reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); |
159 } | 167 } |
160 } | 168 } |
161 return histogram_pointer; | 169 return histogram_pointer; |
162 } | 170 } |
163 | 171 |
164 // Record the result of a histogram creation. | 172 // Record the result of a histogram creation. |
165 void RecordCreateHistogramResult(CreateHistogramResultType result) { | 173 void RecordCreateHistogramResult(CreateHistogramResultType result) { |
166 HistogramBase* result_histogram = GetCreateHistogramResultHistogram(); | 174 HistogramBase* result_histogram = GetCreateHistogramResultHistogram(); |
167 if (result_histogram) | 175 if (result_histogram) |
168 result_histogram->Add(result); | 176 result_histogram->Add(result); |
169 } | 177 } |
170 | 178 |
171 void SetPersistentHistogramMemoryAllocator( | 179 void SetPersistentHistogramMemoryAllocator( |
172 PersistentMemoryAllocator* allocator) { | 180 PersistentMemoryAllocator* allocator) { |
173 // Releasing or changing an allocator is extremely dangerous because it | 181 // Releasing or changing an allocator is extremely dangerous because it |
174 // likely has histograms stored within it. If the backing memory is also | 182 // likely has histograms stored within it. If the backing memory is also |
175 // also released, future accesses to those histograms will seg-fault. | 183 // also released, future accesses to those histograms will seg-fault. |
176 // It's not a fatal CHECK() because tests do this knowing that all | 184 CHECK(!g_allocator); |
177 // such persistent histograms have already been forgotten. | |
178 if (g_allocator) { | |
179 LOG(WARNING) << "Active PersistentMemoryAllocator has been released." | |
180 << " Some existing histogram pointers may be invalid."; | |
181 delete g_allocator; | |
182 } | |
183 g_allocator = allocator; | 185 g_allocator = allocator; |
184 } | 186 } |
185 | 187 |
186 PersistentMemoryAllocator* GetPersistentHistogramMemoryAllocator() { | 188 PersistentMemoryAllocator* GetPersistentHistogramMemoryAllocator() { |
187 return g_allocator; | 189 return g_allocator; |
188 } | 190 } |
189 | 191 |
190 PersistentMemoryAllocator* ReleasePersistentHistogramMemoryAllocator() { | 192 PersistentMemoryAllocator* |
193 ReleasePersistentHistogramMemoryAllocatorForTesting() { | |
191 PersistentMemoryAllocator* allocator = g_allocator; | 194 PersistentMemoryAllocator* allocator = g_allocator; |
195 if (!allocator) | |
196 return nullptr; | |
197 | |
198 // Before releasing the memory, it's necessary to have the Statistics | |
199 // Recorder forget about the histograms contained within otherwise some | |
200 // operations will try to access it. | |
201 PersistentMemoryAllocator::Iterator iter; | |
202 PersistentMemoryAllocator::Reference ref; | |
203 uint32_t type_id; | |
204 allocator->CreateIterator(&iter); | |
205 while ((ref = allocator->GetNextIterable(&iter, &type_id)) != 0) { | |
206 if (type_id == kTypeIdHistogram) { | |
207 PersistentHistogramData* histogram_data = | |
208 allocator->GetAsObject<PersistentHistogramData>( | |
209 ref, kTypeIdHistogram); | |
210 DCHECK(histogram_data); | |
211 std::string name(histogram_data->name); | |
212 StatisticsRecorder::ForgetHistogramForTesting(name); | |
213 DLOG(WARNING) << "Dropped persistent histogram \"" << name << "\""; | |
214 | |
215 // Fix by calling GetCreateHistogramResultHistogram() before setting | |
216 // the (temporary) persistent memory allocator. | |
217 DCHECK_NE(kResultHistogram, name); | |
218 } | |
219 } | |
220 | |
192 g_allocator = nullptr; | 221 g_allocator = nullptr; |
193 return allocator; | 222 return allocator; |
194 }; | 223 }; |
195 | 224 |
196 HistogramBase* CreatePersistentHistogram( | 225 HistogramBase* CreatePersistentHistogram( |
197 PersistentMemoryAllocator* allocator, | 226 PersistentMemoryAllocator* allocator, |
198 PersistentHistogramData* histogram_data_ptr) { | 227 PersistentHistogramData* histogram_data_ptr) { |
199 if (!histogram_data_ptr) { | 228 if (!histogram_data_ptr) { |
200 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); | 229 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER); |
201 NOTREACHED(); | 230 NOTREACHED(); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
437 } | 466 } |
438 RecordCreateHistogramResult(result); | 467 RecordCreateHistogramResult(result); |
439 NOTREACHED() << "error=" << result; | 468 NOTREACHED() << "error=" << result; |
440 | 469 |
441 return nullptr; | 470 return nullptr; |
442 } | 471 } |
443 | 472 |
444 void ImportPersistentHistograms() { | 473 void ImportPersistentHistograms() { |
445 // The lock protects against concurrent access to the iterator and is created | 474 // The lock protects against concurrent access to the iterator and is created |
446 // in a thread-safe manner when needed. | 475 // in a thread-safe manner when needed. |
447 static base::LazyInstance<base::Lock> lock = LAZY_INSTANCE_INITIALIZER; | 476 static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER; |
448 | 477 |
449 if (g_allocator) { | 478 if (g_allocator) { |
450 base::AutoLock auto_lock(lock.Get()); | 479 base::AutoLock auto_lock(lock.Get()); |
451 | 480 |
452 // Each call resumes from where it last left off so need persistant | 481 // Each call resumes from where it last left off so need persistant |
453 // iterator. This class has a constructor so even the definition has | 482 // iterator. This class has a constructor so even the definition has |
454 // to be protected by the lock in order to be thread-safe. | 483 // to be protected by the lock in order to be thread-safe. |
455 static PersistentMemoryAllocator::Iterator iter; | 484 static PersistentMemoryAllocator::Iterator iter; |
456 if (iter.is_clear()) | 485 if (iter.is_clear()) |
457 g_allocator->CreateIterator(&iter); | 486 g_allocator->CreateIterator(&iter); |
458 | 487 |
459 for (;;) { | 488 for (;;) { |
grt (UTC plus 2)
2016/02/15 15:42:39
fyi for the future: "while (true)" is more common
bcwhite
2016/02/15 19:22:10
Done.
| |
460 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); | 489 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); |
461 if (!histogram) | 490 if (!histogram) |
462 break; | 491 break; |
463 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); | 492 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); |
464 } | 493 } |
465 } | 494 } |
466 } | 495 } |
467 | 496 |
468 } // namespace base | 497 } // namespace base |
OLD | NEW |