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 try if we want | |
ramant (doing other things)
2012/02/15 18:33:46
nit: try -> true
jar (doing other things)
2012/02/15 20:26:32
Done. I added a lot of text to try to be even cle
| |
41 // other modules, such as an allocator, to call with a new thread-specific | |
42 // Now() function to use (instead of of calling into tracked_time). | |
43 static const bool kAllowAlternateTimeSourceHandling = true; | |
44 | |
45 // Environment variable name that is used to activate alternate timer profiling | |
46 // (such as using TCMalloc allocations to provide a pseudo-timer) for tasks | |
47 // instead of wall clock profiling. | |
48 static const char k_alternate_profile_timer[] = "CHROME_PROFILER_TIME"; | |
ramant (doing other things)
2012/02/15 18:33:46
nit: should we consider commenting that "k_alterna
jar (doing other things)
2012/02/15 20:26:32
I went back and tried to move it to shared place.
| |
49 | |
38 } // namespace | 50 } // namespace |
39 | 51 |
40 //------------------------------------------------------------------------------ | 52 //------------------------------------------------------------------------------ |
41 // DeathData tallies durations when a death takes place. | 53 // DeathData tallies durations when a death takes place. |
42 | 54 |
43 DeathData::DeathData() { | 55 DeathData::DeathData() { |
44 Clear(); | 56 Clear(); |
45 } | 57 } |
46 | 58 |
47 DeathData::DeathData(int count) { | 59 DeathData::DeathData(int count) { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 void Births::Clear() { birth_count_ = 0; } | 181 void Births::Clear() { birth_count_ = 0; } |
170 | 182 |
171 //------------------------------------------------------------------------------ | 183 //------------------------------------------------------------------------------ |
172 // ThreadData maintains the central data for all births and deaths on a single | 184 // ThreadData maintains the central data for all births and deaths on a single |
173 // thread. | 185 // thread. |
174 | 186 |
175 // TODO(jar): We should pull all these static vars together, into a struct, and | 187 // 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 | 188 // optimize layout so that we benefit from locality of reference during accesses |
177 // to them. | 189 // to them. |
178 | 190 |
191 // static | |
192 NowFunction* ThreadData::now_function_ = NULL; | |
193 | |
179 // A TLS slot which points to the ThreadData instance for the current thread. We | 194 // 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 | 195 // do a fake initialization here (zeroing out data), and then the real in-place |
181 // construction happens when we call tls_index_.Initialize(). | 196 // construction happens when we call tls_index_.Initialize(). |
182 // static | 197 // static |
183 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; | 198 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; |
184 | 199 |
185 // static | 200 // static |
186 int ThreadData::worker_thread_data_creation_count_ = 0; | 201 int ThreadData::worker_thread_data_creation_count_ = 0; |
187 | 202 |
188 // static | 203 // static |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
363 | 378 |
364 void ThreadData::TallyADeath(const Births& birth, | 379 void ThreadData::TallyADeath(const Births& birth, |
365 DurationInt queue_duration, | 380 DurationInt queue_duration, |
366 DurationInt run_duration) { | 381 DurationInt run_duration) { |
367 // Stir in some randomness, plus add constant in case durations are zero. | 382 // Stir in some randomness, plus add constant in case durations are zero. |
368 const DurationInt kSomePrimeNumber = 2147483647; | 383 const DurationInt kSomePrimeNumber = 2147483647; |
369 random_number_ += queue_duration + run_duration + kSomePrimeNumber; | 384 random_number_ += queue_duration + run_duration + kSomePrimeNumber; |
370 // An address is going to have some randomness to it as well ;-). | 385 // An address is going to have some randomness to it as well ;-). |
371 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); | 386 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); |
372 | 387 |
388 // We don't have queue durations without OS timer. OS timer is automatically | |
389 // used for task-post-timing, so the use of an alternate timer implies all | |
390 // queue times are invalid. | |
391 if (kAllowAlternateTimeSourceHandling && now_function_) | |
392 queue_duration = 0; | |
393 | |
373 DeathMap::iterator it = death_map_.find(&birth); | 394 DeathMap::iterator it = death_map_.find(&birth); |
374 DeathData* death_data; | 395 DeathData* death_data; |
375 if (it != death_map_.end()) { | 396 if (it != death_map_.end()) { |
376 death_data = &it->second; | 397 death_data = &it->second; |
377 } else { | 398 } else { |
378 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 399 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
379 death_data = &death_map_[&birth]; | 400 death_data = &death_map_[&birth]; |
380 } // Release lock ASAP. | 401 } // Release lock ASAP. |
381 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 402 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
382 | 403 |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 void ThreadData::Reset() { | 593 void ThreadData::Reset() { |
573 base::AutoLock lock(map_lock_); | 594 base::AutoLock lock(map_lock_); |
574 for (DeathMap::iterator it = death_map_.begin(); | 595 for (DeathMap::iterator it = death_map_.begin(); |
575 it != death_map_.end(); ++it) | 596 it != death_map_.end(); ++it) |
576 it->second.Clear(); | 597 it->second.Clear(); |
577 for (BirthMap::iterator it = birth_map_.begin(); | 598 for (BirthMap::iterator it = birth_map_.begin(); |
578 it != birth_map_.end(); ++it) | 599 it != birth_map_.end(); ++it) |
579 it->second->Clear(); | 600 it->second->Clear(); |
580 } | 601 } |
581 | 602 |
603 static void OptionallyInitializeAlternateTimer() { | |
604 char* alternate_selector = getenv(k_alternate_profile_timer); | |
605 if (!alternate_selector) | |
606 return; | |
607 switch (*alternate_selector) { | |
608 case '0': // This is the default value, and uses the wall clock time. | |
609 break; | |
610 case '1': { | |
611 // Use the TCMalloc allocations-on-thread as a pseudo-time. | |
612 NowFunction* now_function = GetAlternateTimeSource(); | |
613 if (!now_function) | |
614 break; | |
615 ThreadData::SetAlternateTimeSource(now_function); | |
ramant (doing other things)
2012/02/15 18:33:46
nit: should we consider moving the following check
jar (doing other things)
2012/02/15 20:26:32
Done.
| |
616 break; | |
617 } | |
618 | |
619 default: | |
620 NOTREACHED(); | |
621 break; | |
622 } | |
623 } | |
624 | |
582 bool ThreadData::Initialize() { | 625 bool ThreadData::Initialize() { |
583 if (!kTrackAllTaskObjects) | 626 if (!kTrackAllTaskObjects) |
584 return false; // Not compiled in. | 627 return false; // Not compiled in. |
585 if (status_ >= DEACTIVATED) | 628 if (status_ >= DEACTIVATED) |
586 return true; // Someone else did the initialization. | 629 return true; // Someone else did the initialization. |
587 // Due to racy lazy initialization in tests, we'll need to recheck status_ | 630 // Due to racy lazy initialization in tests, we'll need to recheck status_ |
588 // after we acquire the lock. | 631 // after we acquire the lock. |
589 | 632 |
590 // Ensure that we don't double initialize tls. We are called when single | 633 // 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 | 634 // threaded in the product, but some tests may be racy and lazy about our |
592 // initialization. | 635 // initialization. |
593 base::AutoLock lock(*list_lock_.Pointer()); | 636 base::AutoLock lock(*list_lock_.Pointer()); |
594 if (status_ >= DEACTIVATED) | 637 if (status_ >= DEACTIVATED) |
595 return true; // Someone raced in here and beat us. | 638 return true; // Someone raced in here and beat us. |
596 | 639 |
640 // Put an alternate timer in place if the environment calls for it, such as | |
641 // for tracking TCMalloc allocations. This insertion is idempotent, so we | |
642 // don't mind if there is a race, and we'd prefer not to be in a lock while | |
643 // doing this work. | |
ramant (doing other things)
2012/02/15 18:33:46
Wondered if "_heap_init" happens before ThreadData
jar (doing other things)
2012/02/15 20:26:32
heap_init is run super-duper-early, before *any* a
| |
644 if (kAllowAlternateTimeSourceHandling) | |
645 OptionallyInitializeAlternateTimer(); | |
646 | |
597 // Perform the "real" TLS initialization now, and leave it intact through | 647 // Perform the "real" TLS initialization now, and leave it intact through |
598 // process termination. | 648 // process termination. |
599 if (!tls_index_.initialized()) { // Testing may have initialized this. | 649 if (!tls_index_.initialized()) { // Testing may have initialized this. |
600 DCHECK_EQ(status_, UNINITIALIZED); | 650 DCHECK_EQ(status_, UNINITIALIZED); |
601 tls_index_.Initialize(&ThreadData::OnThreadTermination); | 651 tls_index_.Initialize(&ThreadData::OnThreadTermination); |
602 if (!tls_index_.initialized()) | 652 if (!tls_index_.initialized()) |
603 return false; | 653 return false; |
604 } else { | 654 } else { |
605 // TLS was initialzed for us earlier. | 655 // TLS was initialzed for us earlier. |
606 DCHECK_EQ(status_, DORMANT_DURING_TESTS); | 656 DCHECK_EQ(status_, DORMANT_DURING_TESTS); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
659 } | 709 } |
660 return Now(); | 710 return Now(); |
661 } | 711 } |
662 | 712 |
663 // static | 713 // static |
664 TrackedTime ThreadData::NowForEndOfRun() { | 714 TrackedTime ThreadData::NowForEndOfRun() { |
665 return Now(); | 715 return Now(); |
666 } | 716 } |
667 | 717 |
668 // static | 718 // static |
719 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { | |
720 if (kAllowAlternateTimeSourceHandling) | |
721 now_function_ = now_function; | |
722 } | |
723 | |
724 // static | |
669 TrackedTime ThreadData::Now() { | 725 TrackedTime ThreadData::Now() { |
726 if (kAllowAlternateTimeSourceHandling && now_function_) | |
727 return TrackedTime::FromMilliseconds((*now_function_)()); | |
670 if (kTrackAllTaskObjects && TrackingStatus()) | 728 if (kTrackAllTaskObjects && TrackingStatus()) |
671 return TrackedTime::Now(); | 729 return TrackedTime::Now(); |
672 return TrackedTime(); // Super fast when disabled, or not compiled. | 730 return TrackedTime(); // Super fast when disabled, or not compiled. |
673 } | 731 } |
674 | 732 |
675 // static | 733 // static |
676 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { | 734 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { |
677 base::AutoLock lock(*list_lock_.Pointer()); | 735 base::AutoLock lock(*list_lock_.Pointer()); |
678 if (worker_thread_data_creation_count_ == 0) | 736 if (worker_thread_data_creation_count_ == 0) |
679 return; // We haven't really run much, and couldn't have leaked. | 737 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) { | 888 ++it) { |
831 base::DictionaryValue* parent_child = new base::DictionaryValue; | 889 base::DictionaryValue* parent_child = new base::DictionaryValue; |
832 it->first->ToValue("parent", parent_child); | 890 it->first->ToValue("parent", parent_child); |
833 it->second->ToValue("child", parent_child); | 891 it->second->ToValue("child", parent_child); |
834 descendants->Append(parent_child); | 892 descendants->Append(parent_child); |
835 } | 893 } |
836 dictionary->Set("descendants", descendants); | 894 dictionary->Set("descendants", descendants); |
837 } | 895 } |
838 | 896 |
839 } // namespace tracked_objects | 897 } // namespace tracked_objects |
OLD | NEW |