Chromium Code Reviews| 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" |
| 16 #include "base/process/process_handle.h" | 17 #include "base/process/process_handle.h" |
| 17 #include "base/strings/stringprintf.h" | |
| 18 #include "base/third_party/valgrind/memcheck.h" | 18 #include "base/third_party/valgrind/memcheck.h" |
| 19 #include "base/threading/worker_pool.h" | 19 #include "base/threading/worker_pool.h" |
| 20 #include "base/tracking_info.h" | 20 #include "base/tracking_info.h" |
| 21 #include "build/build_config.h" | 21 #include "build/build_config.h" |
| 22 | 22 |
| 23 using base::TimeDelta; | 23 using base::TimeDelta; |
| 24 | 24 |
| 25 namespace base { | 25 namespace base { |
| 26 class TimeDelta; | 26 class TimeDelta; |
| 27 } | 27 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 switches::kProfilerTiming) == | 67 switches::kProfilerTiming) == |
| 68 switches::kProfilerTimingDisabledValue) | 68 switches::kProfilerTimingDisabledValue) |
| 69 ? DISABLED_TIMING | 69 ? DISABLED_TIMING |
| 70 : ENABLED_TIMING; | 70 : ENABLED_TIMING; |
| 71 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, | 71 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, |
| 72 current_timing_enabled); | 72 current_timing_enabled); |
| 73 } | 73 } |
| 74 return current_timing_enabled == ENABLED_TIMING; | 74 return current_timing_enabled == ENABLED_TIMING; |
| 75 } | 75 } |
| 76 | 76 |
| 77 // Sanitize a thread name by replacing trailing sequence of digits with "*". | |
| 78 // Examples: | |
| 79 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*" | |
| 80 // 2. "Chrome_IOThread" => "Chrome_IOThread" | |
| 81 std::string SanitizeThreadName(const std::string& thread_name) { | |
| 82 size_t i = thread_name.length(); | |
| 83 | |
| 84 while (i > 0 && isdigit(thread_name[i - 1])) | |
| 85 --i; | |
| 86 | |
| 87 if (i == thread_name.length()) | |
| 88 return thread_name; | |
| 89 | |
| 90 return thread_name.substr(0, i) + '*'; | |
| 91 } | |
| 92 | |
| 77 } // namespace | 93 } // namespace |
| 78 | 94 |
| 79 //------------------------------------------------------------------------------ | 95 //------------------------------------------------------------------------------ |
| 80 // DeathData tallies durations when a death takes place. | 96 // DeathData tallies durations when a death takes place. |
| 81 | 97 |
| 82 DeathData::DeathData() | 98 DeathData::DeathData() |
| 83 : count_(0), | 99 : count_(0), |
| 84 sample_probability_count_(0), | 100 sample_probability_count_(0), |
| 85 run_duration_sum_(0), | 101 run_duration_sum_(0), |
| 86 queue_duration_sum_(0), | 102 queue_duration_sum_(0), |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 245 : location_(location), | 261 : location_(location), |
| 246 birth_thread_(¤t) { | 262 birth_thread_(¤t) { |
| 247 } | 263 } |
| 248 | 264 |
| 249 //------------------------------------------------------------------------------ | 265 //------------------------------------------------------------------------------ |
| 250 BirthOnThreadSnapshot::BirthOnThreadSnapshot() { | 266 BirthOnThreadSnapshot::BirthOnThreadSnapshot() { |
| 251 } | 267 } |
| 252 | 268 |
| 253 BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth) | 269 BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth) |
| 254 : location(birth.location()), | 270 : location(birth.location()), |
| 255 thread_name(birth.birth_thread()->thread_name()) { | 271 thread_name(birth.birth_thread()->sanitized_thread_name()) {} |
| 256 } | |
| 257 | 272 |
| 258 BirthOnThreadSnapshot::~BirthOnThreadSnapshot() { | 273 BirthOnThreadSnapshot::~BirthOnThreadSnapshot() { |
| 259 } | 274 } |
| 260 | 275 |
| 261 //------------------------------------------------------------------------------ | 276 //------------------------------------------------------------------------------ |
| 262 Births::Births(const Location& location, const ThreadData& current) | 277 Births::Births(const Location& location, const ThreadData& current) |
| 263 : BirthOnThread(location, current), | 278 : BirthOnThread(location, current), |
| 264 birth_count_(1) { } | 279 birth_count_(1) { } |
| 265 | 280 |
| 266 int Births::birth_count() const { return birth_count_; } | 281 int Births::birth_count() const { return birth_count_; } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 278 // static | 293 // static |
| 279 ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL; | 294 ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL; |
| 280 | 295 |
| 281 // A TLS slot which points to the ThreadData instance for the current thread. | 296 // A TLS slot which points to the ThreadData instance for the current thread. |
| 282 // We do a fake initialization here (zeroing out data), and then the real | 297 // We do a fake initialization here (zeroing out data), and then the real |
| 283 // in-place construction happens when we call tls_index_.Initialize(). | 298 // in-place construction happens when we call tls_index_.Initialize(). |
| 284 // static | 299 // static |
| 285 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; | 300 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; |
| 286 | 301 |
| 287 // static | 302 // static |
| 288 int ThreadData::worker_thread_data_creation_count_ = 0; | |
| 289 | |
| 290 // static | |
| 291 int ThreadData::cleanup_count_ = 0; | 303 int ThreadData::cleanup_count_ = 0; |
| 292 | 304 |
| 293 // static | 305 // static |
| 294 int ThreadData::incarnation_counter_ = 0; | 306 int ThreadData::incarnation_counter_ = 0; |
| 295 | 307 |
| 296 // static | 308 // static |
| 297 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; | 309 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; |
| 298 | 310 |
| 299 // static | 311 // static |
| 300 ThreadData* ThreadData::first_retired_worker_ = NULL; | 312 ThreadData* ThreadData::first_retired_thread_data_ = NULL; |
| 301 | 313 |
| 302 // static | 314 // static |
| 303 base::LazyInstance<base::Lock>::Leaky | 315 base::LazyInstance<base::Lock>::Leaky |
| 304 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; | 316 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; |
| 305 | 317 |
| 306 // static | 318 // static |
| 307 base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED; | 319 base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED; |
| 308 | 320 |
| 309 ThreadData::ThreadData(const std::string& suggested_name) | 321 ThreadData::ThreadData(const std::string& sanitized_thread_name) |
| 310 : next_(NULL), | 322 : next_(NULL), |
| 311 next_retired_worker_(NULL), | 323 next_retired_(NULL), |
| 312 worker_thread_number_(0), | 324 sanitized_thread_name_(sanitized_thread_name), |
| 313 incarnation_count_for_pool_(-1), | 325 incarnation_count_for_pool_(-1), |
| 314 current_stopwatch_(NULL) { | 326 current_stopwatch_(NULL) { |
| 315 DCHECK_GE(suggested_name.size(), 0u); | |
| 316 thread_name_ = suggested_name; | |
| 317 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 327 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
| 318 } | 328 } |
| 319 | 329 |
| 320 ThreadData::ThreadData(int thread_number) | |
| 321 : next_(NULL), | |
| 322 next_retired_worker_(NULL), | |
| 323 worker_thread_number_(thread_number), | |
| 324 incarnation_count_for_pool_(-1), | |
| 325 current_stopwatch_(NULL) { | |
| 326 CHECK_GT(thread_number, 0); | |
| 327 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); | |
| 328 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | |
| 329 } | |
| 330 | |
| 331 ThreadData::~ThreadData() { | 330 ThreadData::~ThreadData() { |
| 332 } | 331 } |
| 333 | 332 |
| 334 void ThreadData::PushToHeadOfList() { | 333 void ThreadData::PushToHeadOfList() { |
| 335 // Toss in a hint of randomness (atop the uniniitalized value). | 334 // Toss in a hint of randomness (atop the uniniitalized value). |
| 336 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, | 335 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, |
| 337 sizeof(random_number_)); | 336 sizeof(random_number_)); |
| 338 MSAN_UNPOISON(&random_number_, sizeof(random_number_)); | 337 MSAN_UNPOISON(&random_number_, sizeof(random_number_)); |
| 339 random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0)); | 338 random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0)); |
| 340 random_number_ ^= (Now() - TrackedTime()).InMilliseconds(); | 339 random_number_ ^= (Now() - TrackedTime()).InMilliseconds(); |
| 341 | 340 |
| 342 DCHECK(!next_); | 341 DCHECK(!next_); |
| 343 base::AutoLock lock(*list_lock_.Pointer()); | 342 base::AutoLock lock(*list_lock_.Pointer()); |
| 344 incarnation_count_for_pool_ = incarnation_counter_; | 343 incarnation_count_for_pool_ = incarnation_counter_; |
| 345 next_ = all_thread_data_list_head_; | 344 next_ = all_thread_data_list_head_; |
| 346 all_thread_data_list_head_ = this; | 345 all_thread_data_list_head_ = this; |
| 347 } | 346 } |
| 348 | 347 |
| 349 // static | 348 // static |
| 350 ThreadData* ThreadData::first() { | 349 ThreadData* ThreadData::first() { |
| 351 base::AutoLock lock(*list_lock_.Pointer()); | 350 base::AutoLock lock(*list_lock_.Pointer()); |
| 352 return all_thread_data_list_head_; | 351 return all_thread_data_list_head_; |
| 353 } | 352 } |
| 354 | 353 |
| 355 ThreadData* ThreadData::next() const { return next_; } | 354 ThreadData* ThreadData::next() const { return next_; } |
| 356 | 355 |
| 357 // static | 356 // static |
| 358 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { | 357 void ThreadData::InitializeThreadContext(const std::string& thread_name) { |
| 359 if (base::WorkerPool::RunsTasksOnCurrentThread()) | 358 if (base::WorkerPool::RunsTasksOnCurrentThread()) |
| 360 return; | 359 return; |
| 361 EnsureTlsInitialization(); | 360 EnsureTlsInitialization(); |
| 362 ThreadData* current_thread_data = | 361 ThreadData* current_thread_data = |
| 363 reinterpret_cast<ThreadData*>(tls_index_.Get()); | 362 reinterpret_cast<ThreadData*>(tls_index_.Get()); |
| 364 if (current_thread_data) | 363 if (current_thread_data) |
| 365 return; // Browser tests instigate this. | 364 return; // Browser tests instigate this. |
| 366 current_thread_data = new ThreadData(suggested_name); | 365 current_thread_data = |
| 366 GetRetiredOrCreateThreadData(SanitizeThreadName(thread_name)); | |
| 367 tls_index_.Set(current_thread_data); | 367 tls_index_.Set(current_thread_data); |
| 368 } | 368 } |
| 369 | 369 |
| 370 // static | 370 // static |
| 371 ThreadData* ThreadData::Get() { | 371 ThreadData* ThreadData::Get() { |
| 372 if (!tls_index_.initialized()) | 372 if (!tls_index_.initialized()) |
| 373 return NULL; // For unittests only. | 373 return NULL; // For unittests only. |
| 374 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); | 374 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); |
| 375 if (registered) | 375 if (registered) |
| 376 return registered; | 376 return registered; |
| 377 | 377 |
| 378 // We must be a worker thread, since we didn't pre-register. | 378 // We must be a worker thread, since we didn't pre-register. |
| 379 ThreadData* worker_thread_data = NULL; | 379 ThreadData* worker_thread_data = |
| 380 int worker_thread_number = 0; | 380 GetRetiredOrCreateThreadData("WorkerThread-*"); |
| 381 { | |
| 382 base::AutoLock lock(*list_lock_.Pointer()); | |
| 383 if (first_retired_worker_) { | |
| 384 worker_thread_data = first_retired_worker_; | |
| 385 first_retired_worker_ = first_retired_worker_->next_retired_worker_; | |
| 386 worker_thread_data->next_retired_worker_ = NULL; | |
| 387 } else { | |
| 388 worker_thread_number = ++worker_thread_data_creation_count_; | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 // If we can't find a previously used instance, then we have to create one. | |
| 393 if (!worker_thread_data) { | |
| 394 DCHECK_GT(worker_thread_number, 0); | |
| 395 worker_thread_data = new ThreadData(worker_thread_number); | |
| 396 } | |
| 397 DCHECK_GT(worker_thread_data->worker_thread_number_, 0); | |
| 398 | |
| 399 tls_index_.Set(worker_thread_data); | 381 tls_index_.Set(worker_thread_data); |
| 400 return worker_thread_data; | 382 return worker_thread_data; |
| 401 } | 383 } |
| 402 | 384 |
| 403 // static | 385 // static |
| 404 void ThreadData::OnThreadTermination(void* thread_data) { | 386 void ThreadData::OnThreadTermination(void* thread_data) { |
| 405 DCHECK(thread_data); // TLS should *never* call us with a NULL. | 387 DCHECK(thread_data); // TLS should *never* call us with a NULL. |
| 406 // We must NOT do any allocations during this callback. There is a chance | 388 // We must NOT do any allocations during this callback. There is a chance |
| 407 // that the allocator is no longer active on this thread. | 389 // that the allocator is no longer active on this thread. |
| 408 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); | 390 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); |
| 409 } | 391 } |
| 410 | 392 |
| 411 void ThreadData::OnThreadTerminationCleanup() { | 393 void ThreadData::OnThreadTerminationCleanup() { |
| 394 // We must NOT do any allocations during this callback. There is a chance that | |
| 395 // the allocator is no longer active on this thread. | |
| 396 | |
| 412 // The list_lock_ was created when we registered the callback, so it won't be | 397 // The list_lock_ was created when we registered the callback, so it won't be |
| 413 // allocated here despite the lazy reference. | 398 // allocated here despite the lazy reference. |
| 414 base::AutoLock lock(*list_lock_.Pointer()); | 399 base::AutoLock lock(*list_lock_.Pointer()); |
| 415 if (incarnation_counter_ != incarnation_count_for_pool_) | 400 if (incarnation_counter_ != incarnation_count_for_pool_) |
| 416 return; // ThreadData was constructed in an earlier unit test. | 401 return; // ThreadData was constructed in an earlier unit test. |
| 417 ++cleanup_count_; | 402 ++cleanup_count_; |
| 418 // Only worker threads need to be retired and reused. | 403 |
| 419 if (!worker_thread_number_) { | 404 // Add this ThreadData to a retired list so that it can be reused by a thread |
| 420 return; | 405 // with the same name sanitized name in the future. |
| 421 } | 406 DCHECK(!next_retired_); |
| 422 // We must NOT do any allocations during this callback. | 407 next_retired_ = first_retired_thread_data_; |
| 423 // Using the simple linked lists avoids all allocations. | 408 first_retired_thread_data_ = this; |
| 424 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); | |
| 425 this->next_retired_worker_ = first_retired_worker_; | |
| 426 first_retired_worker_ = this; | |
| 427 } | 409 } |
| 428 | 410 |
| 429 // static | 411 // static |
| 430 void ThreadData::Snapshot(int current_profiling_phase, | 412 void ThreadData::Snapshot(int current_profiling_phase, |
| 431 ProcessDataSnapshot* process_data_snapshot) { | 413 ProcessDataSnapshot* process_data_snapshot) { |
| 432 // Get an unchanging copy of a ThreadData list. | 414 // Get an unchanging copy of a ThreadData list. |
| 433 ThreadData* my_list = ThreadData::first(); | 415 ThreadData* my_list = ThreadData::first(); |
| 434 | 416 |
| 435 // Gather data serially. | 417 // Gather data serially. |
| 436 // This hackish approach *can* get some slightly corrupt tallies, as we are | 418 // This hackish approach *can* get some slightly corrupt tallies, as we are |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 // phase, if any. Store the deltas in the result. | 610 // phase, if any. Store the deltas in the result. |
| 629 for (const DeathDataPhaseSnapshot* phase = &death.second; phase; | 611 for (const DeathDataPhaseSnapshot* phase = &death.second; phase; |
| 630 phase = phase->prev) { | 612 phase = phase->prev) { |
| 631 const DeathDataSnapshot& death_data = | 613 const DeathDataSnapshot& death_data = |
| 632 phase->prev ? phase->death_data.Delta(phase->prev->death_data) | 614 phase->prev ? phase->death_data.Delta(phase->prev->death_data) |
| 633 : phase->death_data; | 615 : phase->death_data; |
| 634 | 616 |
| 635 if (death_data.count > 0) { | 617 if (death_data.count > 0) { |
| 636 (*phased_snapshots)[phase->profiling_phase].tasks.push_back( | 618 (*phased_snapshots)[phase->profiling_phase].tasks.push_back( |
| 637 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data, | 619 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data, |
| 638 thread_name())); | 620 sanitized_thread_name())); |
| 639 } | 621 } |
| 640 } | 622 } |
| 641 } | 623 } |
| 642 } | 624 } |
| 643 | 625 |
| 644 // This may be called from another thread. | 626 // This may be called from another thread. |
| 645 void ThreadData::SnapshotMaps(int profiling_phase, | 627 void ThreadData::SnapshotMaps(int profiling_phase, |
| 646 BirthMap* birth_map, | 628 BirthMap* birth_map, |
| 647 DeathsSnapshot* deaths) { | 629 DeathsSnapshot* deaths) { |
| 648 base::AutoLock lock(map_lock_); | 630 base::AutoLock lock(map_lock_); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 739 if (now_function_for_testing_) | 721 if (now_function_for_testing_) |
| 740 return TrackedTime::FromMilliseconds((*now_function_for_testing_)()); | 722 return TrackedTime::FromMilliseconds((*now_function_for_testing_)()); |
| 741 if (IsProfilerTimingEnabled() && TrackingStatus()) | 723 if (IsProfilerTimingEnabled() && TrackingStatus()) |
| 742 return TrackedTime::Now(); | 724 return TrackedTime::Now(); |
| 743 return TrackedTime(); // Super fast when disabled, or not compiled. | 725 return TrackedTime(); // Super fast when disabled, or not compiled. |
| 744 } | 726 } |
| 745 | 727 |
| 746 // static | 728 // static |
| 747 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { | 729 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { |
| 748 base::AutoLock lock(*list_lock_.Pointer()); | 730 base::AutoLock lock(*list_lock_.Pointer()); |
| 749 if (worker_thread_data_creation_count_ == 0) | |
| 750 return; // We haven't really run much, and couldn't have leaked. | |
| 751 | 731 |
| 752 // TODO(jar): until this is working on XP, don't run the real test. | 732 // TODO(jar): until this is working on XP, don't run the real test. |
| 753 #if 0 | 733 #if 0 |
| 754 // Verify that we've at least shutdown/cleanup the major namesd threads. The | 734 // Verify that we've at least shutdown/cleanup the major namesd threads. The |
| 755 // caller should tell us how many thread shutdowns should have taken place by | 735 // caller should tell us how many thread shutdowns should have taken place by |
| 756 // now. | 736 // now. |
| 757 CHECK_GT(cleanup_count_, major_threads_shutdown_count); | 737 CHECK_GT(cleanup_count_, major_threads_shutdown_count); |
| 758 #endif | 738 #endif |
| 759 } | 739 } |
| 760 | 740 |
| 761 // static | 741 // static |
| 762 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) { | 742 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) { |
| 763 // This is only called from test code, where we need to cleanup so that | 743 // This is only called from test code, where we need to cleanup so that |
| 764 // additional tests can be run. | 744 // additional tests can be run. |
| 765 // We must be single threaded... but be careful anyway. | 745 // We must be single threaded... but be careful anyway. |
| 766 InitializeAndSetTrackingStatus(DEACTIVATED); | 746 InitializeAndSetTrackingStatus(DEACTIVATED); |
| 767 | 747 |
| 768 ThreadData* thread_data_list; | 748 ThreadData* thread_data_list; |
| 769 { | 749 { |
| 770 base::AutoLock lock(*list_lock_.Pointer()); | 750 base::AutoLock lock(*list_lock_.Pointer()); |
| 771 thread_data_list = all_thread_data_list_head_; | 751 thread_data_list = all_thread_data_list_head_; |
| 772 all_thread_data_list_head_ = NULL; | 752 all_thread_data_list_head_ = NULL; |
| 773 ++incarnation_counter_; | 753 ++incarnation_counter_; |
| 774 // To be clean, break apart the retired worker list (though we leak them). | 754 // To be clean, break apart the retired worker list (though we leak them). |
| 775 while (first_retired_worker_) { | 755 while (first_retired_thread_data_) { |
| 776 ThreadData* worker = first_retired_worker_; | 756 ThreadData* thread_data = first_retired_thread_data_; |
| 777 CHECK_GT(worker->worker_thread_number_, 0); | 757 first_retired_thread_data_ = thread_data->next_retired_; |
| 778 first_retired_worker_ = worker->next_retired_worker_; | 758 thread_data->next_retired_ = nullptr; |
| 779 worker->next_retired_worker_ = NULL; | |
| 780 } | 759 } |
| 781 } | 760 } |
| 782 | 761 |
| 783 // Put most global static back in pristine shape. | 762 // Put most global static back in pristine shape. |
| 784 worker_thread_data_creation_count_ = 0; | |
| 785 cleanup_count_ = 0; | 763 cleanup_count_ = 0; |
| 786 tls_index_.Set(NULL); | 764 tls_index_.Set(NULL); |
| 787 // Almost UNINITIALIZED. | 765 // Almost UNINITIALIZED. |
| 788 base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS); | 766 base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS); |
| 789 | 767 |
| 790 // To avoid any chance of racing in unit tests, which is the only place we | 768 // To avoid any chance of racing in unit tests, which is the only place we |
| 791 // call this function, we may sometimes leak all the data structures we | 769 // call this function, we may sometimes leak all the data structures we |
| 792 // recovered, as they may still be in use on threads from prior tests! | 770 // recovered, as they may still be in use on threads from prior tests! |
| 793 if (leak) { | 771 if (leak) { |
| 794 ThreadData* thread_data = thread_data_list; | 772 ThreadData* thread_data = thread_data_list; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 806 ThreadData* next_thread_data = thread_data_list; | 784 ThreadData* next_thread_data = thread_data_list; |
| 807 thread_data_list = thread_data_list->next(); | 785 thread_data_list = thread_data_list->next(); |
| 808 | 786 |
| 809 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 787 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
| 810 next_thread_data->birth_map_.end() != it; ++it) | 788 next_thread_data->birth_map_.end() != it; ++it) |
| 811 delete it->second; // Delete the Birth Records. | 789 delete it->second; // Delete the Birth Records. |
| 812 delete next_thread_data; // Includes all Death Records. | 790 delete next_thread_data; // Includes all Death Records. |
| 813 } | 791 } |
| 814 } | 792 } |
| 815 | 793 |
| 794 // static | |
| 795 ThreadData* ThreadData::GetRetiredOrCreateThreadData( | |
| 796 const std::string& sanitized_thread_name) { | |
| 797 { | |
| 798 base::AutoLock lock(*list_lock_.Pointer()); | |
| 799 ThreadData** previous_thread_data_next_retired_pointer = | |
| 800 &first_retired_thread_data_; | |
| 801 ThreadData* current_thread_data = first_retired_thread_data_; | |
| 802 | |
| 803 // Assuming that there aren't more than a few tens of retired ThreadData | |
|
Ilya Sherman
2016/11/12 01:21:16
Is it worth DCHECKing the list size?
fdoray
2016/11/14 14:32:07
Done. DCHECKed that it stays under 30.
| |
| 804 // instances, this lookup should be quick compared to the thread creation | |
| 805 // time. Retired ThreadData instances cannot be stored in a map because | |
| 806 // insertions are done from OnThreadTerminationCleanup() where allocations | |
| 807 // are not allowed. | |
| 808 while (current_thread_data) { | |
| 809 if (current_thread_data->sanitized_thread_name() == | |
| 810 sanitized_thread_name) { | |
| 811 DCHECK_EQ(*previous_thread_data_next_retired_pointer, | |
| 812 current_thread_data); | |
| 813 *previous_thread_data_next_retired_pointer = | |
| 814 current_thread_data->next_retired_; | |
| 815 current_thread_data->next_retired_ = nullptr; | |
| 816 return current_thread_data; | |
| 817 } | |
| 818 previous_thread_data_next_retired_pointer = | |
| 819 ¤t_thread_data->next_retired_; | |
| 820 current_thread_data = current_thread_data->next_retired_; | |
| 821 } | |
| 822 } | |
| 823 return new ThreadData(sanitized_thread_name); | |
| 824 } | |
| 825 | |
| 816 //------------------------------------------------------------------------------ | 826 //------------------------------------------------------------------------------ |
| 817 TaskStopwatch::TaskStopwatch() | 827 TaskStopwatch::TaskStopwatch() |
| 818 : wallclock_duration_ms_(0), | 828 : wallclock_duration_ms_(0), |
| 819 current_thread_data_(NULL), | 829 current_thread_data_(NULL), |
| 820 excluded_duration_ms_(0), | 830 excluded_duration_ms_(0), |
| 821 parent_(NULL) { | 831 parent_(NULL) { |
| 822 #if DCHECK_IS_ON() | 832 #if DCHECK_IS_ON() |
| 823 state_ = CREATED; | 833 state_ = CREATED; |
| 824 child_ = NULL; | 834 child_ = NULL; |
| 825 #endif | 835 #endif |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 971 #endif | 981 #endif |
| 972 } | 982 } |
| 973 | 983 |
| 974 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) = | 984 ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) = |
| 975 default; | 985 default; |
| 976 | 986 |
| 977 ProcessDataSnapshot::~ProcessDataSnapshot() { | 987 ProcessDataSnapshot::~ProcessDataSnapshot() { |
| 978 } | 988 } |
| 979 | 989 |
| 980 } // namespace tracked_objects | 990 } // namespace tracked_objects |
| OLD | NEW |