| 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 <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/profiler/alternate_timer.h" |
| 11 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
| 12 #include "base/third_party/valgrind/memcheck.h" | 13 #include "base/third_party/valgrind/memcheck.h" |
| 13 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 14 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 15 #include "base/port.h" | 16 #include "base/port.h" |
| 16 | 17 |
| 17 using base::TimeDelta; | 18 using base::TimeDelta; |
| 18 | 19 |
| 19 namespace tracked_objects { | 20 namespace tracked_objects { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Flag to compile out almost all of the task tracking code. | 24 // Flag to compile out almost all of the task tracking code. |
| 24 const bool kTrackAllTaskObjects = true; | 25 const bool kTrackAllTaskObjects = true; |
| 25 | 26 |
| 26 // Flag to compile out parent-child link recording. | 27 // Flag to compile out parent-child link recording. |
| 27 const bool kTrackParentChildLinks = false; | 28 const bool kTrackParentChildLinks = false; |
| 28 | 29 |
| 29 // When ThreadData is first initialized, should we start in an ACTIVE state to | 30 // When ThreadData is first initialized, should we start in an ACTIVE state to |
| 30 // record all of the startup-time tasks, or should we start up DEACTIVATED, so | 31 // record all of the startup-time tasks, or should we start up DEACTIVATED, so |
| 31 // that we only record after parsing the command line flag --enable-tracking. | 32 // that we only record after parsing the command line flag --enable-tracking. |
| 32 // Note that the flag may force either state, so this really controls only the | 33 // Note that the flag may force either state, so this really controls only the |
| 33 // period of time up until that flag is parsed. If there is no flag seen, then | 34 // period of time up until that flag is parsed. If there is no flag seen, then |
| 34 // this state may prevail for much or all of the process lifetime. | 35 // this state may prevail for much or all of the process lifetime. |
| 35 const ThreadData::Status kInitialStartupState = | 36 const ThreadData::Status kInitialStartupState = |
| 36 ThreadData::PROFILING_CHILDREN_ACTIVE; | 37 ThreadData::PROFILING_CHILDREN_ACTIVE; |
| 37 | 38 |
| 39 // Control whether an alternate time source (Now() function) is supported by |
| 40 // the ThreadData class. This compile time flag should be set to true if we |
| 41 // want other modules (such as a memory allocator, or a thread-specific CPU time |
| 42 // clock) to be able to provide a thread-specific Now() function. Without this |
| 43 // compile-time flag, the code will only support the wall-clock time. This flag |
| 44 // can be flipped to efficiently disable this path (if there is a performance |
| 45 // problem with its presence). |
| 46 static const bool kAllowAlternateTimeSourceHandling = true; |
| 38 } // namespace | 47 } // namespace |
| 39 | 48 |
| 40 //------------------------------------------------------------------------------ | 49 //------------------------------------------------------------------------------ |
| 41 // DeathData tallies durations when a death takes place. | 50 // DeathData tallies durations when a death takes place. |
| 42 | 51 |
| 43 DeathData::DeathData() { | 52 DeathData::DeathData() { |
| 44 Clear(); | 53 Clear(); |
| 45 } | 54 } |
| 46 | 55 |
| 47 DeathData::DeathData(int count) { | 56 DeathData::DeathData(int count) { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 void Births::Clear() { birth_count_ = 0; } | 178 void Births::Clear() { birth_count_ = 0; } |
| 170 | 179 |
| 171 //------------------------------------------------------------------------------ | 180 //------------------------------------------------------------------------------ |
| 172 // ThreadData maintains the central data for all births and deaths on a single | 181 // ThreadData maintains the central data for all births and deaths on a single |
| 173 // thread. | 182 // thread. |
| 174 | 183 |
| 175 // TODO(jar): We should pull all these static vars together, into a struct, and | 184 // TODO(jar): We should pull all these static vars together, into a struct, and |
| 176 // optimize layout so that we benefit from locality of reference during accesses | 185 // optimize layout so that we benefit from locality of reference during accesses |
| 177 // to them. | 186 // to them. |
| 178 | 187 |
| 188 // static |
| 189 NowFunction* ThreadData::now_function_ = NULL; |
| 190 |
| 179 // A TLS slot which points to the ThreadData instance for the current thread. We | 191 // A TLS slot which points to the ThreadData instance for the current thread. We |
| 180 // do a fake initialization here (zeroing out data), and then the real in-place | 192 // do a fake initialization here (zeroing out data), and then the real in-place |
| 181 // construction happens when we call tls_index_.Initialize(). | 193 // construction happens when we call tls_index_.Initialize(). |
| 182 // static | 194 // static |
| 183 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; | 195 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; |
| 184 | 196 |
| 185 // static | 197 // static |
| 186 int ThreadData::worker_thread_data_creation_count_ = 0; | 198 int ThreadData::worker_thread_data_creation_count_ = 0; |
| 187 | 199 |
| 188 // static | 200 // static |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 375 |
| 364 void ThreadData::TallyADeath(const Births& birth, | 376 void ThreadData::TallyADeath(const Births& birth, |
| 365 DurationInt queue_duration, | 377 DurationInt queue_duration, |
| 366 DurationInt run_duration) { | 378 DurationInt run_duration) { |
| 367 // Stir in some randomness, plus add constant in case durations are zero. | 379 // Stir in some randomness, plus add constant in case durations are zero. |
| 368 const DurationInt kSomePrimeNumber = 2147483647; | 380 const DurationInt kSomePrimeNumber = 2147483647; |
| 369 random_number_ += queue_duration + run_duration + kSomePrimeNumber; | 381 random_number_ += queue_duration + run_duration + kSomePrimeNumber; |
| 370 // An address is going to have some randomness to it as well ;-). | 382 // An address is going to have some randomness to it as well ;-). |
| 371 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); | 383 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); |
| 372 | 384 |
| 385 // We don't have queue durations without OS timer. OS timer is automatically |
| 386 // used for task-post-timing, so the use of an alternate timer implies all |
| 387 // queue times are invalid. |
| 388 if (kAllowAlternateTimeSourceHandling && now_function_) |
| 389 queue_duration = 0; |
| 390 |
| 373 DeathMap::iterator it = death_map_.find(&birth); | 391 DeathMap::iterator it = death_map_.find(&birth); |
| 374 DeathData* death_data; | 392 DeathData* death_data; |
| 375 if (it != death_map_.end()) { | 393 if (it != death_map_.end()) { |
| 376 death_data = &it->second; | 394 death_data = &it->second; |
| 377 } else { | 395 } else { |
| 378 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 396 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
| 379 death_data = &death_map_[&birth]; | 397 death_data = &death_map_[&birth]; |
| 380 } // Release lock ASAP. | 398 } // Release lock ASAP. |
| 381 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 399 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
| 382 | 400 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 void ThreadData::Reset() { | 590 void ThreadData::Reset() { |
| 573 base::AutoLock lock(map_lock_); | 591 base::AutoLock lock(map_lock_); |
| 574 for (DeathMap::iterator it = death_map_.begin(); | 592 for (DeathMap::iterator it = death_map_.begin(); |
| 575 it != death_map_.end(); ++it) | 593 it != death_map_.end(); ++it) |
| 576 it->second.Clear(); | 594 it->second.Clear(); |
| 577 for (BirthMap::iterator it = birth_map_.begin(); | 595 for (BirthMap::iterator it = birth_map_.begin(); |
| 578 it != birth_map_.end(); ++it) | 596 it != birth_map_.end(); ++it) |
| 579 it->second->Clear(); | 597 it->second->Clear(); |
| 580 } | 598 } |
| 581 | 599 |
| 600 static void OptionallyInitializeAlternateTimer() { |
| 601 char* alternate_selector = getenv(kAlternateProfilerTime); |
| 602 if (!alternate_selector) |
| 603 return; |
| 604 switch (*alternate_selector) { |
| 605 case '0': // This is the default value, and uses the wall clock time. |
| 606 break; |
| 607 case '1': { |
| 608 // Use the TCMalloc allocations-on-thread as a pseudo-time. |
| 609 ThreadData::SetAlternateTimeSource(GetAlternateTimeSource()); |
| 610 break; |
| 611 } |
| 612 default: |
| 613 NOTREACHED(); |
| 614 break; |
| 615 } |
| 616 } |
| 617 |
| 582 bool ThreadData::Initialize() { | 618 bool ThreadData::Initialize() { |
| 583 if (!kTrackAllTaskObjects) | 619 if (!kTrackAllTaskObjects) |
| 584 return false; // Not compiled in. | 620 return false; // Not compiled in. |
| 585 if (status_ >= DEACTIVATED) | 621 if (status_ >= DEACTIVATED) |
| 586 return true; // Someone else did the initialization. | 622 return true; // Someone else did the initialization. |
| 587 // Due to racy lazy initialization in tests, we'll need to recheck status_ | 623 // Due to racy lazy initialization in tests, we'll need to recheck status_ |
| 588 // after we acquire the lock. | 624 // after we acquire the lock. |
| 589 | 625 |
| 590 // Ensure that we don't double initialize tls. We are called when single | 626 // Ensure that we don't double initialize tls. We are called when single |
| 591 // threaded in the product, but some tests may be racy and lazy about our | 627 // threaded in the product, but some tests may be racy and lazy about our |
| 592 // initialization. | 628 // initialization. |
| 593 base::AutoLock lock(*list_lock_.Pointer()); | 629 base::AutoLock lock(*list_lock_.Pointer()); |
| 594 if (status_ >= DEACTIVATED) | 630 if (status_ >= DEACTIVATED) |
| 595 return true; // Someone raced in here and beat us. | 631 return true; // Someone raced in here and beat us. |
| 596 | 632 |
| 633 // Put an alternate timer in place if the environment calls for it, such as |
| 634 // for tracking TCMalloc allocations. This insertion is idempotent, so we |
| 635 // don't mind if there is a race, and we'd prefer not to be in a lock while |
| 636 // doing this work. |
| 637 if (kAllowAlternateTimeSourceHandling) |
| 638 OptionallyInitializeAlternateTimer(); |
| 639 |
| 597 // Perform the "real" TLS initialization now, and leave it intact through | 640 // Perform the "real" TLS initialization now, and leave it intact through |
| 598 // process termination. | 641 // process termination. |
| 599 if (!tls_index_.initialized()) { // Testing may have initialized this. | 642 if (!tls_index_.initialized()) { // Testing may have initialized this. |
| 600 DCHECK_EQ(status_, UNINITIALIZED); | 643 DCHECK_EQ(status_, UNINITIALIZED); |
| 601 tls_index_.Initialize(&ThreadData::OnThreadTermination); | 644 tls_index_.Initialize(&ThreadData::OnThreadTermination); |
| 602 if (!tls_index_.initialized()) | 645 if (!tls_index_.initialized()) |
| 603 return false; | 646 return false; |
| 604 } else { | 647 } else { |
| 605 // TLS was initialzed for us earlier. | 648 // TLS was initialzed for us earlier. |
| 606 DCHECK_EQ(status_, DORMANT_DURING_TESTS); | 649 DCHECK_EQ(status_, DORMANT_DURING_TESTS); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 } | 702 } |
| 660 return Now(); | 703 return Now(); |
| 661 } | 704 } |
| 662 | 705 |
| 663 // static | 706 // static |
| 664 TrackedTime ThreadData::NowForEndOfRun() { | 707 TrackedTime ThreadData::NowForEndOfRun() { |
| 665 return Now(); | 708 return Now(); |
| 666 } | 709 } |
| 667 | 710 |
| 668 // static | 711 // static |
| 712 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { |
| 713 DCHECK(now_function); |
| 714 if (kAllowAlternateTimeSourceHandling) |
| 715 now_function_ = now_function; |
| 716 } |
| 717 |
| 718 // static |
| 669 TrackedTime ThreadData::Now() { | 719 TrackedTime ThreadData::Now() { |
| 720 if (kAllowAlternateTimeSourceHandling && now_function_) |
| 721 return TrackedTime::FromMilliseconds((*now_function_)()); |
| 670 if (kTrackAllTaskObjects && TrackingStatus()) | 722 if (kTrackAllTaskObjects && TrackingStatus()) |
| 671 return TrackedTime::Now(); | 723 return TrackedTime::Now(); |
| 672 return TrackedTime(); // Super fast when disabled, or not compiled. | 724 return TrackedTime(); // Super fast when disabled, or not compiled. |
| 673 } | 725 } |
| 674 | 726 |
| 675 // static | 727 // static |
| 676 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { | 728 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { |
| 677 base::AutoLock lock(*list_lock_.Pointer()); | 729 base::AutoLock lock(*list_lock_.Pointer()); |
| 678 if (worker_thread_data_creation_count_ == 0) | 730 if (worker_thread_data_creation_count_ == 0) |
| 679 return; // We haven't really run much, and couldn't have leaked. | 731 return; // We haven't really run much, and couldn't have leaked. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 ++it) { | 882 ++it) { |
| 831 base::DictionaryValue* parent_child = new base::DictionaryValue; | 883 base::DictionaryValue* parent_child = new base::DictionaryValue; |
| 832 it->first->ToValue("parent", parent_child); | 884 it->first->ToValue("parent", parent_child); |
| 833 it->second->ToValue("child", parent_child); | 885 it->second->ToValue("child", parent_child); |
| 834 descendants->Append(parent_child); | 886 descendants->Append(parent_child); |
| 835 } | 887 } |
| 836 dictionary->Set("descendants", descendants); | 888 dictionary->Set("descendants", descendants); |
| 837 } | 889 } |
| 838 | 890 |
| 839 } // namespace tracked_objects | 891 } // namespace tracked_objects |
| OLD | NEW |