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 |