Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1036)

Side by Side Diff: base/metrics/statistics_recorder.cc

Issue 2565893002: Fix TSAN race in access to StatisticsRecorder::lock_ (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/metrics/statistics_recorder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « base/metrics/statistics_recorder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698