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 <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <map> | 10 #include <map> |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 // | 55 // |
56 // First off, when the instance is created, the FROM_HERE macro is expanded | 56 // First off, when the instance is created, the FROM_HERE macro is expanded |
57 // to specify the birth place (file, line, function) where the instance was | 57 // to specify the birth place (file, line, function) where the instance was |
58 // created. That data is used to create a transient Location instance | 58 // created. That data is used to create a transient Location instance |
59 // encapsulating the above triple of information. The strings (like __FILE__) | 59 // encapsulating the above triple of information. The strings (like __FILE__) |
60 // are passed around by reference, with the assumption that they are static, and | 60 // are passed around by reference, with the assumption that they are static, and |
61 // will never go away. This ensures that the strings can be dealt with as atoms | 61 // will never go away. This ensures that the strings can be dealt with as atoms |
62 // with great efficiency (i.e., copying of strings is never needed, and | 62 // with great efficiency (i.e., copying of strings is never needed, and |
63 // comparisons for equality can be based on pointer comparisons). | 63 // comparisons for equality can be based on pointer comparisons). |
64 // | 64 // |
65 // Next, a Births instance is created for use ONLY on the thread where this | 65 // Next, a Births instance is constructed or found. A Births instance records |
66 // instance was created. That Births instance records (in a base class | 66 // (in a base class BirthOnThread) references to the static data provided in a |
67 // BirthOnThread) references to the static data provided in a Location instance, | 67 // Location instance, as well as a pointer to the ThreadData bound to the thread |
68 // as well as a pointer specifying the thread on which the birth takes place. | 68 // on which the birth takes place (see discussion on ThreadData below). There is |
69 // Hence there is at most one Births instance for each Location on each thread. | 69 // at most one Births instance for each Location / ThreadData pair. The derived |
70 // The derived Births class contains slots for recording statistics about all | 70 // Births class contains slots for recording statistics about all instances born |
71 // instances born at the same location. Statistics currently include only the | 71 // at the same location. Statistics currently include only the count of |
72 // count of instances constructed. | 72 // instances constructed. |
73 // | 73 // |
74 // Since the base class BirthOnThread contains only constant data, it can be | 74 // Since the base class BirthOnThread contains only constant data, it can be |
75 // freely accessed by any thread at any time (i.e., only the statistic needs to | 75 // freely accessed by any thread at any time. The statistics must be handled |
76 // be handled carefully, and stats are updated exclusively on the birth thread). | 76 // more carefully; they are updated exclusively by the single thread to which |
| 77 // the ThreadData is bound at a given time. |
77 // | 78 // |
78 // For Tasks, having now either constructed or found the Births instance | 79 // For Tasks, having now either constructed or found the Births instance |
79 // described above, a pointer to the Births instance is then recorded into the | 80 // described above, a pointer to the Births instance is then recorded into the |
80 // PendingTask structure in MessageLoop. This fact alone is very useful in | 81 // PendingTask structure. This fact alone is very useful in debugging, when |
81 // debugging, when there is a question of where an instance came from. In | 82 // there is a question of where an instance came from. In addition, the birth |
82 // addition, the birth time is also recorded and used to later evaluate the | 83 // time is also recorded and used to later evaluate the lifetime duration of the |
83 // lifetime duration of the whole Task. As a result of the above embedding, we | 84 // whole Task. As a result of the above embedding, we can find out a Task's |
84 // can find out a Task's location of birth, and thread of birth, without using | 85 // location of birth, and name of birth thread, without using any locks, as all |
85 // any locks, as all that data is constant across the life of the process. | 86 // that data is constant across the life of the process. |
86 // | 87 // |
87 // The above work *could* also be done for any other object as well by calling | 88 // The above work *could* also be done for any other object as well by calling |
88 // TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate. | 89 // TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate. |
89 // | 90 // |
90 // The amount of memory used in the above data structures depends on how many | 91 // The upper bound for the amount of memory used in the above data structures is |
91 // threads there are, and how many Locations of construction there are. | 92 // the product of the number of ThreadData instances and the number of |
92 // Fortunately, we don't use memory that is the product of those two counts, but | 93 // Locations. Fortunately, Locations are often created on a single thread and |
93 // rather we only need one Births instance for each thread that constructs an | 94 // the memory utilization is actually fairly restrained. |
94 // instance at a Location. In many cases, instances are only created on one | |
95 // thread, so the memory utilization is actually fairly restrained. | |
96 // | 95 // |
97 // Lastly, when an instance is deleted, the final tallies of statistics are | 96 // Lastly, when an instance is deleted, the final tallies of statistics are |
98 // carefully accumulated. That tallying writes into slots (members) in a | 97 // carefully accumulated. That tallying writes into slots (members) in a |
99 // collection of DeathData instances. For each birth place Location that is | 98 // collection of DeathData instances. For each Births / death ThreadData pair, |
100 // destroyed on a thread, there is a DeathData instance to record the additional | 99 // there is a DeathData instance to record the additional death count, as well |
101 // death count, as well as accumulate the run-time and queue-time durations for | 100 // as to accumulate the run-time and queue-time durations for the instance as it |
102 // the instance as it is destroyed (dies). By maintaining a single place to | 101 // is destroyed (dies). Since a ThreadData is bound to at most one thread at a |
103 // aggregate this running sum *only* for the given thread, we avoid the need to | 102 // time, there is no need to lock such DeathData instances. (i.e., these |
104 // lock such DeathData instances. (i.e., these accumulated stats in a DeathData | 103 // accumulated stats in a DeathData instance are exclusively updated by the |
105 // instance are exclusively updated by the singular owning thread). | 104 // singular owning thread). |
106 // | 105 // |
107 // With the above life cycle description complete, the major remaining detail | 106 // With the above life cycle description complete, the major remaining detail is |
108 // is explaining how each thread maintains a list of DeathData instances, and | 107 // explaining how existing Births and DeathData instances are found to avoid |
109 // of Births instances, and is able to avoid additional (redundant/unnecessary) | 108 // redundant allocations. |
110 // allocations. | |
111 // | 109 // |
112 // Each thread maintains a list of data items specific to that thread in a | 110 // A ThreadData instance maintains maps of Births and DeathData instances. The |
113 // ThreadData instance (for that specific thread only). The two critical items | 111 // Births map is indexed by Location and the DeathData map is indexed by |
114 // are lists of DeathData and Births instances. These lists are maintained in | 112 // Births*. As noted earlier, we can compare Locations very efficiently as we |
115 // STL maps, which are indexed by Location. As noted earlier, we can compare | 113 // consider the underlying data (file, function, line) to be atoms, and hence |
116 // locations very efficiently as we consider the underlying data (file, | 114 // pointer comparison is used rather than (slow) string comparisons. |
117 // function, line) to be atoms, and hence pointer comparison is used rather than | |
118 // (slow) string comparisons. | |
119 // | 115 // |
120 // To provide a mechanism for iterating over all "known threads," which means | 116 // The first time that a thread calls ThreadData::InitializeThreadContext() or |
121 // threads that have recorded a birth or a death, we create a singly linked list | 117 // ThreadData::Get(), a ThreadData instance is bound to it and stored in TLS. If |
122 // of ThreadData instances. Each such instance maintains a pointer to the next | 118 // a ThreadData bound to a terminated thread with the same sanitized name (i.e. |
123 // one. A static member of ThreadData provides a pointer to the first item on | 119 // name without trailing digits) as the current thread is available, it is |
124 // this global list, and access via that all_thread_data_list_head_ item | 120 // reused. Otherwise, a new ThreadData instance is instantiated. Since a |
125 // requires the use of the list_lock_. | 121 // ThreadData is bound to at most one thread at a time, there is no need to |
126 // When new ThreadData instances is added to the global list, it is pre-pended, | 122 // acquire a lock to access its maps. Over time, a ThreadData may be bound to |
127 // which ensures that any prior acquisition of the list is valid (i.e., the | 123 // different threads that share the same sanitized name. |
128 // holder can iterate over it without fear of it changing, or the necessity of | 124 // |
129 // using an additional lock. Iterations are actually pretty rare (used | 125 // We maintain a list of all ThreadData instances for the current process. Each |
| 126 // ThreadData instance has a pointer to the next one. A static member of |
| 127 // ThreadData provides a pointer to the first item on this global list, and |
| 128 // access via that all_thread_data_list_head_ item requires the use of the |
| 129 // list_lock_. |
| 130 // |
| 131 // When new ThreadData instances are added to the global list, they are pre- |
| 132 // pended, which ensures that any prior acquisition of the list is valid (i.e., |
| 133 // the holder can iterate over it without fear of it changing, or the necessity |
| 134 // of using an additional lock. Iterations are actually pretty rare (used |
130 // primarily for cleanup, or snapshotting data for display), so this lock has | 135 // primarily for cleanup, or snapshotting data for display), so this lock has |
131 // very little global performance impact. | 136 // very little global performance impact. |
132 // | 137 // |
133 // The above description tries to define the high performance (run time) | 138 // The above description tries to define the high performance (run time) |
134 // portions of these classes. After gathering statistics, calls instigated | 139 // portions of these classes. After gathering statistics, calls instigated |
135 // by visiting about:profiler will assemble and aggregate data for display. The | 140 // by visiting about:profiler will assemble and aggregate data for display. The |
136 // following data structures are used for producing such displays. They are | 141 // following data structures are used for producing such displays. They are |
137 // not performance critical, and their only major constraint is that they should | 142 // not performance critical, and their only major constraint is that they should |
138 // be able to run concurrently with ongoing augmentation of the birth and death | 143 // be able to run concurrently with ongoing augmentation of the birth and death |
139 // data. | 144 // data. |
(...skipping 26 matching lines...) Expand all Loading... |
166 // atomically collecting all data, so we could have count that does not, for | 171 // atomically collecting all data, so we could have count that does not, for |
167 // example, match with the number of durations we accumulated). The advantage | 172 // example, match with the number of durations we accumulated). The advantage |
168 // to having fast (non-atomic) updates of the data outweighs the minimal risk of | 173 // to having fast (non-atomic) updates of the data outweighs the minimal risk of |
169 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, | 174 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, |
170 // not the underlying and ongoing statistic). In contrast, pointer data that | 175 // not the underlying and ongoing statistic). In contrast, pointer data that |
171 // is accessed during snapshotting is completely invariant, and hence is | 176 // is accessed during snapshotting is completely invariant, and hence is |
172 // perfectly acquired (i.e., no potential corruption, and no risk of a bad | 177 // perfectly acquired (i.e., no potential corruption, and no risk of a bad |
173 // memory reference). | 178 // memory reference). |
174 // | 179 // |
175 // TODO(jar): We can implement a Snapshot system that *tries* to grab the | 180 // TODO(jar): We can implement a Snapshot system that *tries* to grab the |
176 // snapshots on the source threads *when* they have MessageLoops available | 181 // snapshots on the source threads *when* they have SingleThreadTaskRunners |
177 // (worker threads don't have message loops generally, and hence gathering from | 182 // available (worker threads don't have SingleThreadTaskRunners, and hence |
178 // them will continue to be asynchronous). We had an implementation of this in | 183 // gathering from them will continue to be asynchronous). We had an |
179 // the past, but the difficulty is dealing with message loops being terminated. | 184 // implementation of this in the past, but the difficulty is dealing with |
180 // We can *try* to spam the available threads via some task runner to | 185 // threads being terminated. We can *try* to post a task to threads that have a |
181 // achieve this feat, and it *might* be valuable when we are collecting data | 186 // SingleThreadTaskRunner and check if that succeeds (will fail if the thread |
| 187 // has been terminated). This *might* be valuable when we are collecting data |
182 // for upload via UMA (where correctness of data may be more significant than | 188 // for upload via UMA (where correctness of data may be more significant than |
183 // for a single screen of about:profiler). | 189 // for a single screen of about:profiler). |
184 // | 190 // |
185 // TODO(jar): We need to store DataCollections, and provide facilities for | 191 // TODO(jar): We need to store DataCollections, and provide facilities for |
186 // taking the difference between two gathered DataCollections. For now, we're | 192 // taking the difference between two gathered DataCollections. For now, we're |
187 // just adding a hack that Reset()s to zero all counts and stats. This is also | 193 // just adding a hack that Reset()s to zero all counts and stats. This is also |
188 // done in a slightly thread-unsafe fashion, as the resetting is done | 194 // done in a slightly thread-unsafe fashion, as the resetting is done |
189 // asynchronously relative to ongoing updates (but all data is 32 bit in size). | 195 // asynchronously relative to ongoing updates (but all data is 32 bit in size). |
190 // For basic profiling, this will work "most of the time," and should be | 196 // For basic profiling, this will work "most of the time," and should be |
191 // sufficient... but storing away DataCollections is the "right way" to do this. | 197 // sufficient... but storing away DataCollections is the "right way" to do this. |
(...skipping 30 matching lines...) Expand all Loading... |
222 | 228 |
223 //------------------------------------------------------------------------------ | 229 //------------------------------------------------------------------------------ |
224 // A "snapshotted" representation of the BirthOnThread class. | 230 // A "snapshotted" representation of the BirthOnThread class. |
225 | 231 |
226 struct BASE_EXPORT BirthOnThreadSnapshot { | 232 struct BASE_EXPORT BirthOnThreadSnapshot { |
227 BirthOnThreadSnapshot(); | 233 BirthOnThreadSnapshot(); |
228 explicit BirthOnThreadSnapshot(const BirthOnThread& birth); | 234 explicit BirthOnThreadSnapshot(const BirthOnThread& birth); |
229 ~BirthOnThreadSnapshot(); | 235 ~BirthOnThreadSnapshot(); |
230 | 236 |
231 LocationSnapshot location; | 237 LocationSnapshot location; |
232 std::string thread_name; | 238 std::string sanitized_thread_name; |
233 }; | 239 }; |
234 | 240 |
235 //------------------------------------------------------------------------------ | 241 //------------------------------------------------------------------------------ |
236 // A class for accumulating counts of births (without bothering with a map<>). | 242 // A class for accumulating counts of births (without bothering with a map<>). |
237 | 243 |
238 class BASE_EXPORT Births: public BirthOnThread { | 244 class BASE_EXPORT Births: public BirthOnThread { |
239 public: | 245 public: |
240 Births(const Location& location, const ThreadData& current); | 246 Births(const Location& location, const ThreadData& current); |
241 | 247 |
242 int birth_count() const; | 248 int birth_count() const; |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 // A temporary collection of data that can be sorted and summarized. It is | 477 // A temporary collection of data that can be sorted and summarized. It is |
472 // gathered (carefully) from many threads. Instances are held in arrays and | 478 // gathered (carefully) from many threads. Instances are held in arrays and |
473 // processed, filtered, and rendered. | 479 // processed, filtered, and rendered. |
474 // The source of this data was collected on many threads, and is asynchronously | 480 // The source of this data was collected on many threads, and is asynchronously |
475 // changing. The data in this instance is not asynchronously changing. | 481 // changing. The data in this instance is not asynchronously changing. |
476 | 482 |
477 struct BASE_EXPORT TaskSnapshot { | 483 struct BASE_EXPORT TaskSnapshot { |
478 TaskSnapshot(); | 484 TaskSnapshot(); |
479 TaskSnapshot(const BirthOnThreadSnapshot& birth, | 485 TaskSnapshot(const BirthOnThreadSnapshot& birth, |
480 const DeathDataSnapshot& death_data, | 486 const DeathDataSnapshot& death_data, |
481 const std::string& death_thread_name); | 487 const std::string& death_sanitized_thread_name); |
482 ~TaskSnapshot(); | 488 ~TaskSnapshot(); |
483 | 489 |
484 BirthOnThreadSnapshot birth; | 490 BirthOnThreadSnapshot birth; |
485 // Delta between death data for a thread for a certain profiling phase and the | 491 // Delta between death data for a thread for a certain profiling phase and the |
486 // snapshot for the pervious phase, if any. Otherwise, just a snapshot. | 492 // snapshot for the pervious phase, if any. Otherwise, just a snapshot. |
487 DeathDataSnapshot death_data; | 493 DeathDataSnapshot death_data; |
488 std::string death_thread_name; | 494 std::string death_sanitized_thread_name; |
489 }; | 495 }; |
490 | 496 |
491 //------------------------------------------------------------------------------ | 497 //------------------------------------------------------------------------------ |
492 // For each thread, we have a ThreadData that stores all tracking info generated | 498 // For each thread, we have a ThreadData that stores all tracking info generated |
493 // on this thread. This prevents the need for locking as data accumulates. | 499 // on this thread. This prevents the need for locking as data accumulates. |
494 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. | 500 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. |
495 // We also have a linked list of ThreadData instances, and that list is used to | 501 // We also have a linked list of ThreadData instances, and that list is used to |
496 // harvest data from all existing instances. | 502 // harvest data from all existing instances. |
497 | 503 |
498 struct ProcessDataPhaseSnapshot; | 504 struct ProcessDataPhaseSnapshot; |
(...skipping 15 matching lines...) Expand all Loading... |
514 DEACTIVATED, // No longer recording profiling. | 520 DEACTIVATED, // No longer recording profiling. |
515 PROFILING_ACTIVE, // Recording profiles. | 521 PROFILING_ACTIVE, // Recording profiles. |
516 STATUS_LAST = PROFILING_ACTIVE | 522 STATUS_LAST = PROFILING_ACTIVE |
517 }; | 523 }; |
518 | 524 |
519 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; | 525 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; |
520 typedef std::map<const Births*, DeathData> DeathMap; | 526 typedef std::map<const Births*, DeathData> DeathMap; |
521 | 527 |
522 // Initialize the current thread context with a new instance of ThreadData. | 528 // Initialize the current thread context with a new instance of ThreadData. |
523 // This is used by all threads that have names, and should be explicitly | 529 // This is used by all threads that have names, and should be explicitly |
524 // set *before* any births on the threads have taken place. It is generally | 530 // set *before* any births on the threads have taken place. |
525 // only used by the message loop, which has a well defined thread name. | 531 static void InitializeThreadContext(const std::string& thread_name); |
526 static void InitializeThreadContext(const std::string& suggested_name); | |
527 | 532 |
528 // Using Thread Local Store, find the current instance for collecting data. | 533 // Using Thread Local Store, find the current instance for collecting data. |
529 // If an instance does not exist, construct one (and remember it for use on | 534 // If an instance does not exist, construct one (and remember it for use on |
530 // this thread. | 535 // this thread. |
531 // This may return NULL if the system is disabled for any reason. | 536 // This may return NULL if the system is disabled for any reason. |
532 static ThreadData* Get(); | 537 static ThreadData* Get(); |
533 | 538 |
534 // Fills |process_data_snapshot| with phased snapshots of all profiling | 539 // Fills |process_data_snapshot| with phased snapshots of all profiling |
535 // phases, including the current one, identified by |current_profiling_phase|. | 540 // phases, including the current one, identified by |current_profiling_phase|. |
536 // |current_profiling_phase| is necessary because a child process can start | 541 // |current_profiling_phase| is necessary because a child process can start |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 // finished). | 579 // finished). |
575 static void TallyRunOnWorkerThreadIfTracking(const Births* births, | 580 static void TallyRunOnWorkerThreadIfTracking(const Births* births, |
576 const TrackedTime& time_posted, | 581 const TrackedTime& time_posted, |
577 const TaskStopwatch& stopwatch); | 582 const TaskStopwatch& stopwatch); |
578 | 583 |
579 // Record the end of execution in region, generally corresponding to a scope | 584 // Record the end of execution in region, generally corresponding to a scope |
580 // being exited. | 585 // being exited. |
581 static void TallyRunInAScopedRegionIfTracking(const Births* births, | 586 static void TallyRunInAScopedRegionIfTracking(const Births* births, |
582 const TaskStopwatch& stopwatch); | 587 const TaskStopwatch& stopwatch); |
583 | 588 |
584 const std::string& thread_name() const { return thread_name_; } | 589 const std::string& sanitized_thread_name() const { |
| 590 return sanitized_thread_name_; |
| 591 } |
585 | 592 |
586 // Initializes all statics if needed (this initialization call should be made | 593 // Initializes all statics if needed (this initialization call should be made |
587 // while we are single threaded). | 594 // while we are single threaded). |
588 static void EnsureTlsInitialization(); | 595 static void EnsureTlsInitialization(); |
589 | 596 |
590 // Sets internal status_. | 597 // Sets internal status_. |
591 // If |status| is false, then status_ is set to DEACTIVATED. | 598 // If |status| is false, then status_ is set to DEACTIVATED. |
592 // If |status| is true, then status_ is set to PROFILING_ACTIVE. | 599 // If |status| is true, then status_ is set to PROFILING_ACTIVE. |
593 static void InitializeAndSetTrackingStatus(Status status); | 600 static void InitializeAndSetTrackingStatus(Status status); |
594 | 601 |
(...skipping 28 matching lines...) Expand all Loading... |
623 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); | 630 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); |
624 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); | 631 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
625 | 632 |
626 // Type for an alternate timer function (testing only). | 633 // Type for an alternate timer function (testing only). |
627 typedef unsigned int NowFunction(); | 634 typedef unsigned int NowFunction(); |
628 | 635 |
629 typedef std::map<const BirthOnThread*, int> BirthCountMap; | 636 typedef std::map<const BirthOnThread*, int> BirthCountMap; |
630 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> | 637 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> |
631 DeathsSnapshot; | 638 DeathsSnapshot; |
632 | 639 |
633 // Worker thread construction creates a name since there is none. | 640 explicit ThreadData(const std::string& sanitized_thread_name); |
634 explicit ThreadData(int thread_number); | |
635 | |
636 // Message loop based construction should provide a name. | |
637 explicit ThreadData(const std::string& suggested_name); | |
638 | |
639 ~ThreadData(); | 641 ~ThreadData(); |
640 | 642 |
641 // Push this instance to the head of all_thread_data_list_head_, linking it to | 643 // Push this instance to the head of all_thread_data_list_head_, linking it to |
642 // the previous head. This is performed after each construction, and leaves | 644 // the previous head. This is performed after each construction, and leaves |
643 // the instance permanently on that list. | 645 // the instance permanently on that list. |
644 void PushToHeadOfList(); | 646 void PushToHeadOfList(); |
645 | 647 |
646 // (Thread safe) Get start of list of all ThreadData instances using the lock. | 648 // (Thread safe) Get start of list of all ThreadData instances using the lock. |
647 static ThreadData* first(); | 649 static ThreadData* first(); |
648 | 650 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 // uninitialized) state. If there is any chance that other threads are still | 694 // uninitialized) state. If there is any chance that other threads are still |
693 // using the data structures, then the |leak| argument should be passed in as | 695 // using the data structures, then the |leak| argument should be passed in as |
694 // true, and the data structures (birth maps, death maps, ThreadData | 696 // true, and the data structures (birth maps, death maps, ThreadData |
695 // insntances, etc.) will be leaked and not deleted. If you have joined all | 697 // insntances, etc.) will be leaked and not deleted. If you have joined all |
696 // threads since the time that InitializeAndSetTrackingStatus() was called, | 698 // threads since the time that InitializeAndSetTrackingStatus() was called, |
697 // then you can pass in a |leak| value of false, and this function will | 699 // then you can pass in a |leak| value of false, and this function will |
698 // delete recursively all data structures, starting with the list of | 700 // delete recursively all data structures, starting with the list of |
699 // ThreadData instances. | 701 // ThreadData instances. |
700 static void ShutdownSingleThreadedCleanup(bool leak); | 702 static void ShutdownSingleThreadedCleanup(bool leak); |
701 | 703 |
| 704 // Returns a ThreadData instance for a thread whose sanitized name is |
| 705 // |sanitized_thread_name|. The returned instance may have been extracted from |
| 706 // the list of retired ThreadData instances or newly allocated. |
| 707 static ThreadData* GetRetiredOrCreateThreadData( |
| 708 const std::string& sanitized_thread_name); |
| 709 |
702 // When non-null, this specifies an external function that supplies monotone | 710 // When non-null, this specifies an external function that supplies monotone |
703 // increasing time functcion. | 711 // increasing time functcion. |
704 static NowFunction* now_function_for_testing_; | 712 static NowFunction* now_function_for_testing_; |
705 | 713 |
706 // We use thread local store to identify which ThreadData to interact with. | 714 // We use thread local store to identify which ThreadData to interact with. |
707 static base::ThreadLocalStorage::StaticSlot tls_index_; | 715 static base::ThreadLocalStorage::StaticSlot tls_index_; |
708 | 716 |
709 // List of ThreadData instances for use with worker threads. When a worker | 717 // Linked list of ThreadData instances that were associated with threads that |
710 // thread is done (terminated), we push it onto this list. When a new worker | 718 // have been terminated and that have not been associated with a new thread |
711 // thread is created, we first try to re-use a ThreadData instance from the | 719 // since then. This is only accessed while |list_lock_| is held. |
712 // list, and if none are available, construct a new one. | 720 static ThreadData* first_retired_thread_data_; |
713 // This is only accessed while list_lock_ is held. | |
714 static ThreadData* first_retired_worker_; | |
715 | 721 |
716 // Link to the most recently created instance (starts a null terminated list). | 722 // Link to the most recently created instance (starts a null terminated list). |
717 // The list is traversed by about:profiler when it needs to snapshot data. | 723 // The list is traversed by about:profiler when it needs to snapshot data. |
718 // This is only accessed while list_lock_ is held. | 724 // This is only accessed while list_lock_ is held. |
719 static ThreadData* all_thread_data_list_head_; | 725 static ThreadData* all_thread_data_list_head_; |
720 | 726 |
721 // The next available worker thread number. This should only be accessed when | |
722 // the list_lock_ is held. | |
723 static int worker_thread_data_creation_count_; | |
724 | |
725 // The number of times TLS has called us back to cleanup a ThreadData | 727 // The number of times TLS has called us back to cleanup a ThreadData |
726 // instance. This is only accessed while list_lock_ is held. | 728 // instance. This is only accessed while list_lock_ is held. |
727 static int cleanup_count_; | 729 static int cleanup_count_; |
728 | 730 |
729 // Incarnation sequence number, indicating how many times (during unittests) | 731 // Incarnation sequence number, indicating how many times (during unittests) |
730 // we've either transitioned out of UNINITIALIZED, or into that state. This | 732 // we've either transitioned out of UNINITIALIZED, or into that state. This |
731 // value is only accessed while the list_lock_ is held. | 733 // value is only accessed while the list_lock_ is held. |
732 static int incarnation_counter_; | 734 static int incarnation_counter_; |
733 | 735 |
734 // Protection for access to all_thread_data_list_head_, and to | 736 // Protection for access to all_thread_data_list_head_, and to |
735 // unregistered_thread_data_pool_. This lock is leaked at shutdown. | 737 // unregistered_thread_data_pool_. This lock is leaked at shutdown. |
736 // The lock is very infrequently used, so we can afford to just make a lazy | 738 // The lock is very infrequently used, so we can afford to just make a lazy |
737 // instance and be safe. | 739 // instance and be safe. |
738 static base::LazyInstance<base::Lock>::Leaky list_lock_; | 740 static base::LazyInstance<base::Lock>::Leaky list_lock_; |
739 | 741 |
740 // We set status_ to SHUTDOWN when we shut down the tracking service. | 742 // We set status_ to SHUTDOWN when we shut down the tracking service. |
741 static base::subtle::Atomic32 status_; | 743 static base::subtle::Atomic32 status_; |
742 | 744 |
743 // Link to next instance (null terminated list). Used to globally track all | 745 // Link to next instance (null terminated list). Used to globally track all |
744 // registered instances (corresponds to all registered threads where we keep | 746 // registered instances (corresponds to all registered threads where we keep |
745 // data). | 747 // data). Only modified in the constructor. |
746 ThreadData* next_; | 748 ThreadData* next_; |
747 | 749 |
748 // Pointer to another ThreadData instance for a Worker-Thread that has been | 750 // Pointer to another retired ThreadData instance. This value is nullptr if |
749 // retired (its thread was terminated). This value is non-NULL only for a | 751 // this is associated with an active thread. |
750 // retired ThreadData associated with a Worker-Thread. | 752 ThreadData* next_retired_thread_data_; |
751 ThreadData* next_retired_worker_; | |
752 | 753 |
753 // The name of the thread that is being recorded. If this thread has no | 754 // The name of the thread that is being recorded, with all trailing digits |
754 // message_loop, then this is a worker thread, with a sequence number postfix. | 755 // replaced with a single "*" character. |
755 std::string thread_name_; | 756 const std::string sanitized_thread_name_; |
756 | |
757 // Indicate if this is a worker thread, and the ThreadData contexts should be | |
758 // stored in the unregistered_thread_data_pool_ when not in use. | |
759 // Value is zero when it is not a worker thread. Value is a positive integer | |
760 // corresponding to the created thread name if it is a worker thread. | |
761 int worker_thread_number_; | |
762 | 757 |
763 // A map used on each thread to keep track of Births on this thread. | 758 // A map used on each thread to keep track of Births on this thread. |
764 // This map should only be accessed on the thread it was constructed on. | 759 // This map should only be accessed on the thread it was constructed on. |
765 // When a snapshot is needed, this structure can be locked in place for the | 760 // When a snapshot is needed, this structure can be locked in place for the |
766 // duration of the snapshotting activity. | 761 // duration of the snapshotting activity. |
767 BirthMap birth_map_; | 762 BirthMap birth_map_; |
768 | 763 |
769 // Similar to birth_map_, this records informations about death of tracked | 764 // Similar to birth_map_, this records informations about death of tracked |
770 // instances (i.e., when a tracked instance was destroyed on this thread). | 765 // instances (i.e., when a tracked instance was destroyed on this thread). |
771 // It is locked before changing, and hence other threads may access it by | 766 // It is locked before changing, and hence other threads may access it by |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
894 ProcessDataSnapshot(const ProcessDataSnapshot& other); | 889 ProcessDataSnapshot(const ProcessDataSnapshot& other); |
895 ~ProcessDataSnapshot(); | 890 ~ProcessDataSnapshot(); |
896 | 891 |
897 PhasedProcessDataSnapshotMap phased_snapshots; | 892 PhasedProcessDataSnapshotMap phased_snapshots; |
898 base::ProcessId process_id; | 893 base::ProcessId process_id; |
899 }; | 894 }; |
900 | 895 |
901 } // namespace tracked_objects | 896 } // namespace tracked_objects |
902 | 897 |
903 #endif // BASE_TRACKED_OBJECTS_H_ | 898 #endif // BASE_TRACKED_OBJECTS_H_ |
OLD | NEW |