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 |