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" |
(...skipping 10 matching lines...) Expand all Loading... |
21 | 21 |
22 using base::TimeDelta; | 22 using base::TimeDelta; |
23 | 23 |
24 namespace base { | 24 namespace base { |
25 class TimeDelta; | 25 class TimeDelta; |
26 } | 26 } |
27 | 27 |
28 namespace tracked_objects { | 28 namespace tracked_objects { |
29 | 29 |
30 namespace { | 30 namespace { |
31 // TODO(jar): Evaluate the perf impact of enabling this. If the perf impact is | |
32 // negligible, enable by default. | |
33 // Flag to compile out parent-child link recording. | |
34 const bool kTrackParentChildLinks = false; | |
35 | |
36 // 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 |
37 // 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 |
38 // 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. |
39 // 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 |
40 // 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 |
41 // 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. |
42 const ThreadData::Status kInitialStartupState = | 37 const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE; |
43 ThreadData::PROFILING_CHILDREN_ACTIVE; | |
44 | 38 |
45 // Control whether an alternate time source (Now() function) is supported by | 39 // Control whether an alternate time source (Now() function) is supported by |
46 // the ThreadData class. This compile time flag should be set to true if we | 40 // the ThreadData class. This compile time flag should be set to true if we |
47 // want other modules (such as a memory allocator, or a thread-specific CPU time | 41 // want other modules (such as a memory allocator, or a thread-specific CPU time |
48 // clock) to be able to provide a thread-specific Now() function. Without this | 42 // clock) to be able to provide a thread-specific Now() function. Without this |
49 // compile-time flag, the code will only support the wall-clock time. This flag | 43 // compile-time flag, the code will only support the wall-clock time. This flag |
50 // can be flipped to efficiently disable this path (if there is a performance | 44 // can be flipped to efficiently disable this path (if there is a performance |
51 // problem with its presence). | 45 // problem with its presence). |
52 static const bool kAllowAlternateTimeSourceHandling = true; | 46 static const bool kAllowAlternateTimeSourceHandling = true; |
53 | 47 |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 child = it->second; | 515 child = it->second; |
522 child->RecordBirth(); | 516 child->RecordBirth(); |
523 } else { | 517 } else { |
524 child = new Births(location, *this); // Leak this. | 518 child = new Births(location, *this); // Leak this. |
525 // Lock since the map may get relocated now, and other threads sometimes | 519 // Lock since the map may get relocated now, and other threads sometimes |
526 // snapshot it (but they lock before copying it). | 520 // snapshot it (but they lock before copying it). |
527 base::AutoLock lock(map_lock_); | 521 base::AutoLock lock(map_lock_); |
528 birth_map_[location] = child; | 522 birth_map_[location] = child; |
529 } | 523 } |
530 | 524 |
531 if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE && | |
532 !parent_stack_.empty()) { | |
533 const Births* parent = parent_stack_.top(); | |
534 ParentChildPair pair(parent, child); | |
535 if (parent_child_set_.find(pair) == parent_child_set_.end()) { | |
536 // Lock since the map may get relocated now, and other threads sometimes | |
537 // snapshot it (but they lock before copying it). | |
538 base::AutoLock lock(map_lock_); | |
539 parent_child_set_.insert(pair); | |
540 } | |
541 } | |
542 | |
543 return child; | 525 return child; |
544 } | 526 } |
545 | 527 |
546 void ThreadData::TallyADeath(const Births& births, | 528 void ThreadData::TallyADeath(const Births& births, |
547 int32 queue_duration, | 529 int32 queue_duration, |
548 const TaskStopwatch& stopwatch) { | 530 const TaskStopwatch& stopwatch) { |
549 int32 run_duration = stopwatch.RunDurationMs(); | 531 int32 run_duration = stopwatch.RunDurationMs(); |
550 | 532 |
551 // Stir in some randomness, plus add constant in case durations are zero. | 533 // Stir in some randomness, plus add constant in case durations are zero. |
552 const uint32 kSomePrimeNumber = 2147483647; | 534 const uint32 kSomePrimeNumber = 2147483647; |
(...skipping 13 matching lines...) Expand all Loading... |
566 | 548 |
567 DeathMap::iterator it = death_map_.find(&births); | 549 DeathMap::iterator it = death_map_.find(&births); |
568 DeathData* death_data; | 550 DeathData* death_data; |
569 if (it != death_map_.end()) { | 551 if (it != death_map_.end()) { |
570 death_data = &it->second; | 552 death_data = &it->second; |
571 } else { | 553 } else { |
572 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 554 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
573 death_data = &death_map_[&births]; | 555 death_data = &death_map_[&births]; |
574 } // Release lock ASAP. | 556 } // Release lock ASAP. |
575 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 557 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
576 | |
577 if (!kTrackParentChildLinks) | |
578 return; | |
579 if (!parent_stack_.empty()) { // We might get turned off. | |
580 DCHECK_EQ(parent_stack_.top(), &births); | |
581 parent_stack_.pop(); | |
582 } | |
583 } | 558 } |
584 | 559 |
585 // static | 560 // static |
586 Births* ThreadData::TallyABirthIfActive(const Location& location) { | 561 Births* ThreadData::TallyABirthIfActive(const Location& location) { |
587 if (!TrackingStatus()) | 562 if (!TrackingStatus()) |
588 return NULL; | 563 return NULL; |
589 ThreadData* current_thread_data = Get(); | 564 ThreadData* current_thread_data = Get(); |
590 if (!current_thread_data) | 565 if (!current_thread_data) |
591 return NULL; | 566 return NULL; |
592 return current_thread_data->TallyABirth(location); | 567 return current_thread_data->TallyABirth(location); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 } | 646 } |
672 | 647 |
673 void ThreadData::SnapshotExecutedTasks( | 648 void ThreadData::SnapshotExecutedTasks( |
674 int current_profiling_phase, | 649 int current_profiling_phase, |
675 PhasedProcessDataSnapshotMap* phased_snapshots, | 650 PhasedProcessDataSnapshotMap* phased_snapshots, |
676 BirthCountMap* birth_counts) { | 651 BirthCountMap* birth_counts) { |
677 // Get copy of data, so that the data will not change during the iterations | 652 // Get copy of data, so that the data will not change during the iterations |
678 // and processing. | 653 // and processing. |
679 BirthMap birth_map; | 654 BirthMap birth_map; |
680 DeathsSnapshot deaths; | 655 DeathsSnapshot deaths; |
681 ParentChildSet parent_child_set; | 656 SnapshotMaps(current_profiling_phase, &birth_map, &deaths); |
682 SnapshotMaps(current_profiling_phase, &birth_map, &deaths, &parent_child_set); | |
683 | 657 |
684 for (const auto& birth : birth_map) { | 658 for (const auto& birth : birth_map) { |
685 (*birth_counts)[birth.second] += birth.second->birth_count(); | 659 (*birth_counts)[birth.second] += birth.second->birth_count(); |
686 } | 660 } |
687 | 661 |
688 for (const auto& death : deaths) { | 662 for (const auto& death : deaths) { |
689 (*birth_counts)[death.first] -= death.first->birth_count(); | 663 (*birth_counts)[death.first] -= death.first->birth_count(); |
690 | 664 |
691 // For the current death data, walk through all its snapshots, starting from | 665 // For the current death data, walk through all its snapshots, starting from |
692 // the current one, then from the previous profiling phase etc., and for | 666 // the current one, then from the previous profiling phase etc., and for |
(...skipping 10 matching lines...) Expand all Loading... |
703 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data, | 677 TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data, |
704 thread_name())); | 678 thread_name())); |
705 } | 679 } |
706 } | 680 } |
707 } | 681 } |
708 } | 682 } |
709 | 683 |
710 // This may be called from another thread. | 684 // This may be called from another thread. |
711 void ThreadData::SnapshotMaps(int profiling_phase, | 685 void ThreadData::SnapshotMaps(int profiling_phase, |
712 BirthMap* birth_map, | 686 BirthMap* birth_map, |
713 DeathsSnapshot* deaths, | 687 DeathsSnapshot* deaths) { |
714 ParentChildSet* parent_child_set) { | |
715 base::AutoLock lock(map_lock_); | 688 base::AutoLock lock(map_lock_); |
716 | 689 |
717 for (const auto& birth : birth_map_) | 690 for (const auto& birth : birth_map_) |
718 (*birth_map)[birth.first] = birth.second; | 691 (*birth_map)[birth.first] = birth.second; |
719 | 692 |
720 for (const auto& death : death_map_) { | 693 for (const auto& death : death_map_) { |
721 deaths->push_back(std::make_pair( | 694 deaths->push_back(std::make_pair( |
722 death.first, | 695 death.first, |
723 DeathDataPhaseSnapshot(profiling_phase, death.second.count(), | 696 DeathDataPhaseSnapshot(profiling_phase, death.second.count(), |
724 death.second.run_duration_sum(), | 697 death.second.run_duration_sum(), |
725 death.second.run_duration_max(), | 698 death.second.run_duration_max(), |
726 death.second.run_duration_sample(), | 699 death.second.run_duration_sample(), |
727 death.second.queue_duration_sum(), | 700 death.second.queue_duration_sum(), |
728 death.second.queue_duration_max(), | 701 death.second.queue_duration_max(), |
729 death.second.queue_duration_sample(), | 702 death.second.queue_duration_sample(), |
730 death.second.last_phase_snapshot()))); | 703 death.second.last_phase_snapshot()))); |
731 } | 704 } |
732 | |
733 if (!kTrackParentChildLinks) | |
734 return; | |
735 | |
736 for (const auto& parent_child : parent_child_set_) | |
737 parent_child_set->insert(parent_child); | |
738 } | 705 } |
739 | 706 |
740 void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) { | 707 void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) { |
741 base::AutoLock lock(map_lock_); | 708 base::AutoLock lock(map_lock_); |
742 | 709 |
743 for (auto& death : death_map_) { | 710 for (auto& death : death_map_) { |
744 death.second.OnProfilingPhaseCompleted(profiling_phase); | 711 death.second.OnProfilingPhaseCompleted(profiling_phase); |
745 } | 712 } |
746 } | 713 } |
747 | 714 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
784 } | 751 } |
785 | 752 |
786 // Incarnation counter is only significant to testing, as it otherwise will | 753 // Incarnation counter is only significant to testing, as it otherwise will |
787 // never again change in this process. | 754 // never again change in this process. |
788 ++incarnation_counter_; | 755 ++incarnation_counter_; |
789 | 756 |
790 // The lock is not critical for setting status_, but it doesn't hurt. It also | 757 // The lock is not critical for setting status_, but it doesn't hurt. It also |
791 // ensures that if we have a racy initialization, that we'll bail as soon as | 758 // ensures that if we have a racy initialization, that we'll bail as soon as |
792 // we get the lock earlier in this method. | 759 // we get the lock earlier in this method. |
793 status_ = kInitialStartupState; | 760 status_ = kInitialStartupState; |
794 if (!kTrackParentChildLinks && | |
795 kInitialStartupState == PROFILING_CHILDREN_ACTIVE) | |
796 status_ = PROFILING_ACTIVE; | |
797 DCHECK(status_ != UNINITIALIZED); | 761 DCHECK(status_ != UNINITIALIZED); |
798 return true; | 762 return true; |
799 } | 763 } |
800 | 764 |
801 // static | 765 // static |
802 bool ThreadData::InitializeAndSetTrackingStatus(Status status) { | 766 bool ThreadData::InitializeAndSetTrackingStatus(Status status) { |
803 DCHECK_GE(status, DEACTIVATED); | 767 DCHECK_GE(status, DEACTIVATED); |
804 DCHECK_LE(status, PROFILING_CHILDREN_ACTIVE); | 768 DCHECK_LE(status, PROFILING_ACTIVE); |
805 | 769 |
806 if (!Initialize()) // No-op if already initialized. | 770 if (!Initialize()) // No-op if already initialized. |
807 return false; // Not compiled in. | 771 return false; // Not compiled in. |
808 | 772 |
809 if (!kTrackParentChildLinks && status > DEACTIVATED) | 773 if (status > DEACTIVATED) |
810 status = PROFILING_ACTIVE; | 774 status = PROFILING_ACTIVE; |
811 status_ = status; | 775 status_ = status; |
812 return true; | 776 return true; |
813 } | 777 } |
814 | 778 |
815 // static | 779 // static |
816 ThreadData::Status ThreadData::status() { | 780 ThreadData::Status ThreadData::status() { |
817 return status_; | 781 return status_; |
818 } | 782 } |
819 | 783 |
820 // static | 784 // static |
821 bool ThreadData::TrackingStatus() { | 785 bool ThreadData::TrackingStatus() { |
822 return status_ > DEACTIVATED; | 786 return status_ > DEACTIVATED; |
823 } | 787 } |
824 | 788 |
825 // static | 789 // static |
826 bool ThreadData::TrackingParentChildStatus() { | |
827 return status_ >= PROFILING_CHILDREN_ACTIVE; | |
828 } | |
829 | |
830 // static | |
831 void ThreadData::PrepareForStartOfRun(const Births* parent) { | |
832 if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) { | |
833 ThreadData* current_thread_data = Get(); | |
834 if (current_thread_data) | |
835 current_thread_data->parent_stack_.push(parent); | |
836 } | |
837 } | |
838 | |
839 // static | |
840 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { | 790 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { |
841 DCHECK(now_function); | 791 DCHECK(now_function); |
842 if (kAllowAlternateTimeSourceHandling) | 792 if (kAllowAlternateTimeSourceHandling) |
843 now_function_ = now_function; | 793 now_function_ = now_function; |
844 } | 794 } |
845 | 795 |
846 // static | 796 // static |
847 void ThreadData::EnableProfilerTiming() { | 797 void ThreadData::EnableProfilerTiming() { |
848 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING); | 798 base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING); |
849 } | 799 } |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 const std::string& death_thread_name) | 1006 const std::string& death_thread_name) |
1057 : birth(birth), | 1007 : birth(birth), |
1058 death_data(death_data), | 1008 death_data(death_data), |
1059 death_thread_name(death_thread_name) { | 1009 death_thread_name(death_thread_name) { |
1060 } | 1010 } |
1061 | 1011 |
1062 TaskSnapshot::~TaskSnapshot() { | 1012 TaskSnapshot::~TaskSnapshot() { |
1063 } | 1013 } |
1064 | 1014 |
1065 //------------------------------------------------------------------------------ | 1015 //------------------------------------------------------------------------------ |
1066 // ParentChildPairSnapshot | |
1067 | |
1068 ParentChildPairSnapshot::ParentChildPairSnapshot() { | |
1069 } | |
1070 | |
1071 ParentChildPairSnapshot::ParentChildPairSnapshot( | |
1072 const ThreadData::ParentChildPair& parent_child) | |
1073 : parent(*parent_child.first), | |
1074 child(*parent_child.second) { | |
1075 } | |
1076 | |
1077 ParentChildPairSnapshot::~ParentChildPairSnapshot() { | |
1078 } | |
1079 | |
1080 //------------------------------------------------------------------------------ | |
1081 // ProcessDataPhaseSnapshot | 1016 // ProcessDataPhaseSnapshot |
1082 | 1017 |
1083 ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() { | 1018 ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() { |
1084 } | 1019 } |
1085 | 1020 |
1086 ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() { | 1021 ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() { |
1087 } | 1022 } |
1088 | 1023 |
1089 //------------------------------------------------------------------------------ | 1024 //------------------------------------------------------------------------------ |
1090 // ProcessDataPhaseSnapshot | 1025 // ProcessDataPhaseSnapshot |
1091 | 1026 |
1092 ProcessDataSnapshot::ProcessDataSnapshot() | 1027 ProcessDataSnapshot::ProcessDataSnapshot() |
1093 #if !defined(OS_NACL) | 1028 #if !defined(OS_NACL) |
1094 : process_id(base::GetCurrentProcId()) { | 1029 : process_id(base::GetCurrentProcId()) { |
1095 #else | 1030 #else |
1096 : process_id(base::kNullProcessId) { | 1031 : process_id(base::kNullProcessId) { |
1097 #endif | 1032 #endif |
1098 } | 1033 } |
1099 | 1034 |
1100 ProcessDataSnapshot::~ProcessDataSnapshot() { | 1035 ProcessDataSnapshot::~ProcessDataSnapshot() { |
1101 } | 1036 } |
1102 | 1037 |
1103 } // namespace tracked_objects | 1038 } // namespace tracked_objects |
OLD | NEW |