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 <limits.h> | 7 #include <limits.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #include "base/atomicops.h" | 10 #include "base/atomicops.h" |
11 #include "base/base_switches.h" | 11 #include "base/base_switches.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/debug/leak_annotations.h" | 14 #include "base/debug/leak_annotations.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/process/process_handle.h" | 16 #include "base/process/process_handle.h" |
17 #include "base/profiler/alternate_timer.h" | |
18 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
19 #include "base/third_party/valgrind/memcheck.h" | 18 #include "base/third_party/valgrind/memcheck.h" |
20 #include "base/tracking_info.h" | 19 #include "base/tracking_info.h" |
21 #include "build/build_config.h" | 20 #include "build/build_config.h" |
22 | 21 |
23 using base::TimeDelta; | 22 using base::TimeDelta; |
24 | 23 |
25 namespace base { | 24 namespace base { |
26 class TimeDelta; | 25 class TimeDelta; |
27 } | 26 } |
28 | 27 |
29 namespace tracked_objects { | 28 namespace tracked_objects { |
30 | 29 |
31 namespace { | 30 namespace { |
32 // When ThreadData is first initialized, should we start in an ACTIVE state to | 31 // When ThreadData is first initialized, should we start in an ACTIVE state to |
33 // record all of the startup-time tasks, or should we start up DEACTIVATED, so | 32 // record all of the startup-time tasks, or should we start up DEACTIVATED, so |
34 // that we only record after parsing the command line flag --enable-tracking. | 33 // that we only record after parsing the command line flag --enable-tracking. |
35 // Note that the flag may force either state, so this really controls only the | 34 // Note that the flag may force either state, so this really controls only the |
36 // period of time up until that flag is parsed. If there is no flag seen, then | 35 // period of time up until that flag is parsed. If there is no flag seen, then |
37 // this state may prevail for much or all of the process lifetime. | 36 // this state may prevail for much or all of the process lifetime. |
38 const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE; | 37 const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE; |
39 | 38 |
40 // Control whether an alternate time source (Now() function) is supported by | |
41 // the ThreadData class. This compile time flag should be set to true if we | |
42 // want other modules (such as a memory allocator, or a thread-specific CPU time | |
43 // clock) to be able to provide a thread-specific Now() function. Without this | |
44 // compile-time flag, the code will only support the wall-clock time. This flag | |
45 // can be flipped to efficiently disable this path (if there is a performance | |
46 // problem with its presence). | |
47 static const bool kAllowAlternateTimeSourceHandling = true; | |
48 | |
49 // Possible states of the profiler timing enabledness. | 39 // Possible states of the profiler timing enabledness. |
50 enum { | 40 enum { |
51 UNDEFINED_TIMING, | 41 UNDEFINED_TIMING, |
52 ENABLED_TIMING, | 42 ENABLED_TIMING, |
53 DISABLED_TIMING, | 43 DISABLED_TIMING, |
54 }; | 44 }; |
55 | 45 |
56 // State of the profiler timing enabledness. | 46 // State of the profiler timing enabledness. |
57 base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING; | 47 base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING; |
58 | 48 |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 | 268 |
279 //------------------------------------------------------------------------------ | 269 //------------------------------------------------------------------------------ |
280 // ThreadData maintains the central data for all births and deaths on a single | 270 // ThreadData maintains the central data for all births and deaths on a single |
281 // thread. | 271 // thread. |
282 | 272 |
283 // TODO(jar): We should pull all these static vars together, into a struct, and | 273 // TODO(jar): We should pull all these static vars together, into a struct, and |
284 // optimize layout so that we benefit from locality of reference during accesses | 274 // optimize layout so that we benefit from locality of reference during accesses |
285 // to them. | 275 // to them. |
286 | 276 |
287 // static | 277 // static |
288 NowFunction* ThreadData::now_function_ = NULL; | 278 ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL; |
289 | |
290 // static | |
291 bool ThreadData::now_function_is_time_ = false; | |
292 | 279 |
293 // A TLS slot which points to the ThreadData instance for the current thread. | 280 // A TLS slot which points to the ThreadData instance for the current thread. |
294 // We do a fake initialization here (zeroing out data), and then the real | 281 // We do a fake initialization here (zeroing out data), and then the real |
295 // in-place construction happens when we call tls_index_.Initialize(). | 282 // in-place construction happens when we call tls_index_.Initialize(). |
296 // static | 283 // static |
297 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; | 284 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; |
298 | 285 |
299 // static | 286 // static |
300 int ThreadData::worker_thread_data_creation_count_ = 0; | 287 int ThreadData::worker_thread_data_creation_count_ = 0; |
301 | 288 |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 const TaskStopwatch& stopwatch) { | 496 const TaskStopwatch& stopwatch) { |
510 int32_t run_duration = stopwatch.RunDurationMs(); | 497 int32_t run_duration = stopwatch.RunDurationMs(); |
511 | 498 |
512 // Stir in some randomness, plus add constant in case durations are zero. | 499 // Stir in some randomness, plus add constant in case durations are zero. |
513 const uint32_t kSomePrimeNumber = 2147483647; | 500 const uint32_t kSomePrimeNumber = 2147483647; |
514 random_number_ += queue_duration + run_duration + kSomePrimeNumber; | 501 random_number_ += queue_duration + run_duration + kSomePrimeNumber; |
515 // An address is going to have some randomness to it as well ;-). | 502 // An address is going to have some randomness to it as well ;-). |
516 random_number_ ^= | 503 random_number_ ^= |
517 static_cast<uint32_t>(&births - reinterpret_cast<Births*>(0)); | 504 static_cast<uint32_t>(&births - reinterpret_cast<Births*>(0)); |
518 | 505 |
519 // We don't have queue durations without OS timer. OS timer is automatically | |
520 // used for task-post-timing, so the use of an alternate timer implies all | |
521 // queue times are invalid, unless it was explicitly said that we can trust | |
522 // the alternate timer. | |
523 if (kAllowAlternateTimeSourceHandling && | |
524 now_function_ && | |
525 !now_function_is_time_) { | |
526 queue_duration = 0; | |
527 } | |
528 | |
529 DeathMap::iterator it = death_map_.find(&births); | 506 DeathMap::iterator it = death_map_.find(&births); |
530 DeathData* death_data; | 507 DeathData* death_data; |
531 if (it != death_map_.end()) { | 508 if (it != death_map_.end()) { |
532 death_data = &it->second; | 509 death_data = &it->second; |
533 } else { | 510 } else { |
534 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 511 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
535 death_data = &death_map_[&births]; | 512 death_data = &death_map_[&births]; |
536 } // Release lock ASAP. | 513 } // Release lock ASAP. |
537 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 514 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
538 } | 515 } |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 } | 662 } |
686 | 663 |
687 void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) { | 664 void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) { |
688 base::AutoLock lock(map_lock_); | 665 base::AutoLock lock(map_lock_); |
689 | 666 |
690 for (auto& death : death_map_) { | 667 for (auto& death : death_map_) { |
691 death.second.OnProfilingPhaseCompleted(profiling_phase); | 668 death.second.OnProfilingPhaseCompleted(profiling_phase); |
692 } | 669 } |
693 } | 670 } |
694 | 671 |
695 static void OptionallyInitializeAlternateTimer() { | |
696 NowFunction* alternate_time_source = GetAlternateTimeSource(); | |
697 if (alternate_time_source) | |
698 ThreadData::SetAlternateTimeSource(alternate_time_source); | |
699 } | |
700 | |
701 void ThreadData::Initialize() { | 672 void ThreadData::Initialize() { |
702 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED) | 673 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED) |
703 return; // Someone else did the initialization. | 674 return; // Someone else did the initialization. |
704 // Due to racy lazy initialization in tests, we'll need to recheck status_ | 675 // Due to racy lazy initialization in tests, we'll need to recheck status_ |
705 // after we acquire the lock. | 676 // after we acquire the lock. |
706 | 677 |
707 // Ensure that we don't double initialize tls. We are called when single | 678 // Ensure that we don't double initialize tls. We are called when single |
708 // threaded in the product, but some tests may be racy and lazy about our | 679 // threaded in the product, but some tests may be racy and lazy about our |
709 // initialization. | 680 // initialization. |
710 base::AutoLock lock(*list_lock_.Pointer()); | 681 base::AutoLock lock(*list_lock_.Pointer()); |
711 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED) | 682 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED) |
712 return; // Someone raced in here and beat us. | 683 return; // Someone raced in here and beat us. |
713 | 684 |
714 // Put an alternate timer in place if the environment calls for it, such as | |
715 // for tracking TCMalloc allocations. This insertion is idempotent, so we | |
716 // don't mind if there is a race, and we'd prefer not to be in a lock while | |
717 // doing this work. | |
718 if (kAllowAlternateTimeSourceHandling) | |
719 OptionallyInitializeAlternateTimer(); | |
720 | |
721 // Perform the "real" TLS initialization now, and leave it intact through | 685 // Perform the "real" TLS initialization now, and leave it intact through |
722 // process termination. | 686 // process termination. |
723 if (!tls_index_.initialized()) { // Testing may have initialized this. | 687 if (!tls_index_.initialized()) { // Testing may have initialized this. |
724 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED); | 688 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED); |
725 tls_index_.Initialize(&ThreadData::OnThreadTermination); | 689 tls_index_.Initialize(&ThreadData::OnThreadTermination); |
726 DCHECK(tls_index_.initialized()); | 690 DCHECK(tls_index_.initialized()); |
727 } else { | 691 } else { |
728 // TLS was initialzed for us earlier. | 692 // TLS was initialzed for us earlier. |
729 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), DORMANT_DURING_TESTS); | 693 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), DORMANT_DURING_TESTS); |
730 } | 694 } |
(...skipping 25 matching lines...) Expand all Loading... |
756 ThreadData::Status ThreadData::status() { | 720 ThreadData::Status ThreadData::status() { |
757 return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_)); | 721 return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_)); |
758 } | 722 } |
759 | 723 |
760 // static | 724 // static |
761 bool ThreadData::TrackingStatus() { | 725 bool ThreadData::TrackingStatus() { |
762 return base::subtle::Acquire_Load(&status_) > DEACTIVATED; | 726 return base::subtle::Acquire_Load(&status_) > DEACTIVATED; |
763 } | 727 } |
764 | 728 |
765 // static | 729 // static |
766 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { | |
767 DCHECK(now_function); | |
768 if (kAllowAlternateTimeSourceHandling) | |
769 now_function_ = now_function; | |
770 } | |
771 | |
772 // static | |
773 void ThreadData::EnableProfilerTiming() { | 730 void ThreadData::EnableProfilerTiming() { |
774 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING); | 731 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING); |
775 } | 732 } |
776 | 733 |
777 // static | 734 // static |
778 TrackedTime ThreadData::Now() { | 735 TrackedTime ThreadData::Now() { |
779 if (kAllowAlternateTimeSourceHandling && now_function_) | 736 if (now_function_for_testing_) |
780 return TrackedTime::FromMilliseconds((*now_function_)()); | 737 return TrackedTime::FromMilliseconds((*now_function_for_testing_)()); |
781 if (IsProfilerTimingEnabled() && TrackingStatus()) | 738 if (IsProfilerTimingEnabled() && TrackingStatus()) |
782 return TrackedTime::Now(); | 739 return TrackedTime::Now(); |
783 return TrackedTime(); // Super fast when disabled, or not compiled. | 740 return TrackedTime(); // Super fast when disabled, or not compiled. |
784 } | 741 } |
785 | 742 |
786 // static | 743 // static |
787 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { | 744 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { |
788 base::AutoLock lock(*list_lock_.Pointer()); | 745 base::AutoLock lock(*list_lock_.Pointer()); |
789 if (worker_thread_data_creation_count_ == 0) | 746 if (worker_thread_data_creation_count_ == 0) |
790 return; // We haven't really run much, and couldn't have leaked. | 747 return; // We haven't really run much, and couldn't have leaked. |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1005 : process_id(base::GetCurrentProcId()) { | 962 : process_id(base::GetCurrentProcId()) { |
1006 #else | 963 #else |
1007 : process_id(base::kNullProcessId) { | 964 : process_id(base::kNullProcessId) { |
1008 #endif | 965 #endif |
1009 } | 966 } |
1010 | 967 |
1011 ProcessDataSnapshot::~ProcessDataSnapshot() { | 968 ProcessDataSnapshot::~ProcessDataSnapshot() { |
1012 } | 969 } |
1013 | 970 |
1014 } // namespace tracked_objects | 971 } // namespace tracked_objects |
OLD | NEW |