| 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/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 Loading... |
| 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 Loading... |
| 323 : location_(location), | 343 : location_(location), |
| 324 birth_thread_(¤t) { | 344 birth_thread_(¤t) { |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |