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

Side by Side Diff: base/tracked_objects.cc

Issue 2488073002: Reuse ThreadData instances associated with terminated named threads. (Closed)
Patch Set: rebase 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/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | 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/tracked_objects.h" 5 #include "base/tracked_objects.h"
6 6
7 #include <ctype.h>
7 #include <limits.h> 8 #include <limits.h>
8 #include <stdlib.h> 9 #include <stdlib.h>
9 10
10 #include "base/atomicops.h" 11 #include "base/atomicops.h"
11 #include "base/base_switches.h" 12 #include "base/base_switches.h"
12 #include "base/command_line.h" 13 #include "base/command_line.h"
13 #include "base/compiler_specific.h" 14 #include "base/compiler_specific.h"
14 #include "base/debug/leak_annotations.h" 15 #include "base/debug/leak_annotations.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/metrics/histogram_macros.h"
16 #include "base/numerics/safe_conversions.h" 18 #include "base/numerics/safe_conversions.h"
17 #include "base/numerics/safe_math.h" 19 #include "base/numerics/safe_math.h"
18 #include "base/process/process_handle.h" 20 #include "base/process/process_handle.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/third_party/valgrind/memcheck.h" 21 #include "base/third_party/valgrind/memcheck.h"
21 #include "base/threading/worker_pool.h" 22 #include "base/threading/worker_pool.h"
22 #include "base/tracking_info.h" 23 #include "base/tracking_info.h"
23 #include "build/build_config.h" 24 #include "build/build_config.h"
24 25
25 using base::TimeDelta; 26 using base::TimeDelta;
26 27
27 namespace base { 28 namespace base {
28 class TimeDelta; 29 class TimeDelta;
29 } 30 }
30 31
31 namespace tracked_objects { 32 namespace tracked_objects {
32 33
33 namespace { 34 namespace {
35
36 constexpr char kWorkerThreadSanitizedName[] = "WorkerThread-*";
37
34 // When ThreadData is first initialized, should we start in an ACTIVE state to 38 // When ThreadData is first initialized, should we start in an ACTIVE state to
35 // record all of the startup-time tasks, or should we start up DEACTIVATED, so 39 // record all of the startup-time tasks, or should we start up DEACTIVATED, so
36 // that we only record after parsing the command line flag --enable-tracking. 40 // that we only record after parsing the command line flag --enable-tracking.
37 // Note that the flag may force either state, so this really controls only the 41 // Note that the flag may force either state, so this really controls only the
38 // period of time up until that flag is parsed. If there is no flag seen, then 42 // period of time up until that flag is parsed. If there is no flag seen, then
39 // this state may prevail for much or all of the process lifetime. 43 // this state may prevail for much or all of the process lifetime.
40 const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE; 44 const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
41 45
42 // Possible states of the profiler timing enabledness. 46 // Possible states of the profiler timing enabledness.
43 enum { 47 enum {
(...skipping 25 matching lines...) Expand all
69 switches::kProfilerTiming) == 73 switches::kProfilerTiming) ==
70 switches::kProfilerTimingDisabledValue) 74 switches::kProfilerTimingDisabledValue)
71 ? DISABLED_TIMING 75 ? DISABLED_TIMING
72 : ENABLED_TIMING; 76 : ENABLED_TIMING;
73 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, 77 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled,
74 current_timing_enabled); 78 current_timing_enabled);
75 } 79 }
76 return current_timing_enabled == ENABLED_TIMING; 80 return current_timing_enabled == ENABLED_TIMING;
77 } 81 }
78 82
83 // Sanitize a thread name by replacing trailing sequence of digits with "*".
84 // Examples:
85 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*"
86 // 2. "Chrome_IOThread" => "Chrome_IOThread"
87 std::string SanitizeThreadName(const std::string& thread_name) {
88 size_t i = thread_name.length();
89
90 while (i > 0 && isdigit(thread_name[i - 1]))
91 --i;
92
93 if (i == thread_name.length())
94 return thread_name;
95
96 return thread_name.substr(0, i) + '*';
97 }
98
79 } // namespace 99 } // namespace
80 100
81 //------------------------------------------------------------------------------ 101 //------------------------------------------------------------------------------
82 // DeathData tallies durations when a death takes place. 102 // DeathData tallies durations when a death takes place.
83 103
84 DeathData::DeathData() 104 DeathData::DeathData()
85 : count_(0), 105 : count_(0),
86 sample_probability_count_(0), 106 sample_probability_count_(0),
87 run_duration_sum_(0), 107 run_duration_sum_(0),
88 queue_duration_sum_(0), 108 queue_duration_sum_(0),
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 : location_(location), 343 : location_(location),
324 birth_thread_(&current) { 344 birth_thread_(&current) {
325 } 345 }
326 346
327 //------------------------------------------------------------------------------ 347 //------------------------------------------------------------------------------
328 BirthOnThreadSnapshot::BirthOnThreadSnapshot() { 348 BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
329 } 349 }
330 350
331 BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth) 351 BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
332 : location(birth.location()), 352 : location(birth.location()),
333 thread_name(birth.birth_thread()->thread_name()) { 353 sanitized_thread_name(birth.birth_thread()->sanitized_thread_name()) {}
334 }
335 354
336 BirthOnThreadSnapshot::~BirthOnThreadSnapshot() { 355 BirthOnThreadSnapshot::~BirthOnThreadSnapshot() {
337 } 356 }
338 357
339 //------------------------------------------------------------------------------ 358 //------------------------------------------------------------------------------
340 Births::Births(const Location& location, const ThreadData& current) 359 Births::Births(const Location& location, const ThreadData& current)
341 : BirthOnThread(location, current), 360 : BirthOnThread(location, current),
342 birth_count_(1) { } 361 birth_count_(1) { }
343 362
344 int Births::birth_count() const { return birth_count_; } 363 int Births::birth_count() const { return birth_count_; }
(...skipping 11 matching lines...) Expand all
356 // static 375 // static
357 ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL; 376 ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL;
358 377
359 // A TLS slot which points to the ThreadData instance for the current thread. 378 // A TLS slot which points to the ThreadData instance for the current thread.
360 // We do a fake initialization here (zeroing out data), and then the real 379 // We do a fake initialization here (zeroing out data), and then the real
361 // in-place construction happens when we call tls_index_.Initialize(). 380 // in-place construction happens when we call tls_index_.Initialize().
362 // static 381 // static
363 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; 382 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
364 383
365 // static 384 // static
366 int ThreadData::worker_thread_data_creation_count_ = 0;
367
368 // static
369 int ThreadData::cleanup_count_ = 0; 385 int ThreadData::cleanup_count_ = 0;
370 386
371 // static 387 // static
372 int ThreadData::incarnation_counter_ = 0; 388 int ThreadData::incarnation_counter_ = 0;
373 389
374 // static 390 // static
375 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; 391 ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
376 392
377 // static 393 // static
378 ThreadData* ThreadData::first_retired_worker_ = NULL; 394 ThreadData* ThreadData::first_retired_thread_data_ = NULL;
379 395
380 // static 396 // static
381 base::LazyInstance<base::Lock>::Leaky 397 base::LazyInstance<base::Lock>::Leaky
382 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; 398 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
383 399
384 // static 400 // static
385 base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED; 401 base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED;
386 402
387 ThreadData::ThreadData(const std::string& suggested_name) 403 ThreadData::ThreadData(const std::string& sanitized_thread_name)
388 : next_(NULL), 404 : next_(NULL),
389 next_retired_worker_(NULL), 405 next_retired_thread_data_(NULL),
390 worker_thread_number_(0), 406 sanitized_thread_name_(sanitized_thread_name),
391 incarnation_count_for_pool_(-1), 407 incarnation_count_for_pool_(-1),
392 current_stopwatch_(NULL) { 408 current_stopwatch_(NULL) {
393 DCHECK_GE(suggested_name.size(), 0u); 409 DCHECK(sanitized_thread_name_.empty() ||
394 thread_name_ = suggested_name; 410 !isdigit(sanitized_thread_name_.back()));
395 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. 411 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
396 } 412 }
397 413
398 ThreadData::ThreadData(int thread_number)
399 : next_(NULL),
400 next_retired_worker_(NULL),
401 worker_thread_number_(thread_number),
402 incarnation_count_for_pool_(-1),
403 current_stopwatch_(NULL) {
404 CHECK_GT(thread_number, 0);
405 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
406 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
407 }
408
409 ThreadData::~ThreadData() { 414 ThreadData::~ThreadData() {
410 } 415 }
411 416
412 void ThreadData::PushToHeadOfList() { 417 void ThreadData::PushToHeadOfList() {
413 // Toss in a hint of randomness (atop the uniniitalized value). 418 // Toss in a hint of randomness (atop the uniniitalized value).
414 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, 419 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
415 sizeof(random_number_)); 420 sizeof(random_number_));
416 MSAN_UNPOISON(&random_number_, sizeof(random_number_)); 421 MSAN_UNPOISON(&random_number_, sizeof(random_number_));
417 random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0)); 422 random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0));
418 random_number_ ^= (Now() - TrackedTime()).InMilliseconds(); 423 random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
419 424
420 DCHECK(!next_); 425 DCHECK(!next_);
421 base::AutoLock lock(*list_lock_.Pointer()); 426 base::AutoLock lock(*list_lock_.Pointer());
422 incarnation_count_for_pool_ = incarnation_counter_; 427 incarnation_count_for_pool_ = incarnation_counter_;
423 next_ = all_thread_data_list_head_; 428 next_ = all_thread_data_list_head_;
424 all_thread_data_list_head_ = this; 429 all_thread_data_list_head_ = this;
425 } 430 }
426 431
427 // static 432 // static
428 ThreadData* ThreadData::first() { 433 ThreadData* ThreadData::first() {
429 base::AutoLock lock(*list_lock_.Pointer()); 434 base::AutoLock lock(*list_lock_.Pointer());
430 return all_thread_data_list_head_; 435 return all_thread_data_list_head_;
431 } 436 }
432 437
433 ThreadData* ThreadData::next() const { return next_; } 438 ThreadData* ThreadData::next() const { return next_; }
434 439
435 // static 440 // static
436 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { 441 void ThreadData::InitializeThreadContext(const std::string& thread_name) {
437 if (base::WorkerPool::RunsTasksOnCurrentThread()) 442 if (base::WorkerPool::RunsTasksOnCurrentThread())
438 return; 443 return;
444 DCHECK_NE(thread_name, kWorkerThreadSanitizedName);
439 EnsureTlsInitialization(); 445 EnsureTlsInitialization();
440 ThreadData* current_thread_data = 446 ThreadData* current_thread_data =
441 reinterpret_cast<ThreadData*>(tls_index_.Get()); 447 reinterpret_cast<ThreadData*>(tls_index_.Get());
442 if (current_thread_data) 448 if (current_thread_data)
443 return; // Browser tests instigate this. 449 return; // Browser tests instigate this.
444 current_thread_data = new ThreadData(suggested_name); 450 current_thread_data =
451 GetRetiredOrCreateThreadData(SanitizeThreadName(thread_name));
445 tls_index_.Set(current_thread_data); 452 tls_index_.Set(current_thread_data);
446 } 453 }
447 454
448 // static 455 // static
449 ThreadData* ThreadData::Get() { 456 ThreadData* ThreadData::Get() {
450 if (!tls_index_.initialized()) 457 if (!tls_index_.initialized())
451 return NULL; // For unittests only. 458 return NULL; // For unittests only.
452 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); 459 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get());
453 if (registered) 460 if (registered)
454 return registered; 461 return registered;
455 462
456 // We must be a worker thread, since we didn't pre-register. 463 // We must be a worker thread, since we didn't pre-register.
457 ThreadData* worker_thread_data = NULL; 464 ThreadData* worker_thread_data =
458 int worker_thread_number = 0; 465 GetRetiredOrCreateThreadData(kWorkerThreadSanitizedName);
459 {
460 base::AutoLock lock(*list_lock_.Pointer());
461 if (first_retired_worker_) {
462 worker_thread_data = first_retired_worker_;
463 first_retired_worker_ = first_retired_worker_->next_retired_worker_;
464 worker_thread_data->next_retired_worker_ = NULL;
465 } else {
466 worker_thread_number = ++worker_thread_data_creation_count_;
467 }
468 }
469
470 // If we can't find a previously used instance, then we have to create one.
471 if (!worker_thread_data) {
472 DCHECK_GT(worker_thread_number, 0);
473 worker_thread_data = new ThreadData(worker_thread_number);
474 }
475 DCHECK_GT(worker_thread_data->worker_thread_number_, 0);
476
477 tls_index_.Set(worker_thread_data); 466 tls_index_.Set(worker_thread_data);
478 return worker_thread_data; 467 return worker_thread_data;
479 } 468 }
480 469
481 // static 470 // static
482 void ThreadData::OnThreadTermination(void* thread_data) { 471 void ThreadData::OnThreadTermination(void* thread_data) {
483 DCHECK(thread_data); // TLS should *never* call us with a NULL. 472 DCHECK(thread_data); // TLS should *never* call us with a NULL.
484 // We must NOT do any allocations during this callback. There is a chance 473 // We must NOT do any allocations during this callback. There is a chance
485 // that the allocator is no longer active on this thread. 474 // that the allocator is no longer active on this thread.
486 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); 475 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
487 } 476 }
488 477
489 void ThreadData::OnThreadTerminationCleanup() { 478 void ThreadData::OnThreadTerminationCleanup() {
479 // We must NOT do any allocations during this callback. There is a chance that
480 // the allocator is no longer active on this thread.
481
490 // The list_lock_ was created when we registered the callback, so it won't be 482 // The list_lock_ was created when we registered the callback, so it won't be
491 // allocated here despite the lazy reference. 483 // allocated here despite the lazy reference.
492 base::AutoLock lock(*list_lock_.Pointer()); 484 base::AutoLock lock(*list_lock_.Pointer());
493 if (incarnation_counter_ != incarnation_count_for_pool_) 485 if (incarnation_counter_ != incarnation_count_for_pool_)
494 return; // ThreadData was constructed in an earlier unit test. 486 return; // ThreadData was constructed in an earlier unit test.
495 ++cleanup_count_; 487 ++cleanup_count_;
496 // Only worker threads need to be retired and reused. 488
497 if (!worker_thread_number_) { 489 // Add this ThreadData to a retired list so that it can be reused by a thread
498 return; 490 // with the same name sanitized name in the future.
499 } 491 // |next_retired_thread_data_| is expected to be nullptr for a ThreadData
500 // We must NOT do any allocations during this callback. 492 // associated with an active thread.
501 // Using the simple linked lists avoids all allocations. 493 DCHECK(!next_retired_thread_data_);
502 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); 494 next_retired_thread_data_ = first_retired_thread_data_;
503 this->next_retired_worker_ = first_retired_worker_; 495 first_retired_thread_data_ = this;
504 first_retired_worker_ = this;
505 } 496 }
506 497
507 // static 498 // static
508 void ThreadData::Snapshot(int current_profiling_phase, 499 void ThreadData::Snapshot(int current_profiling_phase,
509 ProcessDataSnapshot* process_data_snapshot) { 500 ProcessDataSnapshot* process_data_snapshot) {
510 // Get an unchanging copy of a ThreadData list. 501 // Get an unchanging copy of a ThreadData list.
511 ThreadData* my_list = ThreadData::first(); 502 ThreadData* my_list = ThreadData::first();
512 503
513 // Gather data serially. 504 // Gather data serially.
514 // This hackish approach *can* get some slightly corrupt tallies, as we are 505 // This hackish approach *can* get some slightly corrupt tallies, as we are
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 // phase, if any. Store the deltas in the result. 712 // phase, if any. Store the deltas in the result.
722 for (const DeathDataPhaseSnapshot* phase = &death.second; phase; 713 for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
723 phase = phase->prev) { 714 phase = phase->prev) {
724 const DeathDataSnapshot& death_data = 715 const DeathDataSnapshot& death_data =
725 phase->prev ? phase->death_data.Delta(phase->prev->death_data) 716 phase->prev ? phase->death_data.Delta(phase->prev->death_data)
726 : phase->death_data; 717 : phase->death_data;
727 718
728 if (death_data.count > 0) { 719 if (death_data.count > 0) {
729 (*phased_snapshots)[phase->profiling_phase].tasks.push_back( 720 (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
730 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data, 721 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
731 thread_name())); 722 sanitized_thread_name()));
732 } 723 }
733 } 724 }
734 } 725 }
735 } 726 }
736 727
737 // This may be called from another thread. 728 // This may be called from another thread.
738 void ThreadData::SnapshotMaps(int profiling_phase, 729 void ThreadData::SnapshotMaps(int profiling_phase,
739 BirthMap* birth_map, 730 BirthMap* birth_map,
740 DeathsSnapshot* deaths) { 731 DeathsSnapshot* deaths) {
741 base::AutoLock lock(map_lock_); 732 base::AutoLock lock(map_lock_);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 if (now_function_for_testing_) 831 if (now_function_for_testing_)
841 return TrackedTime::FromMilliseconds((*now_function_for_testing_)()); 832 return TrackedTime::FromMilliseconds((*now_function_for_testing_)());
842 if (IsProfilerTimingEnabled() && TrackingStatus()) 833 if (IsProfilerTimingEnabled() && TrackingStatus())
843 return TrackedTime::Now(); 834 return TrackedTime::Now();
844 return TrackedTime(); // Super fast when disabled, or not compiled. 835 return TrackedTime(); // Super fast when disabled, or not compiled.
845 } 836 }
846 837
847 // static 838 // static
848 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { 839 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) {
849 base::AutoLock lock(*list_lock_.Pointer()); 840 base::AutoLock lock(*list_lock_.Pointer());
850 if (worker_thread_data_creation_count_ == 0)
851 return; // We haven't really run much, and couldn't have leaked.
852 841
853 // TODO(jar): until this is working on XP, don't run the real test. 842 // TODO(jar): until this is working on XP, don't run the real test.
854 #if 0 843 #if 0
855 // Verify that we've at least shutdown/cleanup the major namesd threads. The 844 // Verify that we've at least shutdown/cleanup the major namesd threads. The
856 // caller should tell us how many thread shutdowns should have taken place by 845 // caller should tell us how many thread shutdowns should have taken place by
857 // now. 846 // now.
858 CHECK_GT(cleanup_count_, major_threads_shutdown_count); 847 CHECK_GT(cleanup_count_, major_threads_shutdown_count);
859 #endif 848 #endif
860 } 849 }
861 850
862 // static 851 // static
863 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) { 852 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
864 // This is only called from test code, where we need to cleanup so that 853 // This is only called from test code, where we need to cleanup so that
865 // additional tests can be run. 854 // additional tests can be run.
866 // We must be single threaded... but be careful anyway. 855 // We must be single threaded... but be careful anyway.
867 InitializeAndSetTrackingStatus(DEACTIVATED); 856 InitializeAndSetTrackingStatus(DEACTIVATED);
868 857
869 ThreadData* thread_data_list; 858 ThreadData* thread_data_list;
870 { 859 {
871 base::AutoLock lock(*list_lock_.Pointer()); 860 base::AutoLock lock(*list_lock_.Pointer());
872 thread_data_list = all_thread_data_list_head_; 861 thread_data_list = all_thread_data_list_head_;
873 all_thread_data_list_head_ = NULL; 862 all_thread_data_list_head_ = NULL;
874 ++incarnation_counter_; 863 ++incarnation_counter_;
875 // To be clean, break apart the retired worker list (though we leak them). 864 // To be clean, break apart the retired worker list (though we leak them).
876 while (first_retired_worker_) { 865 while (first_retired_thread_data_) {
877 ThreadData* worker = first_retired_worker_; 866 ThreadData* thread_data = first_retired_thread_data_;
878 CHECK_GT(worker->worker_thread_number_, 0); 867 first_retired_thread_data_ = thread_data->next_retired_thread_data_;
879 first_retired_worker_ = worker->next_retired_worker_; 868 thread_data->next_retired_thread_data_ = nullptr;
880 worker->next_retired_worker_ = NULL;
881 } 869 }
882 } 870 }
883 871
884 // Put most global static back in pristine shape. 872 // Put most global static back in pristine shape.
885 worker_thread_data_creation_count_ = 0;
886 cleanup_count_ = 0; 873 cleanup_count_ = 0;
887 tls_index_.Set(NULL); 874 tls_index_.Set(NULL);
888 // Almost UNINITIALIZED. 875 // Almost UNINITIALIZED.
889 base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS); 876 base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS);
890 877
891 // To avoid any chance of racing in unit tests, which is the only place we 878 // To avoid any chance of racing in unit tests, which is the only place we
892 // call this function, we may sometimes leak all the data structures we 879 // call this function, we may sometimes leak all the data structures we
893 // recovered, as they may still be in use on threads from prior tests! 880 // recovered, as they may still be in use on threads from prior tests!
894 if (leak) { 881 if (leak) {
895 ThreadData* thread_data = thread_data_list; 882 ThreadData* thread_data = thread_data_list;
(...skipping 11 matching lines...) Expand all
907 ThreadData* next_thread_data = thread_data_list; 894 ThreadData* next_thread_data = thread_data_list;
908 thread_data_list = thread_data_list->next(); 895 thread_data_list = thread_data_list->next();
909 896
910 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); 897 for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
911 next_thread_data->birth_map_.end() != it; ++it) 898 next_thread_data->birth_map_.end() != it; ++it)
912 delete it->second; // Delete the Birth Records. 899 delete it->second; // Delete the Birth Records.
913 delete next_thread_data; // Includes all Death Records. 900 delete next_thread_data; // Includes all Death Records.
914 } 901 }
915 } 902 }
916 903
904 // static
905 ThreadData* ThreadData::GetRetiredOrCreateThreadData(
906 const std::string& sanitized_thread_name) {
907 SCOPED_UMA_HISTOGRAM_TIMER("TrackedObjects.GetRetiredOrCreateThreadData");
908
909 {
910 base::AutoLock lock(*list_lock_.Pointer());
911 ThreadData** pcursor = &first_retired_thread_data_;
912 ThreadData* cursor = first_retired_thread_data_;
913
914 // Assuming that there aren't more than a few tens of retired ThreadData
915 // instances, this lookup should be quick compared to the thread creation
916 // time. Retired ThreadData instances cannot be stored in a map because
917 // insertions are done from OnThreadTerminationCleanup() where allocations
918 // are not allowed.
919 //
920 // Note: Test processes may have more than a few tens of retired ThreadData
921 // instances.
922 while (cursor) {
923 if (cursor->sanitized_thread_name() == sanitized_thread_name) {
924 DCHECK_EQ(*pcursor, cursor);
925 *pcursor = cursor->next_retired_thread_data_;
926 cursor->next_retired_thread_data_ = nullptr;
927 return cursor;
928 }
929 pcursor = &cursor->next_retired_thread_data_;
930 cursor = cursor->next_retired_thread_data_;
931 }
932 }
933
934 return new ThreadData(sanitized_thread_name);
935 }
936
917 //------------------------------------------------------------------------------ 937 //------------------------------------------------------------------------------
918 TaskStopwatch::TaskStopwatch() 938 TaskStopwatch::TaskStopwatch()
919 : wallclock_duration_ms_(0), 939 : wallclock_duration_ms_(0),
920 current_thread_data_(NULL), 940 current_thread_data_(NULL),
921 excluded_duration_ms_(0), 941 excluded_duration_ms_(0),
922 parent_(NULL) { 942 parent_(NULL) {
923 #if DCHECK_IS_ON() 943 #if DCHECK_IS_ON()
924 state_ = CREATED; 944 state_ = CREATED;
925 child_ = NULL; 945 child_ = NULL;
926 #endif 946 #endif
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 : profiling_phase(profiling_phase), death_data(death), prev(prev) {} 1051 : profiling_phase(profiling_phase), death_data(death), prev(prev) {}
1032 1052
1033 //------------------------------------------------------------------------------ 1053 //------------------------------------------------------------------------------
1034 // TaskSnapshot 1054 // TaskSnapshot
1035 1055
1036 TaskSnapshot::TaskSnapshot() { 1056 TaskSnapshot::TaskSnapshot() {
1037 } 1057 }
1038 1058
1039 TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth, 1059 TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
1040 const DeathDataSnapshot& death_data, 1060 const DeathDataSnapshot& death_data,
1041 const std::string& death_thread_name) 1061 const std::string& death_sanitized_thread_name)
1042 : birth(birth), 1062 : birth(birth),
1043 death_data(death_data), 1063 death_data(death_data),
1044 death_thread_name(death_thread_name) { 1064 death_sanitized_thread_name(death_sanitized_thread_name) {}
1045 }
1046 1065
1047 TaskSnapshot::~TaskSnapshot() { 1066 TaskSnapshot::~TaskSnapshot() {
1048 } 1067 }
1049 1068
1050 //------------------------------------------------------------------------------ 1069 //------------------------------------------------------------------------------
1051 // ProcessDataPhaseSnapshot 1070 // ProcessDataPhaseSnapshot
1052 1071
1053 ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() { 1072 ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
1054 } 1073 }
1055 1074
(...skipping 14 matching lines...) Expand all
1070 #endif 1089 #endif
1071 } 1090 }
1072 1091
1073 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) = 1092 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) =
1074 default; 1093 default;
1075 1094
1076 ProcessDataSnapshot::~ProcessDataSnapshot() { 1095 ProcessDataSnapshot::~ProcessDataSnapshot() {
1077 } 1096 }
1078 1097
1079 } // namespace tracked_objects 1098 } // namespace tracked_objects
OLDNEW
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698