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 #ifndef BASE_TRACKED_OBJECTS_H_ | 5 #ifndef BASE_TRACKED_OBJECTS_H_ |
6 #define BASE_TRACKED_OBJECTS_H_ | 6 #define BASE_TRACKED_OBJECTS_H_ |
7 | 7 |
8 #include <map> | 8 #include <map> |
9 #include <set> | 9 #include <set> |
10 #include <stack> | 10 #include <stack> |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 // instances for each combination of birth thread, death thread, and location, | 147 // instances for each combination of birth thread, death thread, and location, |
148 // along with the count of such lifetimes. We gather such data into a | 148 // along with the count of such lifetimes. We gather such data into a |
149 // TaskSnapshot instances, so that such instances can be sorted and | 149 // TaskSnapshot instances, so that such instances can be sorted and |
150 // aggregated (and remain frozen during our processing). | 150 // aggregated (and remain frozen during our processing). |
151 // | 151 // |
152 // Profiling consists of phases. The concrete phase in the sequence of phases | 152 // Profiling consists of phases. The concrete phase in the sequence of phases |
153 // is identified by its 0-based index. | 153 // is identified by its 0-based index. |
154 // | 154 // |
155 // The ProcessDataPhaseSnapshot struct is a serialized representation of the | 155 // The ProcessDataPhaseSnapshot struct is a serialized representation of the |
156 // list of ThreadData objects for a process for a concrete profiling phase. It | 156 // list of ThreadData objects for a process for a concrete profiling phase. It |
157 // holds a set of TaskSnapshots and tracks parent/child relationships for the | 157 // holds a set of TaskSnapshots. The statistics in a snapshot are gathered |
158 // executed tasks. The statistics in a snapshot are gathered asynhcronously | 158 // asynhcronously relative to their ongoing updates. |
159 // relative to their ongoing updates. | |
160 // It is possible, though highly unlikely, that stats could be incorrectly | 159 // It is possible, though highly unlikely, that stats could be incorrectly |
161 // recorded by this process (all data is held in 32 bit ints, but we are not | 160 // recorded by this process (all data is held in 32 bit ints, but we are not |
162 // atomically collecting all data, so we could have count that does not, for | 161 // atomically collecting all data, so we could have count that does not, for |
163 // example, match with the number of durations we accumulated). The advantage | 162 // example, match with the number of durations we accumulated). The advantage |
164 // to having fast (non-atomic) updates of the data outweighs the minimal risk of | 163 // to having fast (non-atomic) updates of the data outweighs the minimal risk of |
165 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, | 164 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, |
166 // not the underlying and ongoing statistic). In contrast, pointer data that | 165 // not the underlying and ongoing statistic). In contrast, pointer data that |
167 // is accessed during snapshotting is completely invariant, and hence is | 166 // is accessed during snapshotting is completely invariant, and hence is |
168 // perfectly acquired (i.e., no potential corruption, and no risk of a bad | 167 // perfectly acquired (i.e., no potential corruption, and no risk of a bad |
169 // memory reference). | 168 // memory reference). |
170 // | 169 // |
171 // TODO(jar): We can implement a Snapshot system that *tries* to grab the | 170 // TODO(jar): We can implement a Snapshot system that *tries* to grab the |
172 // snapshots on the source threads *when* they have MessageLoops available | 171 // snapshots on the source threads *when* they have MessageLoops available |
173 // (worker threads don't have message loops generally, and hence gathering from | 172 // (worker threads don't have message loops generally, and hence gathering from |
174 // them will continue to be asynchronous). We had an implementation of this in | 173 // them will continue to be asynchronous). We had an implementation of this in |
175 // the past, but the difficulty is dealing with message loops being terminated. | 174 // the past, but the difficulty is dealing with message loops being terminated. |
176 // We can *try* to spam the available threads via some message loop proxy to | 175 // We can *try* to spam the available threads via some message loop proxy to |
177 // achieve this feat, and it *might* be valuable when we are collecting data | 176 // achieve this feat, and it *might* be valuable when we are collecting data |
178 // for upload via UMA (where correctness of data may be more significant than | 177 // for upload via UMA (where correctness of data may be more significant than |
179 // for a single screen of about:profiler). | 178 // for a single screen of about:profiler). |
180 // | 179 // |
181 // TODO(jar): We should support (optionally) the recording of parent-child | |
182 // relationships for tasks. This should be done by detecting what tasks are | |
183 // Born during the running of a parent task. The resulting data can be used by | |
184 // a smarter profiler to aggregate the cost of a series of child tasks into | |
185 // the ancestor task. It can also be used to illuminate what child or parent is | |
186 // related to each task. | |
187 // | |
188 // TODO(jar): We need to store DataCollections, and provide facilities for | 180 // TODO(jar): We need to store DataCollections, and provide facilities for |
189 // taking the difference between two gathered DataCollections. For now, we're | 181 // taking the difference between two gathered DataCollections. For now, we're |
190 // just adding a hack that Reset()s to zero all counts and stats. This is also | 182 // just adding a hack that Reset()s to zero all counts and stats. This is also |
191 // done in a slightly thread-unsafe fashion, as the resetting is done | 183 // done in a slightly thread-unsafe fashion, as the resetting is done |
192 // asynchronously relative to ongoing updates (but all data is 32 bit in size). | 184 // asynchronously relative to ongoing updates (but all data is 32 bit in size). |
193 // For basic profiling, this will work "most of the time," and should be | 185 // For basic profiling, this will work "most of the time," and should be |
194 // sufficient... but storing away DataCollections is the "right way" to do this. | 186 // sufficient... but storing away DataCollections is the "right way" to do this. |
195 // We'll accomplish this via JavaScript storage of snapshots, and then we'll | 187 // We'll accomplish this via JavaScript storage of snapshots, and then we'll |
196 // remove the Reset() methods. We may also need a short-term-max value in | 188 // remove the Reset() methods. We may also need a short-term-max value in |
197 // DeathData that is reset (as synchronously as possible) during each snapshot. | 189 // DeathData that is reset (as synchronously as possible) during each snapshot. |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 // Map from profiling phase number to the process-wide snapshotted | 415 // Map from profiling phase number to the process-wide snapshotted |
424 // representation of the list of ThreadData objects that died during the given | 416 // representation of the list of ThreadData objects that died during the given |
425 // phase. | 417 // phase. |
426 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; | 418 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; |
427 | 419 |
428 class BASE_EXPORT ThreadData { | 420 class BASE_EXPORT ThreadData { |
429 public: | 421 public: |
430 // Current allowable states of the tracking system. The states can vary | 422 // Current allowable states of the tracking system. The states can vary |
431 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. | 423 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. |
432 enum Status { | 424 enum Status { |
433 UNINITIALIZED, // PRistine, link-time state before running. | 425 UNINITIALIZED, // Pristine, link-time state before running. |
434 DORMANT_DURING_TESTS, // Only used during testing. | 426 DORMANT_DURING_TESTS, // Only used during testing. |
435 DEACTIVATED, // No longer recording profiling. | 427 DEACTIVATED, // No longer recording profiling. |
436 PROFILING_ACTIVE, // Recording profiles (no parent-child links). | 428 PROFILING_ACTIVE, // Recording profiles. |
437 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. | 429 STATUS_LAST = PROFILING_ACTIVE |
438 STATUS_LAST = PROFILING_CHILDREN_ACTIVE | |
439 }; | 430 }; |
440 | 431 |
441 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; | 432 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; |
442 typedef std::map<const Births*, DeathData> DeathMap; | 433 typedef std::map<const Births*, DeathData> DeathMap; |
443 typedef std::pair<const Births*, const Births*> ParentChildPair; | |
444 typedef std::set<ParentChildPair> ParentChildSet; | |
445 typedef std::stack<const Births*> ParentStack; | |
446 | 434 |
447 // Initialize the current thread context with a new instance of ThreadData. | 435 // Initialize the current thread context with a new instance of ThreadData. |
448 // This is used by all threads that have names, and should be explicitly | 436 // This is used by all threads that have names, and should be explicitly |
449 // set *before* any births on the threads have taken place. It is generally | 437 // set *before* any births on the threads have taken place. It is generally |
450 // only used by the message loop, which has a well defined thread name. | 438 // only used by the message loop, which has a well defined thread name. |
451 static void InitializeThreadContext(const std::string& suggested_name); | 439 static void InitializeThreadContext(const std::string& suggested_name); |
452 | 440 |
453 // Using Thread Local Store, find the current instance for collecting data. | 441 // Using Thread Local Store, find the current instance for collecting data. |
454 // If an instance does not exist, construct one (and remember it for use on | 442 // If an instance does not exist, construct one (and remember it for use on |
455 // this thread. | 443 // this thread. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 const TaskStopwatch& stopwatch); | 495 const TaskStopwatch& stopwatch); |
508 | 496 |
509 const std::string& thread_name() const { return thread_name_; } | 497 const std::string& thread_name() const { return thread_name_; } |
510 | 498 |
511 // Initializes all statics if needed (this initialization call should be made | 499 // Initializes all statics if needed (this initialization call should be made |
512 // while we are single threaded). Returns false if unable to initialize. | 500 // while we are single threaded). Returns false if unable to initialize. |
513 static bool Initialize(); | 501 static bool Initialize(); |
514 | 502 |
515 // Sets internal status_. | 503 // Sets internal status_. |
516 // If |status| is false, then status_ is set to DEACTIVATED. | 504 // If |status| is false, then status_ is set to DEACTIVATED. |
517 // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or | 505 // If |status| is true, then status_ is set to PROFILING_ACTIVE. |
518 // PROFILING_CHILDREN_ACTIVE. | 506 // If it fails to initialize the TLS slot, this function will return false. |
519 // If tracking is not compiled in, this function will return false. | |
520 // If parent-child tracking is not compiled in, then an attempt to set the | |
521 // status to PROFILING_CHILDREN_ACTIVE will only result in a status of | |
522 // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is | |
523 // compiled into the binary, and parent-child tracking at the | |
524 // PROFILING_CHILDREN_ACTIVE level might not be compiled in). | |
525 static bool InitializeAndSetTrackingStatus(Status status); | 507 static bool InitializeAndSetTrackingStatus(Status status); |
526 | 508 |
527 static Status status(); | 509 static Status status(); |
528 | 510 |
529 // Indicate if any sort of profiling is being done (i.e., we are more than | 511 // Indicate if any sort of profiling is being done (i.e., we are more than |
530 // DEACTIVATED). | 512 // DEACTIVATED). |
531 static bool TrackingStatus(); | 513 static bool TrackingStatus(); |
532 | 514 |
533 // For testing only, indicate if the status of parent-child tracking is turned | |
534 // on. This is currently a compiled option, atop TrackingStatus(). | |
535 static bool TrackingParentChildStatus(); | |
536 | |
537 // Marks a start of a tracked run. It's super fast when tracking is disabled, | |
538 // and has some internal side effects when we are tracking, so that we can | |
539 // deduce the amount of time accumulated outside of execution of tracked runs. | |
540 // The task that will be tracked is passed in as |parent| so that parent-child | |
541 // relationships can be (optionally) calculated. | |
542 static void PrepareForStartOfRun(const Births* parent); | |
543 | |
544 // Enables profiler timing. | 515 // Enables profiler timing. |
545 static void EnableProfilerTiming(); | 516 static void EnableProfilerTiming(); |
546 | 517 |
547 // Provide a time function that does nothing (runs fast) when we don't have | 518 // Provide a time function that does nothing (runs fast) when we don't have |
548 // the profiler enabled. It will generally be optimized away when it is | 519 // the profiler enabled. It will generally be optimized away when it is |
549 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of | 520 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of |
550 // the code). | 521 // the code). |
551 static TrackedTime Now(); | 522 static TrackedTime Now(); |
552 | 523 |
553 // Use the function |now| to provide current times, instead of calling the | 524 // Use the function |now| to provide current times, instead of calling the |
(...skipping 10 matching lines...) Expand all Loading... |
564 private: | 535 private: |
565 friend class TaskStopwatch; | 536 friend class TaskStopwatch; |
566 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it | 537 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it |
567 // in production code. | 538 // in production code. |
568 // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a | 539 // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a |
569 // better change of optimizing (inlining? etc.) private methods (knowing that | 540 // better change of optimizing (inlining? etc.) private methods (knowing that |
570 // there will be no need for an external entry point). | 541 // there will be no need for an external entry point). |
571 friend class TrackedObjectsTest; | 542 friend class TrackedObjectsTest; |
572 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); | 543 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); |
573 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); | 544 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
574 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest); | |
575 | 545 |
576 typedef std::map<const BirthOnThread*, int> BirthCountMap; | 546 typedef std::map<const BirthOnThread*, int> BirthCountMap; |
577 | 547 |
578 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> | 548 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> |
579 DeathsSnapshot; | 549 DeathsSnapshot; |
580 | 550 |
581 // Worker thread construction creates a name since there is none. | 551 // Worker thread construction creates a name since there is none. |
582 explicit ThreadData(int thread_number); | 552 explicit ThreadData(int thread_number); |
583 | 553 |
584 // Message loop based construction should provide a name. | 554 // Message loop based construction should provide a name. |
(...skipping 30 matching lines...) Expand all Loading... |
615 // number of births for the task that have not yet been balanced by a death. | 585 // number of births for the task that have not yet been balanced by a death. |
616 void SnapshotExecutedTasks(int current_profiling_phase, | 586 void SnapshotExecutedTasks(int current_profiling_phase, |
617 PhasedProcessDataSnapshotMap* phased_snapshots, | 587 PhasedProcessDataSnapshotMap* phased_snapshots, |
618 BirthCountMap* birth_counts); | 588 BirthCountMap* birth_counts); |
619 | 589 |
620 // Using our lock, make a copy of the specified maps. This call may be made | 590 // Using our lock, make a copy of the specified maps. This call may be made |
621 // on non-local threads, which necessitate the use of the lock to prevent | 591 // on non-local threads, which necessitate the use of the lock to prevent |
622 // the map(s) from being reallocated while they are copied. | 592 // the map(s) from being reallocated while they are copied. |
623 void SnapshotMaps(int profiling_phase, | 593 void SnapshotMaps(int profiling_phase, |
624 BirthMap* birth_map, | 594 BirthMap* birth_map, |
625 DeathsSnapshot* deaths, | 595 DeathsSnapshot* deaths); |
626 ParentChildSet* parent_child_set); | |
627 | 596 |
628 // Called for this thread when the current profiling phase, identified by | 597 // Called for this thread when the current profiling phase, identified by |
629 // |profiling_phase|, ends. | 598 // |profiling_phase|, ends. |
630 void OnProfilingPhaseCompletedOnThread(int profiling_phase); | 599 void OnProfilingPhaseCompletedOnThread(int profiling_phase); |
631 | 600 |
632 // This method is called by the TLS system when a thread terminates. | 601 // This method is called by the TLS system when a thread terminates. |
633 // The argument may be NULL if this thread has never tracked a birth or death. | 602 // The argument may be NULL if this thread has never tracked a birth or death. |
634 static void OnThreadTermination(void* thread_data); | 603 static void OnThreadTermination(void* thread_data); |
635 | 604 |
636 // This method should be called when a worker thread terminates, so that we | 605 // This method should be called when a worker thread terminates, so that we |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 // When a snapshot is needed, this structure can be locked in place for the | 687 // When a snapshot is needed, this structure can be locked in place for the |
719 // duration of the snapshotting activity. | 688 // duration of the snapshotting activity. |
720 BirthMap birth_map_; | 689 BirthMap birth_map_; |
721 | 690 |
722 // Similar to birth_map_, this records informations about death of tracked | 691 // Similar to birth_map_, this records informations about death of tracked |
723 // instances (i.e., when a tracked instance was destroyed on this thread). | 692 // instances (i.e., when a tracked instance was destroyed on this thread). |
724 // It is locked before changing, and hence other threads may access it by | 693 // It is locked before changing, and hence other threads may access it by |
725 // locking before reading it. | 694 // locking before reading it. |
726 DeathMap death_map_; | 695 DeathMap death_map_; |
727 | 696 |
728 // A set of parents that created children tasks on this thread. Each pair | |
729 // corresponds to potentially non-local Births (location and thread), and a | |
730 // local Births (that took place on this thread). | |
731 ParentChildSet parent_child_set_; | |
732 | |
733 // Lock to protect *some* access to BirthMap and DeathMap. The maps are | 697 // Lock to protect *some* access to BirthMap and DeathMap. The maps are |
734 // regularly read and written on this thread, but may only be read from other | 698 // regularly read and written on this thread, but may only be read from other |
735 // threads. To support this, we acquire this lock if we are writing from this | 699 // threads. To support this, we acquire this lock if we are writing from this |
736 // thread, or reading from another thread. For reading from this thread we | 700 // thread, or reading from another thread. For reading from this thread we |
737 // don't need a lock, as there is no potential for a conflict since the | 701 // don't need a lock, as there is no potential for a conflict since the |
738 // writing is only done from this thread. | 702 // writing is only done from this thread. |
739 mutable base::Lock map_lock_; | 703 mutable base::Lock map_lock_; |
740 | 704 |
741 // The stack of parents that are currently being profiled. This includes only | |
742 // tasks that have started a timer recently via PrepareForStartOfRun(), but | |
743 // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep, | |
744 // but if a scoped region is profiled, or <sigh> a task runs a nested-message | |
745 // loop, then the stack can grow larger. Note that we don't try to deduct | |
746 // time in nested profiles, as our current timer is based on wall-clock time, | |
747 // and not CPU time (and we're hopeful that nested timing won't be a | |
748 // significant additional cost). | |
749 ParentStack parent_stack_; | |
750 | |
751 // A random number that we used to select decide which sample to keep as a | 705 // A random number that we used to select decide which sample to keep as a |
752 // representative sample in each DeathData instance. We can't start off with | 706 // representative sample in each DeathData instance. We can't start off with |
753 // much randomness (because we can't call RandInt() on all our threads), so | 707 // much randomness (because we can't call RandInt() on all our threads), so |
754 // we stir in more and more as we go. | 708 // we stir in more and more as we go. |
755 uint32 random_number_; | 709 uint32 random_number_; |
756 | 710 |
757 // Record of what the incarnation_counter_ was when this instance was created. | 711 // Record of what the incarnation_counter_ was when this instance was created. |
758 // If the incarnation_counter_ has changed, then we avoid pushing into the | 712 // If the incarnation_counter_ has changed, then we avoid pushing into the |
759 // pool (this is only critical in tests which go through multiple | 713 // pool (this is only critical in tests which go through multiple |
760 // incarnations). | 714 // incarnations). |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 // state, then is optionally started/stopped, then destructed. | 775 // state, then is optionally started/stopped, then destructed. |
822 enum { CREATED, RUNNING, STOPPED } state_; | 776 enum { CREATED, RUNNING, STOPPED } state_; |
823 | 777 |
824 // Currently running stopwatch that is directly nested in this one, if such | 778 // Currently running stopwatch that is directly nested in this one, if such |
825 // stopwatch exists. NULL otherwise. | 779 // stopwatch exists. NULL otherwise. |
826 TaskStopwatch* child_; | 780 TaskStopwatch* child_; |
827 #endif | 781 #endif |
828 }; | 782 }; |
829 | 783 |
830 //------------------------------------------------------------------------------ | 784 //------------------------------------------------------------------------------ |
831 // A snapshotted representation of a (parent, child) task pair, for tracking | |
832 // hierarchical profiles. | |
833 | |
834 struct BASE_EXPORT ParentChildPairSnapshot { | |
835 public: | |
836 ParentChildPairSnapshot(); | |
837 explicit ParentChildPairSnapshot( | |
838 const ThreadData::ParentChildPair& parent_child); | |
839 ~ParentChildPairSnapshot(); | |
840 | |
841 BirthOnThreadSnapshot parent; | |
842 BirthOnThreadSnapshot child; | |
843 }; | |
844 | |
845 //------------------------------------------------------------------------------ | |
846 // A snapshotted representation of the list of ThreadData objects for a process, | 785 // A snapshotted representation of the list of ThreadData objects for a process, |
847 // for a single profiling phase. | 786 // for a single profiling phase. |
848 | 787 |
849 struct BASE_EXPORT ProcessDataPhaseSnapshot { | 788 struct BASE_EXPORT ProcessDataPhaseSnapshot { |
850 public: | 789 public: |
851 ProcessDataPhaseSnapshot(); | 790 ProcessDataPhaseSnapshot(); |
852 ~ProcessDataPhaseSnapshot(); | 791 ~ProcessDataPhaseSnapshot(); |
853 | 792 |
854 std::vector<TaskSnapshot> tasks; | 793 std::vector<TaskSnapshot> tasks; |
855 std::vector<ParentChildPairSnapshot> descendants; | |
856 }; | 794 }; |
857 | 795 |
858 //------------------------------------------------------------------------------ | 796 //------------------------------------------------------------------------------ |
859 // A snapshotted representation of the list of ThreadData objects for a process, | 797 // A snapshotted representation of the list of ThreadData objects for a process, |
860 // for all profiling phases, including the current one. | 798 // for all profiling phases, including the current one. |
861 | 799 |
862 struct BASE_EXPORT ProcessDataSnapshot { | 800 struct BASE_EXPORT ProcessDataSnapshot { |
863 public: | 801 public: |
864 ProcessDataSnapshot(); | 802 ProcessDataSnapshot(); |
865 ~ProcessDataSnapshot(); | 803 ~ProcessDataSnapshot(); |
866 | 804 |
867 PhasedProcessDataSnapshotMap phased_snapshots; | 805 PhasedProcessDataSnapshotMap phased_snapshots; |
868 base::ProcessId process_id; | 806 base::ProcessId process_id; |
869 }; | 807 }; |
870 | 808 |
871 } // namespace tracked_objects | 809 } // namespace tracked_objects |
872 | 810 |
873 #endif // BASE_TRACKED_OBJECTS_H_ | 811 #endif // BASE_TRACKED_OBJECTS_H_ |
OLD | NEW |