OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/statistics_recorder.h" | 5 #include "base/metrics/statistics_recorder.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/at_exit.h" | 9 #include "base/at_exit.h" |
10 #include "base/debug/leak_annotations.h" | 10 #include "base/debug/leak_annotations.h" |
11 #include "base/json/string_escape.h" | 11 #include "base/json/string_escape.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/metrics/metrics_hashes.h" | 15 #include "base/metrics/metrics_hashes.h" |
16 #include "base/metrics/persistent_histogram_allocator.h" | 16 #include "base/metrics/persistent_histogram_allocator.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "base/synchronization/lock.h" | |
20 #include "base/values.h" | 19 #include "base/values.h" |
21 | 20 |
22 namespace { | 21 namespace { |
23 | 22 |
24 // Initialize histogram statistics gathering system. | 23 // Initialize histogram statistics gathering system. |
25 base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ = | 24 base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ = |
26 LAZY_INSTANCE_INITIALIZER; | 25 LAZY_INSTANCE_INITIALIZER; |
27 | 26 |
28 bool HistogramNameLesser(const base::HistogramBase* a, | 27 bool HistogramNameLesser(const base::HistogramBase* a, |
29 const base::HistogramBase* b) { | 28 const base::HistogramBase* b) { |
(...skipping 22 matching lines...) Expand all Loading... | |
52 const HistogramIterator& rhs) | 51 const HistogramIterator& rhs) |
53 : iter_(rhs.iter_), | 52 : iter_(rhs.iter_), |
54 include_persistent_(rhs.include_persistent_) { | 53 include_persistent_(rhs.include_persistent_) { |
55 } | 54 } |
56 | 55 |
57 StatisticsRecorder::HistogramIterator::~HistogramIterator() {} | 56 StatisticsRecorder::HistogramIterator::~HistogramIterator() {} |
58 | 57 |
59 StatisticsRecorder::HistogramIterator& | 58 StatisticsRecorder::HistogramIterator& |
60 StatisticsRecorder::HistogramIterator::operator++() { | 59 StatisticsRecorder::HistogramIterator::operator++() { |
61 const HistogramMap::iterator histograms_end = histograms_->end(); | 60 const HistogramMap::iterator histograms_end = histograms_->end(); |
62 if (iter_ == histograms_end || lock_ == NULL) | 61 if (iter_ == histograms_end) |
63 return *this; | 62 return *this; |
64 | 63 |
65 base::AutoLock auto_lock(*lock_); | 64 base::AutoLock auto_lock(lock_.Get()); |
66 | 65 |
67 for (;;) { | 66 for (;;) { |
68 ++iter_; | 67 ++iter_; |
69 if (iter_ == histograms_end) | 68 if (iter_ == histograms_end) |
70 break; | 69 break; |
71 if (!include_persistent_ && (iter_->second->flags() & | 70 if (!include_persistent_ && (iter_->second->flags() & |
72 HistogramBase::kIsPersistent)) { | 71 HistogramBase::kIsPersistent)) { |
73 continue; | 72 continue; |
74 } | 73 } |
75 break; | 74 break; |
76 } | 75 } |
77 | 76 |
78 return *this; | 77 return *this; |
79 } | 78 } |
80 | 79 |
81 StatisticsRecorder::~StatisticsRecorder() { | 80 StatisticsRecorder::~StatisticsRecorder() { |
82 DCHECK(lock_); | |
83 DCHECK(histograms_); | 81 DCHECK(histograms_); |
84 DCHECK(ranges_); | 82 DCHECK(ranges_); |
85 | 83 |
86 // Clean out what this object created and then restore what existed before. | 84 // Clean out what this object created and then restore what existed before. |
87 Reset(); | 85 Reset(); |
88 base::AutoLock auto_lock(*lock_); | 86 base::AutoLock auto_lock(lock_.Get()); |
89 histograms_ = existing_histograms_.release(); | 87 histograms_ = existing_histograms_.release(); |
90 callbacks_ = existing_callbacks_.release(); | 88 callbacks_ = existing_callbacks_.release(); |
91 ranges_ = existing_ranges_.release(); | 89 ranges_ = existing_ranges_.release(); |
92 } | 90 } |
93 | 91 |
94 // static | 92 // static |
95 void StatisticsRecorder::Initialize() { | 93 void StatisticsRecorder::Initialize() { |
96 // Tests sometimes create local StatisticsRecorders in order to provide a | 94 // Tests sometimes create local StatisticsRecorders in order to provide a |
97 // contained environment of histograms that can be later discarded. If a | 95 // contained environment of histograms that can be later discarded. If a |
98 // true global instance gets created in this environment then it will | 96 // true global instance gets created in this environment then it will |
99 // eventually get disconnected when the local instance destructs and | 97 // eventually get disconnected when the local instance destructs and |
100 // restores the previous state, resulting in no StatisticsRecorder at all. | 98 // restores the previous state, resulting in no StatisticsRecorder at all. |
101 // The global lazy instance, however, will remain valid thus ensuring that | 99 // The global lazy instance, however, will remain valid thus ensuring that |
102 // another never gets installed via this method. If a |histograms_| map | 100 // another never gets installed via this method. If a |histograms_| map |
103 // exists then assume the StatisticsRecorder is already "initialized". | 101 // exists then assume the StatisticsRecorder is already "initialized". |
104 if (histograms_) | 102 if (histograms_) |
105 return; | 103 return; |
106 | 104 |
107 // Ensure that an instance of the StatisticsRecorder object is created. | 105 // Ensure that an instance of the StatisticsRecorder object is created. |
108 g_statistics_recorder_.Get(); | 106 g_statistics_recorder_.Get(); |
109 } | 107 } |
110 | 108 |
111 // static | 109 // static |
112 bool StatisticsRecorder::IsActive() { | 110 bool StatisticsRecorder::IsActive() { |
113 if (lock_ == NULL) | 111 base::AutoLock auto_lock(lock_.Get()); |
114 return false; | 112 return !!histograms_; |
Alexei Svitkine (slow)
2016/12/09 23:20:10
Nit: I find != nullptr more readable.
gab
2016/12/09 23:27:37
Done.
| |
115 base::AutoLock auto_lock(*lock_); | |
116 return NULL != histograms_; | |
117 } | 113 } |
118 | 114 |
119 // static | 115 // static |
120 HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate( | 116 HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate( |
121 HistogramBase* histogram) { | 117 HistogramBase* histogram) { |
122 // As per crbug.com/79322 the histograms are intentionally leaked, so we need | 118 HistogramBase* histogram_to_delete = nullptr; |
123 // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once | 119 HistogramBase* histogram_to_return = nullptr; |
124 // for an object, the duplicates should not be annotated. | 120 { |
125 // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr) | 121 base::AutoLock auto_lock(lock_.Get()); |
126 // twice if (lock_ == NULL) || (!histograms_). | 122 if (!histograms_) { |
127 if (lock_ == NULL) { | 123 histogram_to_return = histogram; |
128 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 | |
129 return histogram; | |
130 } | |
131 | 124 |
132 HistogramBase* histogram_to_delete = NULL; | 125 // As per crbug.com/79322 the histograms are intentionally leaked, so we |
133 HistogramBase* histogram_to_return = NULL; | 126 // need to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used |
134 { | 127 // only once for an object, the duplicates should not be annotated. |
135 base::AutoLock auto_lock(*lock_); | 128 // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr) |
136 if (histograms_ == NULL) { | 129 // twice |if (!histograms_)|. |
137 histogram_to_return = histogram; | 130 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 |
138 } else { | 131 } else { |
139 const std::string& name = histogram->histogram_name(); | 132 const std::string& name = histogram->histogram_name(); |
140 HistogramMap::iterator it = histograms_->find(name); | 133 HistogramMap::iterator it = histograms_->find(name); |
141 if (histograms_->end() == it) { | 134 if (histograms_->end() == it) { |
142 // The StringKey references the name within |histogram| rather than | 135 // The StringKey references the name within |histogram| rather than |
143 // making a copy. | 136 // making a copy. |
144 (*histograms_)[name] = histogram; | 137 (*histograms_)[name] = histogram; |
145 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 | 138 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 |
146 // If there are callbacks for this histogram, we set the kCallbackExists | 139 // If there are callbacks for this histogram, we set the kCallbackExists |
147 // flag. | 140 // flag. |
(...skipping 20 matching lines...) Expand all Loading... | |
168 delete histogram_to_delete; | 161 delete histogram_to_delete; |
169 return histogram_to_return; | 162 return histogram_to_return; |
170 } | 163 } |
171 | 164 |
172 // static | 165 // static |
173 const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges( | 166 const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges( |
174 const BucketRanges* ranges) { | 167 const BucketRanges* ranges) { |
175 DCHECK(ranges->HasValidChecksum()); | 168 DCHECK(ranges->HasValidChecksum()); |
176 std::unique_ptr<const BucketRanges> ranges_deleter; | 169 std::unique_ptr<const BucketRanges> ranges_deleter; |
177 | 170 |
178 if (lock_ == NULL) { | 171 base::AutoLock auto_lock(lock_.Get()); |
172 if (!ranges_) { | |
179 ANNOTATE_LEAKING_OBJECT_PTR(ranges); | 173 ANNOTATE_LEAKING_OBJECT_PTR(ranges); |
180 return ranges; | 174 return ranges; |
181 } | 175 } |
182 | |
183 base::AutoLock auto_lock(*lock_); | |
184 if (ranges_ == NULL) { | |
185 ANNOTATE_LEAKING_OBJECT_PTR(ranges); | |
186 return ranges; | |
187 } | |
188 | 176 |
189 std::list<const BucketRanges*>* checksum_matching_list; | 177 std::list<const BucketRanges*>* checksum_matching_list; |
190 RangesMap::iterator ranges_it = ranges_->find(ranges->checksum()); | 178 RangesMap::iterator ranges_it = ranges_->find(ranges->checksum()); |
191 if (ranges_->end() == ranges_it) { | 179 if (ranges_->end() == ranges_it) { |
192 // Add a new matching list to map. | 180 // Add a new matching list to map. |
193 checksum_matching_list = new std::list<const BucketRanges*>(); | 181 checksum_matching_list = new std::list<const BucketRanges*>(); |
194 ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list); | 182 ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list); |
195 (*ranges_)[ranges->checksum()] = checksum_matching_list; | 183 (*ranges_)[ranges->checksum()] = checksum_matching_list; |
196 } else { | 184 } else { |
197 checksum_matching_list = ranges_it->second; | 185 checksum_matching_list = ranges_it->second; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 std::string json; | 259 std::string json; |
272 histogram->WriteJSON(&json); | 260 histogram->WriteJSON(&json); |
273 output += json; | 261 output += json; |
274 } | 262 } |
275 output += "]}"; | 263 output += "]}"; |
276 return output; | 264 return output; |
277 } | 265 } |
278 | 266 |
279 // static | 267 // static |
280 void StatisticsRecorder::GetHistograms(Histograms* output) { | 268 void StatisticsRecorder::GetHistograms(Histograms* output) { |
281 if (lock_ == NULL) | 269 base::AutoLock auto_lock(lock_.Get()); |
282 return; | 270 if (!histograms_) |
283 base::AutoLock auto_lock(*lock_); | |
284 if (histograms_ == NULL) | |
285 return; | 271 return; |
286 | 272 |
287 for (const auto& entry : *histograms_) { | 273 for (const auto& entry : *histograms_) { |
288 output->push_back(entry.second); | 274 output->push_back(entry.second); |
289 } | 275 } |
290 } | 276 } |
291 | 277 |
292 // static | 278 // static |
293 void StatisticsRecorder::GetBucketRanges( | 279 void StatisticsRecorder::GetBucketRanges( |
294 std::vector<const BucketRanges*>* output) { | 280 std::vector<const BucketRanges*>* output) { |
295 if (lock_ == NULL) | 281 base::AutoLock auto_lock(lock_.Get()); |
296 return; | 282 if (!ranges_) |
297 base::AutoLock auto_lock(*lock_); | |
298 if (ranges_ == NULL) | |
299 return; | 283 return; |
300 | 284 |
301 for (const auto& entry : *ranges_) { | 285 for (const auto& entry : *ranges_) { |
302 for (auto* range_entry : *entry.second) { | 286 for (auto* range_entry : *entry.second) { |
303 output->push_back(range_entry); | 287 output->push_back(range_entry); |
304 } | 288 } |
305 } | 289 } |
306 } | 290 } |
307 | 291 |
308 // static | 292 // static |
309 HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) { | 293 HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) { |
310 // This must be called *before* the lock is acquired below because it will | 294 // This must be called *before* the lock is acquired below because it will |
311 // call back into this object to register histograms. Those called methods | 295 // call back into this object to register histograms. Those called methods |
312 // will acquire the lock at that time. | 296 // will acquire the lock at that time. |
313 ImportGlobalPersistentHistograms(); | 297 ImportGlobalPersistentHistograms(); |
314 | 298 |
315 if (lock_ == NULL) | 299 base::AutoLock auto_lock(lock_.Get()); |
316 return NULL; | 300 if (!histograms_) |
317 base::AutoLock auto_lock(*lock_); | 301 return nullptr; |
318 if (histograms_ == NULL) | |
319 return NULL; | |
320 | 302 |
321 HistogramMap::iterator it = histograms_->find(name); | 303 HistogramMap::iterator it = histograms_->find(name); |
322 if (histograms_->end() == it) | 304 if (histograms_->end() == it) |
323 return NULL; | 305 return nullptr; |
324 return it->second; | 306 return it->second; |
325 } | 307 } |
326 | 308 |
327 // static | 309 // static |
328 StatisticsRecorder::HistogramIterator StatisticsRecorder::begin( | 310 StatisticsRecorder::HistogramIterator StatisticsRecorder::begin( |
329 bool include_persistent) { | 311 bool include_persistent) { |
330 DCHECK(histograms_); | 312 DCHECK(histograms_); |
331 ImportGlobalPersistentHistograms(); | 313 ImportGlobalPersistentHistograms(); |
332 | 314 |
333 HistogramMap::iterator iter_begin; | 315 HistogramMap::iterator iter_begin; |
334 { | 316 { |
335 base::AutoLock auto_lock(*lock_); | 317 base::AutoLock auto_lock(lock_.Get()); |
336 iter_begin = histograms_->begin(); | 318 iter_begin = histograms_->begin(); |
337 } | 319 } |
338 return HistogramIterator(iter_begin, include_persistent); | 320 return HistogramIterator(iter_begin, include_persistent); |
339 } | 321 } |
340 | 322 |
341 // static | 323 // static |
342 StatisticsRecorder::HistogramIterator StatisticsRecorder::end() { | 324 StatisticsRecorder::HistogramIterator StatisticsRecorder::end() { |
343 HistogramMap::iterator iter_end; | 325 HistogramMap::iterator iter_end; |
344 { | 326 { |
345 base::AutoLock auto_lock(*lock_); | 327 base::AutoLock auto_lock(lock_.Get()); |
346 iter_end = histograms_->end(); | 328 iter_end = histograms_->end(); |
347 } | 329 } |
348 return HistogramIterator(iter_end, true); | 330 return HistogramIterator(iter_end, true); |
349 } | 331 } |
350 | 332 |
351 // static | 333 // static |
352 void StatisticsRecorder::InitLogOnShutdown() { | 334 void StatisticsRecorder::InitLogOnShutdown() { |
353 if (lock_ == nullptr) | 335 if (!histograms_) |
354 return; | 336 return; |
355 base::AutoLock auto_lock(*lock_); | 337 |
338 base::AutoLock auto_lock(lock_.Get()); | |
356 g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock(); | 339 g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock(); |
357 } | 340 } |
358 | 341 |
359 // static | 342 // static |
360 void StatisticsRecorder::GetSnapshot(const std::string& query, | 343 void StatisticsRecorder::GetSnapshot(const std::string& query, |
361 Histograms* snapshot) { | 344 Histograms* snapshot) { |
362 if (lock_ == NULL) | 345 base::AutoLock auto_lock(lock_.Get()); |
363 return; | 346 if (!histograms_) |
364 base::AutoLock auto_lock(*lock_); | |
365 if (histograms_ == NULL) | |
366 return; | 347 return; |
367 | 348 |
368 for (const auto& entry : *histograms_) { | 349 for (const auto& entry : *histograms_) { |
369 if (entry.second->histogram_name().find(query) != std::string::npos) | 350 if (entry.second->histogram_name().find(query) != std::string::npos) |
370 snapshot->push_back(entry.second); | 351 snapshot->push_back(entry.second); |
371 } | 352 } |
372 } | 353 } |
373 | 354 |
374 // static | 355 // static |
375 bool StatisticsRecorder::SetCallback( | 356 bool StatisticsRecorder::SetCallback( |
376 const std::string& name, | 357 const std::string& name, |
377 const StatisticsRecorder::OnSampleCallback& cb) { | 358 const StatisticsRecorder::OnSampleCallback& cb) { |
378 DCHECK(!cb.is_null()); | 359 DCHECK(!cb.is_null()); |
379 if (lock_ == NULL) | 360 base::AutoLock auto_lock(lock_.Get()); |
380 return false; | 361 if (!histograms_) |
381 base::AutoLock auto_lock(*lock_); | |
382 if (histograms_ == NULL) | |
383 return false; | 362 return false; |
384 | 363 |
385 if (ContainsKey(*callbacks_, name)) | 364 if (ContainsKey(*callbacks_, name)) |
386 return false; | 365 return false; |
387 callbacks_->insert(std::make_pair(name, cb)); | 366 callbacks_->insert(std::make_pair(name, cb)); |
388 | 367 |
389 auto it = histograms_->find(name); | 368 auto it = histograms_->find(name); |
390 if (it != histograms_->end()) | 369 if (it != histograms_->end()) |
391 it->second->SetFlags(HistogramBase::kCallbackExists); | 370 it->second->SetFlags(HistogramBase::kCallbackExists); |
392 | 371 |
393 return true; | 372 return true; |
394 } | 373 } |
395 | 374 |
396 // static | 375 // static |
397 void StatisticsRecorder::ClearCallback(const std::string& name) { | 376 void StatisticsRecorder::ClearCallback(const std::string& name) { |
398 if (lock_ == NULL) | 377 base::AutoLock auto_lock(lock_.Get()); |
399 return; | 378 if (!histograms_) |
400 base::AutoLock auto_lock(*lock_); | |
401 if (histograms_ == NULL) | |
402 return; | 379 return; |
403 | 380 |
404 callbacks_->erase(name); | 381 callbacks_->erase(name); |
405 | 382 |
406 // We also clear the flag from the histogram (if it exists). | 383 // We also clear the flag from the histogram (if it exists). |
407 auto it = histograms_->find(name); | 384 auto it = histograms_->find(name); |
408 if (it != histograms_->end()) | 385 if (it != histograms_->end()) |
409 it->second->ClearFlags(HistogramBase::kCallbackExists); | 386 it->second->ClearFlags(HistogramBase::kCallbackExists); |
410 } | 387 } |
411 | 388 |
412 // static | 389 // static |
413 StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback( | 390 StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback( |
414 const std::string& name) { | 391 const std::string& name) { |
415 if (lock_ == NULL) | 392 base::AutoLock auto_lock(lock_.Get()); |
416 return OnSampleCallback(); | 393 if (!histograms_) |
417 base::AutoLock auto_lock(*lock_); | |
418 if (histograms_ == NULL) | |
419 return OnSampleCallback(); | 394 return OnSampleCallback(); |
420 | 395 |
421 auto callback_iterator = callbacks_->find(name); | 396 auto callback_iterator = callbacks_->find(name); |
422 return callback_iterator != callbacks_->end() ? callback_iterator->second | 397 return callback_iterator != callbacks_->end() ? callback_iterator->second |
423 : OnSampleCallback(); | 398 : OnSampleCallback(); |
424 } | 399 } |
425 | 400 |
426 // static | 401 // static |
427 size_t StatisticsRecorder::GetHistogramCount() { | 402 size_t StatisticsRecorder::GetHistogramCount() { |
428 if (!lock_) | 403 base::AutoLock auto_lock(lock_.Get()); |
429 return 0; | |
430 | |
431 base::AutoLock auto_lock(*lock_); | |
432 if (!histograms_) | 404 if (!histograms_) |
433 return 0; | 405 return 0; |
434 return histograms_->size(); | 406 return histograms_->size(); |
435 } | 407 } |
436 | 408 |
437 // static | 409 // static |
438 void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) { | 410 void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) { |
439 if (histograms_) | 411 if (histograms_) |
440 histograms_->erase(name); | 412 histograms_->erase(name); |
441 } | 413 } |
442 | 414 |
443 // static | 415 // static |
444 std::unique_ptr<StatisticsRecorder> | 416 std::unique_ptr<StatisticsRecorder> |
445 StatisticsRecorder::CreateTemporaryForTesting() { | 417 StatisticsRecorder::CreateTemporaryForTesting() { |
446 return WrapUnique(new StatisticsRecorder()); | 418 return WrapUnique(new StatisticsRecorder()); |
447 } | 419 } |
448 | 420 |
449 // static | 421 // static |
450 void StatisticsRecorder::UninitializeForTesting() { | 422 void StatisticsRecorder::UninitializeForTesting() { |
451 // Stop now if it's never been initialized. | 423 // Stop now if it's never been initialized. |
452 if (lock_ == NULL || histograms_ == NULL) | 424 if (!histograms_) |
453 return; | 425 return; |
454 | 426 |
455 // Get the global instance and destruct it. It's held in static memory so | 427 // Get the global instance and destruct it. It's held in static memory so |
456 // can't "delete" it; call the destructor explicitly. | 428 // can't "delete" it; call the destructor explicitly. |
457 DCHECK(g_statistics_recorder_.private_instance_); | 429 DCHECK(g_statistics_recorder_.private_instance_); |
458 g_statistics_recorder_.Get().~StatisticsRecorder(); | 430 g_statistics_recorder_.Get().~StatisticsRecorder(); |
459 | 431 |
460 // Now the ugly part. There's no official way to release a LazyInstance once | 432 // Now the ugly part. There's no official way to release a LazyInstance once |
461 // created so it's necessary to clear out an internal variable which | 433 // created so it's necessary to clear out an internal variable which |
462 // shouldn't be publicly visible but is for initialization reasons. | 434 // shouldn't be publicly visible but is for initialization reasons. |
463 g_statistics_recorder_.private_instance_ = 0; | 435 g_statistics_recorder_.private_instance_ = 0; |
464 } | 436 } |
465 | 437 |
466 // static | 438 // static |
467 void StatisticsRecorder::ImportGlobalPersistentHistograms() { | 439 void StatisticsRecorder::ImportGlobalPersistentHistograms() { |
468 if (lock_ == NULL) | 440 if (!histograms_) |
469 return; | 441 return; |
470 | 442 |
471 // Import histograms from known persistent storage. Histograms could have | 443 // Import histograms from known persistent storage. Histograms could have |
472 // been added by other processes and they must be fetched and recognized | 444 // been added by other processes and they must be fetched and recognized |
473 // locally. If the persistent memory segment is not shared between processes, | 445 // locally. If the persistent memory segment is not shared between processes, |
474 // this call does nothing. | 446 // this call does nothing. |
475 GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get(); | 447 GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get(); |
476 if (allocator) | 448 if (allocator) |
477 allocator->ImportHistogramsToStatisticsRecorder(); | 449 allocator->ImportHistogramsToStatisticsRecorder(); |
478 } | 450 } |
479 | 451 |
480 // This singleton instance should be started during the single threaded portion | 452 // This singleton instance should be started during the single threaded portion |
481 // of main(), and hence it is not thread safe. It initializes globals to | 453 // of main(), and hence it is not thread safe. It initializes globals to |
482 // provide support for all future calls. | 454 // provide support for all future calls. |
483 StatisticsRecorder::StatisticsRecorder() { | 455 StatisticsRecorder::StatisticsRecorder() { |
484 if (lock_ == NULL) { | 456 base::AutoLock auto_lock(lock_.Get()); |
485 // This will leak on purpose. It's the only way to make sure we won't race | |
486 // against the static uninitialization of the module while one of our | |
487 // static methods relying on the lock get called at an inappropriate time | |
488 // during the termination phase. Since it's a static data member, we will | |
489 // leak one per process, which would be similar to the instance allocated | |
490 // during static initialization and released only on process termination. | |
491 lock_ = new base::Lock; | |
492 } | |
493 | |
494 base::AutoLock auto_lock(*lock_); | |
495 | 457 |
496 existing_histograms_.reset(histograms_); | 458 existing_histograms_.reset(histograms_); |
497 existing_callbacks_.reset(callbacks_); | 459 existing_callbacks_.reset(callbacks_); |
498 existing_ranges_.reset(ranges_); | 460 existing_ranges_.reset(ranges_); |
499 | 461 |
500 histograms_ = new HistogramMap; | 462 histograms_ = new HistogramMap; |
501 callbacks_ = new CallbackMap; | 463 callbacks_ = new CallbackMap; |
502 ranges_ = new RangesMap; | 464 ranges_ = new RangesMap; |
503 | 465 |
504 InitLogOnShutdownWithoutLock(); | 466 InitLogOnShutdownWithoutLock(); |
505 } | 467 } |
506 | 468 |
507 void StatisticsRecorder::InitLogOnShutdownWithoutLock() { | 469 void StatisticsRecorder::InitLogOnShutdownWithoutLock() { |
508 if (!vlog_initialized_ && VLOG_IS_ON(1)) { | 470 if (!vlog_initialized_ && VLOG_IS_ON(1)) { |
509 vlog_initialized_ = true; | 471 vlog_initialized_ = true; |
510 AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); | 472 AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); |
511 } | 473 } |
512 } | 474 } |
513 | 475 |
514 // static | 476 // static |
515 void StatisticsRecorder::Reset() { | 477 void StatisticsRecorder::Reset() { |
516 // If there's no lock then there is nothing to reset. | |
517 if (!lock_) | |
518 return; | |
519 | 478 |
520 std::unique_ptr<HistogramMap> histograms_deleter; | 479 std::unique_ptr<HistogramMap> histograms_deleter; |
521 std::unique_ptr<CallbackMap> callbacks_deleter; | 480 std::unique_ptr<CallbackMap> callbacks_deleter; |
522 std::unique_ptr<RangesMap> ranges_deleter; | 481 std::unique_ptr<RangesMap> ranges_deleter; |
523 // We don't delete lock_ on purpose to avoid having to properly protect | |
524 // against it going away after we checked for NULL in the static methods. | |
525 { | 482 { |
526 base::AutoLock auto_lock(*lock_); | 483 base::AutoLock auto_lock(lock_.Get()); |
527 histograms_deleter.reset(histograms_); | 484 histograms_deleter.reset(histograms_); |
528 callbacks_deleter.reset(callbacks_); | 485 callbacks_deleter.reset(callbacks_); |
529 ranges_deleter.reset(ranges_); | 486 ranges_deleter.reset(ranges_); |
530 histograms_ = NULL; | 487 histograms_ = nullptr; |
531 callbacks_ = NULL; | 488 callbacks_ = nullptr; |
532 ranges_ = NULL; | 489 ranges_ = nullptr; |
533 } | 490 } |
534 // We are going to leak the histograms and the ranges. | 491 // We are going to leak the histograms and the ranges. |
535 } | 492 } |
536 | 493 |
537 // static | 494 // static |
538 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { | 495 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { |
539 std::string output; | 496 std::string output; |
540 StatisticsRecorder::WriteGraph(std::string(), &output); | 497 StatisticsRecorder::WriteGraph(std::string(), &output); |
541 VLOG(1) << output; | 498 VLOG(1) << output; |
542 } | 499 } |
543 | 500 |
544 | 501 |
545 // static | 502 // static |
546 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 503 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = nullptr; |
547 // static | 504 // static |
548 StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL; | 505 StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = nullptr; |
549 // static | 506 // static |
550 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL; | 507 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = nullptr; |
551 // static | 508 // static |
552 base::Lock* StatisticsRecorder::lock_ = NULL; | 509 base::LazyInstance<base::Lock>::Leaky StatisticsRecorder::lock_ = |
510 LAZY_INSTANCE_INITIALIZER; | |
553 | 511 |
554 } // namespace base | 512 } // namespace base |
OLD | NEW |