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> |
11 #include <string> | 11 #include <string> |
12 #include <utility> | 12 #include <utility> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
15 #include "base/base_export.h" | 15 #include "base/base_export.h" |
16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
17 #include "base/containers/hash_tables.h" | 17 #include "base/containers/hash_tables.h" |
18 #include "base/gtest_prod_util.h" | 18 #include "base/gtest_prod_util.h" |
19 #include "base/lazy_instance.h" | 19 #include "base/lazy_instance.h" |
20 #include "base/location.h" | 20 #include "base/location.h" |
21 #include "base/process/process_handle.h" | 21 #include "base/process/process_handle.h" |
22 #include "base/profiler/alternate_timer.h" | 22 #include "base/profiler/alternate_timer.h" |
23 #include "base/profiler/tracked_time.h" | 23 #include "base/profiler/tracked_time.h" |
24 #include "base/synchronization/lock.h" | 24 #include "base/synchronization/lock.h" |
| 25 #include "base/threading/thread_checker.h" |
25 #include "base/threading/thread_local_storage.h" | 26 #include "base/threading/thread_local_storage.h" |
26 | 27 |
27 namespace base { | 28 namespace base { |
28 struct TrackingInfo; | 29 struct TrackingInfo; |
29 } | 30 } |
30 | 31 |
31 // TrackedObjects provides a database of stats about objects (generally Tasks) | 32 // TrackedObjects provides a database of stats about objects (generally Tasks) |
32 // that are tracked. Tracking means their birth, death, duration, birth thread, | 33 // that are tracked. Tracking means their birth, death, duration, birth thread, |
33 // death thread, and birth place are recorded. This data is carefully spread | 34 // death thread, and birth place are recorded. This data is carefully spread |
34 // across a series of objects so that the counts and times can be rapidly | 35 // across a series of objects so that the counts and times can be rapidly |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 // can find out a Task's location of birth, and thread of birth, without using | 79 // can find out a Task's location of birth, and thread of birth, without using |
79 // any locks, as all that data is constant across the life of the process. | 80 // any locks, as all that data is constant across the life of the process. |
80 // | 81 // |
81 // The above work *could* also be done for any other object as well by calling | 82 // The above work *could* also be done for any other object as well by calling |
82 // TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate. | 83 // TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate. |
83 // | 84 // |
84 // The amount of memory used in the above data structures depends on how many | 85 // The amount of memory used in the above data structures depends on how many |
85 // threads there are, and how many Locations of construction there are. | 86 // threads there are, and how many Locations of construction there are. |
86 // Fortunately, we don't use memory that is the product of those two counts, but | 87 // Fortunately, we don't use memory that is the product of those two counts, but |
87 // rather we only need one Births instance for each thread that constructs an | 88 // rather we only need one Births instance for each thread that constructs an |
88 // instance at a Location. In many cases, instances are only created on one | 89 // instance at a Location. In many cases, instances are only created on one |
89 // thread, so the memory utilization is actually fairly restrained. | 90 // thread, so the memory utilization is actually fairly restrained. |
90 // | 91 // |
91 // Lastly, when an instance is deleted, the final tallies of statistics are | 92 // Lastly, when an instance is deleted, the final tallies of statistics are |
92 // carefully accumulated. That tallying writes into slots (members) in a | 93 // carefully accumulated. That tallying writes into slots (members) in a |
93 // collection of DeathData instances. For each birth place Location that is | 94 // collection of DeathData instances. For each birth place Location that is |
94 // destroyed on a thread, there is a DeathData instance to record the additional | 95 // destroyed on a thread, there is a DeathData instance to record the additional |
95 // death count, as well as accumulate the run-time and queue-time durations for | 96 // death count, as well as accumulate the run-time and queue-time durations for |
96 // the instance as it is destroyed (dies). By maintaining a single place to | 97 // the instance as it is destroyed (dies). By maintaining a single place to |
97 // aggregate this running sum *only* for the given thread, we avoid the need to | 98 // aggregate this running sum *only* for the given thread, we avoid the need to |
98 // lock such DeathData instances. (i.e., these accumulated stats in a DeathData | 99 // lock such DeathData instances. (i.e., these accumulated stats in a DeathData |
99 // instance are exclusively updated by the singular owning thread). | 100 // instance are exclusively updated by the singular owning thread). |
100 // | 101 // |
101 // With the above life cycle description complete, the major remaining detail | 102 // With the above life cycle description complete, the major remaining detail |
102 // is explaining how each thread maintains a list of DeathData instances, and | 103 // is explaining how each thread maintains a list of DeathData instances, and |
103 // of Births instances, and is able to avoid additional (redundant/unnecessary) | 104 // of Births instances, and is able to avoid additional (redundant/unnecessary) |
104 // allocations. | 105 // allocations. |
105 // | 106 // |
106 // Each thread maintains a list of data items specific to that thread in a | 107 // Each thread maintains a list of data items specific to that thread in a |
107 // ThreadData instance (for that specific thread only). The two critical items | 108 // ThreadData instance (for that specific thread only). The two critical items |
108 // are lists of DeathData and Births instances. These lists are maintained in | 109 // are lists of DeathData and Births instances. These lists are maintained in |
109 // STL maps, which are indexed by Location. As noted earlier, we can compare | 110 // STL maps, which are indexed by Location. As noted earlier, we can compare |
110 // locations very efficiently as we consider the underlying data (file, | 111 // locations very efficiently as we consider the underlying data (file, |
111 // function, line) to be atoms, and hence pointer comparison is used rather than | 112 // function, line) to be atoms, and hence pointer comparison is used rather than |
112 // (slow) string comparisons. | 113 // (slow) string comparisons. |
113 // | 114 // |
114 // To provide a mechanism for iterating over all "known threads," which means | 115 // To provide a mechanism for iterating over all "known threads," which means |
115 // threads that have recorded a birth or a death, we create a singly linked list | 116 // threads that have recorded a birth or a death, we create a singly linked list |
116 // of ThreadData instances. Each such instance maintains a pointer to the next | 117 // of ThreadData instances. Each such instance maintains a pointer to the next |
117 // one. A static member of ThreadData provides a pointer to the first item on | 118 // one. A static member of ThreadData provides a pointer to the first item on |
118 // this global list, and access via that all_thread_data_list_head_ item | 119 // this global list, and access via that all_thread_data_list_head_ item |
119 // requires the use of the list_lock_. | 120 // requires the use of the list_lock_. |
120 // When new ThreadData instances is added to the global list, it is pre-pended, | 121 // When new ThreadData instances is added to the global list, it is pre-pended, |
121 // which ensures that any prior acquisition of the list is valid (i.e., the | 122 // which ensures that any prior acquisition of the list is valid (i.e., the |
122 // holder can iterate over it without fear of it changing, or the necessity of | 123 // holder can iterate over it without fear of it changing, or the necessity of |
123 // using an additional lock. Iterations are actually pretty rare (used | 124 // using an additional lock. Iterations are actually pretty rare (used |
124 // primarily for cleanup, or snapshotting data for display), so this lock has | 125 // primarily for cleanup, or snapshotting data for display), so this lock has |
125 // very little global performance impact. | 126 // very little global performance impact. |
126 // | 127 // |
(...skipping 14 matching lines...) Expand all Loading... |
141 // (3) the snapshotted data. | 142 // (3) the snapshotted data. |
142 // | 143 // |
143 // For a given birth location, information about births is spread across data | 144 // For a given birth location, information about births is spread across data |
144 // structures that are asynchronously changing on various threads. For | 145 // structures that are asynchronously changing on various threads. For |
145 // serialization and display purposes, we need to construct TaskSnapshot | 146 // serialization and display purposes, we need to construct TaskSnapshot |
146 // instances for each combination of birth thread, death thread, and location, | 147 // instances for each combination of birth thread, death thread, and location, |
147 // 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 |
148 // TaskSnapshot instances, so that such instances can be sorted and | 149 // TaskSnapshot instances, so that such instances can be sorted and |
149 // aggregated (and remain frozen during our processing). | 150 // aggregated (and remain frozen during our processing). |
150 // | 151 // |
151 // Profiling consists of phases. The concrete phase in the sequence of phases is | 152 // Profiling consists of phases. The concrete phase in the sequence of phases |
152 // identified by its 0-based index. | 153 // is identified by its 0-based index. |
153 // | 154 // |
154 // The ProcessDataPhaseSnapshot struct is a serialized representation of the | 155 // The ProcessDataPhaseSnapshot struct is a serialized representation of the |
155 // 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 |
156 // 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 |
157 // executed tasks. The statistics in a snapshot are gathered asynhcronously | 158 // asynhcronously relative to their ongoing updates. |
158 // relative to their ongoing updates. | |
159 // It is possible, though highly unlikely, that stats could be incorrectly | 159 // It is possible, though highly unlikely, that stats could be incorrectly |
160 // 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 |
161 // 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 |
162 // example, match with the number of durations we accumulated). The advantage | 162 // example, match with the number of durations we accumulated). The advantage |
163 // 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 |
164 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, | 164 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, |
165 // not the underlying and ongoing statistic). In contrast, pointer data that | 165 // not the underlying and ongoing statistic). In contrast, pointer data that |
166 // is accessed during snapshotting is completely invariant, and hence is | 166 // is accessed during snapshotting is completely invariant, and hence is |
167 // 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 |
168 // memory reference). | 168 // memory reference). |
169 // | 169 // |
170 // 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 |
171 // snapshots on the source threads *when* they have MessageLoops available | 171 // snapshots on the source threads *when* they have MessageLoops available |
172 // (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 |
173 // 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 |
174 // 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. |
175 // 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 |
176 // 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 |
177 // 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 |
178 // for a single screen of about:profiler). | 178 // for a single screen of about:profiler). |
179 // | 179 // |
180 // TODO(jar): We should support (optionally) the recording of parent-child | |
181 // relationships for tasks. This should be done by detecting what tasks are | |
182 // Born during the running of a parent task. The resulting data can be used by | |
183 // a smarter profiler to aggregate the cost of a series of child tasks into | |
184 // the ancestor task. It can also be used to illuminate what child or parent is | |
185 // related to each task. | |
186 // | |
187 // TODO(jar): We need to store DataCollections, and provide facilities for | 180 // TODO(jar): We need to store DataCollections, and provide facilities for |
188 // taking the difference between two gathered DataCollections. For now, we're | 181 // taking the difference between two gathered DataCollections. For now, we're |
189 // 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 |
190 // 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 |
191 // 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). |
192 // 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 |
193 // 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. |
194 // 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 |
195 // 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 |
196 // DeathData that is reset (as synchronously as possible) during each snapshot. | 189 // DeathData that is reset (as synchronously as possible) during each snapshot. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 void RecordBirth(); | 240 void RecordBirth(); |
248 | 241 |
249 private: | 242 private: |
250 // The number of births on this thread for our location_. | 243 // The number of births on this thread for our location_. |
251 int birth_count_; | 244 int birth_count_; |
252 | 245 |
253 DISALLOW_COPY_AND_ASSIGN(Births); | 246 DISALLOW_COPY_AND_ASSIGN(Births); |
254 }; | 247 }; |
255 | 248 |
256 //------------------------------------------------------------------------------ | 249 //------------------------------------------------------------------------------ |
257 // Basic info summarizing multiple destructions of a tracked object with a | 250 // A "snapshotted" representation of the DeathData class. |
258 // single birthplace (fixed Location). Used both on specific threads, and also | 251 |
259 // in snapshots when integrating assembled data. | 252 struct BASE_EXPORT DeathDataSnapshot { |
| 253 DeathDataSnapshot(); |
| 254 |
| 255 // Constructs the snapshot from individual values. |
| 256 // The alternative would be taking a DeathData parameter, but this would |
| 257 // create a loop since DeathData indirectly refers DeathDataSnapshot. Passing |
| 258 // a wrapper structure as a param or using an empty constructor for |
| 259 // snapshotting DeathData would be less efficient. |
| 260 DeathDataSnapshot(int count, |
| 261 int32 run_duration_sum, |
| 262 int32 run_duration_max, |
| 263 int32 run_duration_sample, |
| 264 int32 queue_duration_sum, |
| 265 int32 queue_duration_max, |
| 266 int32 queue_duration_sample); |
| 267 ~DeathDataSnapshot(); |
| 268 |
| 269 // Calculates and returns the delta between this snapshot and an earlier |
| 270 // snapshot of the same task |older|. |
| 271 DeathDataSnapshot Delta(const DeathDataSnapshot& older) const; |
| 272 |
| 273 int count; |
| 274 int32 run_duration_sum; |
| 275 int32 run_duration_max; |
| 276 int32 run_duration_sample; |
| 277 int32 queue_duration_sum; |
| 278 int32 queue_duration_max; |
| 279 int32 queue_duration_sample; |
| 280 }; |
| 281 |
| 282 //------------------------------------------------------------------------------ |
| 283 // A "snapshotted" representation of the DeathData for a particular profiling |
| 284 // phase. Used as an element of the list of phase snapshots owned by DeathData. |
| 285 |
| 286 struct DeathDataPhaseSnapshot { |
| 287 DeathDataPhaseSnapshot(int profiling_phase, |
| 288 int count, |
| 289 int32 run_duration_sum, |
| 290 int32 run_duration_max, |
| 291 int32 run_duration_sample, |
| 292 int32 queue_duration_sum, |
| 293 int32 queue_duration_max, |
| 294 int32 queue_duration_sample, |
| 295 const DeathDataPhaseSnapshot* prev); |
| 296 |
| 297 // Profiling phase at which completion this snapshot was taken. |
| 298 int profiling_phase; |
| 299 |
| 300 // Death data snapshot. |
| 301 DeathDataSnapshot death_data; |
| 302 |
| 303 // Pointer to a snapshot from the previous phase. |
| 304 const DeathDataPhaseSnapshot* prev; |
| 305 }; |
| 306 |
| 307 //------------------------------------------------------------------------------ |
| 308 // Information about deaths of a task on a given thread, called "death thread". |
| 309 // Access to members of this class is never protected by a lock. The fields |
| 310 // are accessed in such a way that corruptions resulting from race conditions |
| 311 // are not significant, and don't accumulate as a result of multiple accesses. |
| 312 // All invocations of DeathData::OnProfilingPhaseCompleted and |
| 313 // ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process |
| 314 // must be called from the same thread. It doesn't matter what thread it is, but |
| 315 // it's important the same thread is used as a snapshot thread during the whole |
| 316 // process lifetime. All fields except sample_probability_count_ can be |
| 317 // snapshotted. |
260 | 318 |
261 class BASE_EXPORT DeathData { | 319 class BASE_EXPORT DeathData { |
262 public: | 320 public: |
263 // Default initializer. | |
264 DeathData(); | 321 DeathData(); |
265 | 322 DeathData(const DeathData& other); |
266 // When deaths have not yet taken place, and we gather data from all the | 323 ~DeathData(); |
267 // threads, we create DeathData stats that tally the number of births without | |
268 // a corresponding death. | |
269 explicit DeathData(int count); | |
270 | 324 |
271 // Update stats for a task destruction (death) that had a Run() time of | 325 // Update stats for a task destruction (death) that had a Run() time of |
272 // |duration|, and has had a queueing delay of |queue_duration|. | 326 // |duration|, and has had a queueing delay of |queue_duration|. |
273 void RecordDeath(const int32 queue_duration, | 327 void RecordDeath(const int32 queue_duration, |
274 const int32 run_duration, | 328 const int32 run_duration, |
275 const uint32 random_number); | 329 const uint32 random_number); |
276 | 330 |
277 // Metrics accessors, used only for serialization and in tests. | 331 // Metrics and past snapshots accessors, used only for serialization and in |
| 332 // tests. |
278 int count() const; | 333 int count() const; |
279 int32 run_duration_sum() const; | 334 int32 run_duration_sum() const; |
280 int32 run_duration_max() const; | 335 int32 run_duration_max() const; |
281 int32 run_duration_sample() const; | 336 int32 run_duration_sample() const; |
282 int32 queue_duration_sum() const; | 337 int32 queue_duration_sum() const; |
283 int32 queue_duration_max() const; | 338 int32 queue_duration_max() const; |
284 int32 queue_duration_sample() const; | 339 int32 queue_duration_sample() const; |
| 340 const DeathDataPhaseSnapshot* last_phase_snapshot() const; |
285 | 341 |
286 // Reset all tallies to zero. This is used as a hack on realtime data. | 342 // Called when the current profiling phase, identified by |profiling_phase|, |
287 void Clear(); | 343 // ends. |
| 344 // Must be called only on the snapshot thread. |
| 345 void OnProfilingPhaseCompleted(int profiling_phase); |
288 | 346 |
289 private: | 347 private: |
290 // Members are ordered from most regularly read and updated, to least | 348 // Members are ordered from most regularly read and updated, to least |
291 // frequently used. This might help a bit with cache lines. | 349 // frequently used. This might help a bit with cache lines. |
292 // Number of runs seen (divisor for calculating averages). | 350 // Number of runs seen (divisor for calculating averages). |
| 351 // Can be incremented only on the death thread. |
293 int count_; | 352 int count_; |
294 // Basic tallies, used to compute averages. | 353 |
| 354 // Count used in determining probability of selecting exec/queue times from a |
| 355 // recorded death as samples. |
| 356 // Gets incremented only on the death thread, but can be set to 0 by |
| 357 // OnProfilingPhaseCompleted() on the snapshot thread. |
| 358 int sample_probability_count_; |
| 359 |
| 360 // Basic tallies, used to compute averages. Can be incremented only on the |
| 361 // death thread. |
295 int32 run_duration_sum_; | 362 int32 run_duration_sum_; |
296 int32 queue_duration_sum_; | 363 int32 queue_duration_sum_; |
297 // Max values, used by local visualization routines. These are often read, | 364 // Max values, used by local visualization routines. These are often read, |
298 // but rarely updated. | 365 // but rarely updated. The max values get assigned only on the death thread, |
| 366 // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the |
| 367 // snapshot thread. |
299 int32 run_duration_max_; | 368 int32 run_duration_max_; |
300 int32 queue_duration_max_; | 369 int32 queue_duration_max_; |
301 // Samples, used by crowd sourcing gatherers. These are almost never read, | 370 // Samples, used by crowd sourcing gatherers. These are almost never read, |
302 // and rarely updated. | 371 // and rarely updated. They can be modified only on the death thread. |
303 int32 run_duration_sample_; | 372 int32 run_duration_sample_; |
304 int32 queue_duration_sample_; | 373 int32 queue_duration_sample_; |
| 374 |
| 375 // Snapshot of this death data made at the last profiling phase completion, if |
| 376 // any. DeathData owns the whole list starting with this pointer. |
| 377 // Can be accessed only on the snapshot thread. |
| 378 const DeathDataPhaseSnapshot* last_phase_snapshot_; |
| 379 |
| 380 DISALLOW_ASSIGN(DeathData); |
305 }; | 381 }; |
306 | 382 |
307 //------------------------------------------------------------------------------ | 383 //------------------------------------------------------------------------------ |
308 // A "snapshotted" representation of the DeathData class. | |
309 | |
310 struct BASE_EXPORT DeathDataSnapshot { | |
311 DeathDataSnapshot(); | |
312 explicit DeathDataSnapshot(const DeathData& death_data); | |
313 ~DeathDataSnapshot(); | |
314 | |
315 int count; | |
316 int32 run_duration_sum; | |
317 int32 run_duration_max; | |
318 int32 run_duration_sample; | |
319 int32 queue_duration_sum; | |
320 int32 queue_duration_max; | |
321 int32 queue_duration_sample; | |
322 }; | |
323 | |
324 //------------------------------------------------------------------------------ | |
325 // A temporary collection of data that can be sorted and summarized. It is | 384 // A temporary collection of data that can be sorted and summarized. It is |
326 // gathered (carefully) from many threads. Instances are held in arrays and | 385 // gathered (carefully) from many threads. Instances are held in arrays and |
327 // processed, filtered, and rendered. | 386 // processed, filtered, and rendered. |
328 // The source of this data was collected on many threads, and is asynchronously | 387 // The source of this data was collected on many threads, and is asynchronously |
329 // changing. The data in this instance is not asynchronously changing. | 388 // changing. The data in this instance is not asynchronously changing. |
330 | 389 |
331 struct BASE_EXPORT TaskSnapshot { | 390 struct BASE_EXPORT TaskSnapshot { |
332 TaskSnapshot(); | 391 TaskSnapshot(); |
333 TaskSnapshot(const BirthOnThread& birth, | 392 TaskSnapshot(const BirthOnThreadSnapshot& birth, |
334 const DeathData& death_data, | 393 const DeathDataSnapshot& death_data, |
335 const std::string& death_thread_name); | 394 const std::string& death_thread_name); |
336 ~TaskSnapshot(); | 395 ~TaskSnapshot(); |
337 | 396 |
338 BirthOnThreadSnapshot birth; | 397 BirthOnThreadSnapshot birth; |
| 398 // Delta between death data for a thread for a certain profiling phase and the |
| 399 // snapshot for the pervious phase, if any. Otherwise, just a snapshot. |
339 DeathDataSnapshot death_data; | 400 DeathDataSnapshot death_data; |
340 std::string death_thread_name; | 401 std::string death_thread_name; |
341 }; | 402 }; |
342 | 403 |
343 //------------------------------------------------------------------------------ | 404 //------------------------------------------------------------------------------ |
344 // For each thread, we have a ThreadData that stores all tracking info generated | 405 // For each thread, we have a ThreadData that stores all tracking info generated |
345 // on this thread. This prevents the need for locking as data accumulates. | 406 // on this thread. This prevents the need for locking as data accumulates. |
346 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. | 407 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. |
347 // We also have a linked list of ThreadData instances, and that list is used to | 408 // We also have a linked list of ThreadData instances, and that list is used to |
348 // harvest data from all existing instances. | 409 // harvest data from all existing instances. |
349 | 410 |
350 struct ProcessDataPhaseSnapshot; | 411 struct ProcessDataPhaseSnapshot; |
351 struct ProcessDataSnapshot; | 412 struct ProcessDataSnapshot; |
352 class BASE_EXPORT TaskStopwatch; | 413 class BASE_EXPORT TaskStopwatch; |
353 | 414 |
354 // Map from profiling phase number to the process-wide snapshotted | 415 // Map from profiling phase number to the process-wide snapshotted |
355 // 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 |
356 // phase. | 417 // phase. |
357 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; | 418 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; |
358 | 419 |
359 class BASE_EXPORT ThreadData { | 420 class BASE_EXPORT ThreadData { |
360 public: | 421 public: |
361 // Current allowable states of the tracking system. The states can vary | 422 // Current allowable states of the tracking system. The states can vary |
362 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. | 423 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. |
363 enum Status { | 424 enum Status { |
364 UNINITIALIZED, // PRistine, link-time state before running. | 425 UNINITIALIZED, // Pristine, link-time state before running. |
365 DORMANT_DURING_TESTS, // Only used during testing. | 426 DORMANT_DURING_TESTS, // Only used during testing. |
366 DEACTIVATED, // No longer recording profiling. | 427 DEACTIVATED, // No longer recording profiling. |
367 PROFILING_ACTIVE, // Recording profiles (no parent-child links). | 428 PROFILING_ACTIVE, // Recording profiles. |
368 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. | 429 STATUS_LAST = PROFILING_ACTIVE |
369 STATUS_LAST = PROFILING_CHILDREN_ACTIVE | |
370 }; | 430 }; |
371 | 431 |
372 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; | 432 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; |
373 typedef std::map<const Births*, DeathData> DeathMap; | 433 typedef std::map<const Births*, DeathData> DeathMap; |
374 typedef std::pair<const Births*, const Births*> ParentChildPair; | |
375 typedef std::set<ParentChildPair> ParentChildSet; | |
376 typedef std::stack<const Births*> ParentStack; | |
377 | 434 |
378 // Initialize the current thread context with a new instance of ThreadData. | 435 // Initialize the current thread context with a new instance of ThreadData. |
379 // 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 |
380 // 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 |
381 // 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. |
382 static void InitializeThreadContext(const std::string& suggested_name); | 439 static void InitializeThreadContext(const std::string& suggested_name); |
383 | 440 |
384 // Using Thread Local Store, find the current instance for collecting data. | 441 // Using Thread Local Store, find the current instance for collecting data. |
385 // 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 |
386 // this thread. | 443 // this thread. |
387 // This may return NULL if the system is disabled for any reason. | 444 // This may return NULL if the system is disabled for any reason. |
388 static ThreadData* Get(); | 445 static ThreadData* Get(); |
389 | 446 |
390 // Fills |process_data_snapshot| with phased snapshots of all profiling | 447 // Fills |process_data_snapshot| with phased snapshots of all profiling |
391 // phases, including the current one. | 448 // phases, including the current one, identified by |current_profiling_phase|. |
392 static void Snapshot(ProcessDataSnapshot* process_data_snapshot); | 449 // |current_profiling_phase| is necessary because a child process can start |
| 450 // after several phase-changing events, so it needs to receive the current |
| 451 // phase number from the browser process to fill the correct entry for the |
| 452 // current phase in the |process_data_snapshot| map. |
| 453 static void Snapshot(int current_profiling_phase, |
| 454 ProcessDataSnapshot* process_data_snapshot); |
| 455 |
| 456 // Called when the current profiling phase, identified by |profiling_phase|, |
| 457 // ends. |
| 458 // |profiling_phase| is necessary because a child process can start after |
| 459 // several phase-changing events, so it needs to receive the phase number from |
| 460 // the browser process to fill the correct entry in the |
| 461 // completed_phases_snapshots_ map. |
| 462 static void OnProfilingPhaseCompleted(int profiling_phase); |
393 | 463 |
394 // Finds (or creates) a place to count births from the given location in this | 464 // Finds (or creates) a place to count births from the given location in this |
395 // thread, and increment that tally. | 465 // thread, and increment that tally. |
396 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. | 466 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. |
397 static Births* TallyABirthIfActive(const Location& location); | 467 static Births* TallyABirthIfActive(const Location& location); |
398 | 468 |
399 // Records the end of a timed run of an object. The |completed_task| contains | 469 // Records the end of a timed run of an object. The |completed_task| contains |
400 // a pointer to a Births, the time_posted, and a delayed_start_time if any. | 470 // a pointer to a Births, the time_posted, and a delayed_start_time if any. |
401 // The |start_of_run| indicates when we started to perform the run of the | 471 // The |start_of_run| indicates when we started to perform the run of the |
402 // task. The delayed_start_time is non-null for tasks that were posted as | 472 // task. The delayed_start_time is non-null for tasks that were posted as |
403 // delayed tasks, and it indicates when the task should have run (i.e., when | 473 // delayed tasks, and it indicates when the task should have run (i.e., when |
404 // it should have posted out of the timer queue, and into the work queue. | 474 // it should have posted out of the timer queue, and into the work queue. |
405 // The |end_of_run| was just obtained by a call to Now() (just after the task | 475 // The |end_of_run| was just obtained by a call to Now() (just after the task |
406 // finished). It is provided as an argument to help with testing. | 476 // finished). It is provided as an argument to help with testing. |
407 static void TallyRunOnNamedThreadIfTracking( | 477 static void TallyRunOnNamedThreadIfTracking( |
408 const base::TrackingInfo& completed_task, | 478 const base::TrackingInfo& completed_task, |
409 const TaskStopwatch& stopwatch); | 479 const TaskStopwatch& stopwatch); |
410 | 480 |
411 // Record the end of a timed run of an object. The |birth| is the record for | 481 // Record the end of a timed run of an object. The |birth| is the record for |
412 // the instance, the |time_posted| records that instant, which is presumed to | 482 // the instance, the |time_posted| records that instant, which is presumed to |
413 // be when the task was posted into a queue to run on a worker thread. | 483 // be when the task was posted into a queue to run on a worker thread. |
414 // The |start_of_run| is when the worker thread started to perform the run of | 484 // The |start_of_run| is when the worker thread started to perform the run of |
415 // the task. | 485 // the task. |
416 // The |end_of_run| was just obtained by a call to Now() (just after the task | 486 // The |end_of_run| was just obtained by a call to Now() (just after the task |
417 // finished). | 487 // finished). |
418 static void TallyRunOnWorkerThreadIfTracking(const Births* birth, | 488 static void TallyRunOnWorkerThreadIfTracking(const Births* births, |
419 const TrackedTime& time_posted, | 489 const TrackedTime& time_posted, |
420 const TaskStopwatch& stopwatch); | 490 const TaskStopwatch& stopwatch); |
421 | 491 |
422 // Record the end of execution in region, generally corresponding to a scope | 492 // Record the end of execution in region, generally corresponding to a scope |
423 // being exited. | 493 // being exited. |
424 static void TallyRunInAScopedRegionIfTracking(const Births* birth, | 494 static void TallyRunInAScopedRegionIfTracking(const Births* births, |
425 const TaskStopwatch& stopwatch); | 495 const TaskStopwatch& stopwatch); |
426 | 496 |
427 const std::string& thread_name() const { return thread_name_; } | 497 const std::string& thread_name() const { return thread_name_; } |
428 | 498 |
429 // Initializes all statics if needed (this initialization call should be made | 499 // Initializes all statics if needed (this initialization call should be made |
430 // while we are single threaded). Returns false if unable to initialize. | 500 // while we are single threaded). Returns false if unable to initialize. |
431 static bool Initialize(); | 501 static bool Initialize(); |
432 | 502 |
433 // Sets internal status_. | 503 // Sets internal status_. |
434 // If |status| is false, then status_ is set to DEACTIVATED. | 504 // If |status| is false, then status_ is set to DEACTIVATED. |
435 // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or | 505 // If |status| is true, then status_ is set to PROFILING_ACTIVE. |
436 // PROFILING_CHILDREN_ACTIVE. | 506 // If it fails to initialize the TLS slot, this function will return false. |
437 // If tracking is not compiled in, this function will return false. | |
438 // If parent-child tracking is not compiled in, then an attempt to set the | |
439 // status to PROFILING_CHILDREN_ACTIVE will only result in a status of | |
440 // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is | |
441 // compiled into the binary, and parent-child tracking at the | |
442 // PROFILING_CHILDREN_ACTIVE level might not be compiled in). | |
443 static bool InitializeAndSetTrackingStatus(Status status); | 507 static bool InitializeAndSetTrackingStatus(Status status); |
444 | 508 |
445 static Status status(); | 509 static Status status(); |
446 | 510 |
447 // 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 |
448 // DEACTIVATED). | 512 // DEACTIVATED). |
449 static bool TrackingStatus(); | 513 static bool TrackingStatus(); |
450 | 514 |
451 // For testing only, indicate if the status of parent-child tracking is turned | |
452 // on. This is currently a compiled option, atop TrackingStatus(). | |
453 static bool TrackingParentChildStatus(); | |
454 | |
455 // Marks a start of a tracked run. It's super fast when tracking is disabled, | |
456 // and has some internal side effects when we are tracking, so that we can | |
457 // deduce the amount of time accumulated outside of execution of tracked runs. | |
458 // The task that will be tracked is passed in as |parent| so that parent-child | |
459 // relationships can be (optionally) calculated. | |
460 static void PrepareForStartOfRun(const Births* parent); | |
461 | |
462 // Enables profiler timing. | 515 // Enables profiler timing. |
463 static void EnableProfilerTiming(); | 516 static void EnableProfilerTiming(); |
464 | 517 |
465 // 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 |
466 // 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 |
467 // 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 |
468 // the code). | 521 // the code). |
469 static TrackedTime Now(); | 522 static TrackedTime Now(); |
470 | 523 |
471 // 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... |
482 private: | 535 private: |
483 friend class TaskStopwatch; | 536 friend class TaskStopwatch; |
484 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it | 537 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it |
485 // in production code. | 538 // in production code. |
486 // 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 |
487 // better change of optimizing (inlining? etc.) private methods (knowing that | 540 // better change of optimizing (inlining? etc.) private methods (knowing that |
488 // there will be no need for an external entry point). | 541 // there will be no need for an external entry point). |
489 friend class TrackedObjectsTest; | 542 friend class TrackedObjectsTest; |
490 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); | 543 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); |
491 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); | 544 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
492 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest); | |
493 | 545 |
494 typedef std::map<const BirthOnThread*, int> BirthCountMap; | 546 typedef std::map<const BirthOnThread*, int> BirthCountMap; |
495 | 547 |
| 548 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> |
| 549 DeathsSnapshot; |
| 550 |
496 // Worker thread construction creates a name since there is none. | 551 // Worker thread construction creates a name since there is none. |
497 explicit ThreadData(int thread_number); | 552 explicit ThreadData(int thread_number); |
498 | 553 |
499 // Message loop based construction should provide a name. | 554 // Message loop based construction should provide a name. |
500 explicit ThreadData(const std::string& suggested_name); | 555 explicit ThreadData(const std::string& suggested_name); |
501 | 556 |
502 ~ThreadData(); | 557 ~ThreadData(); |
503 | 558 |
504 // Push this instance to the head of all_thread_data_list_head_, linking it to | 559 // Push this instance to the head of all_thread_data_list_head_, linking it to |
505 // the previous head. This is performed after each construction, and leaves | 560 // the previous head. This is performed after each construction, and leaves |
506 // the instance permanently on that list. | 561 // the instance permanently on that list. |
507 void PushToHeadOfList(); | 562 void PushToHeadOfList(); |
508 | 563 |
509 // (Thread safe) Get start of list of all ThreadData instances using the lock. | 564 // (Thread safe) Get start of list of all ThreadData instances using the lock. |
510 static ThreadData* first(); | 565 static ThreadData* first(); |
511 | 566 |
512 // Iterate through the null terminated list of ThreadData instances. | 567 // Iterate through the null terminated list of ThreadData instances. |
513 ThreadData* next() const; | 568 ThreadData* next() const; |
514 | 569 |
515 | 570 |
516 // In this thread's data, record a new birth. | 571 // In this thread's data, record a new birth. |
517 Births* TallyABirth(const Location& location); | 572 Births* TallyABirth(const Location& location); |
518 | 573 |
519 // Find a place to record a death on this thread. | 574 // Find a place to record a death on this thread. |
520 void TallyADeath(const Births& birth, | 575 void TallyADeath(const Births& births, |
521 int32 queue_duration, | 576 int32 queue_duration, |
522 const TaskStopwatch& stopwatch); | 577 const TaskStopwatch& stopwatch); |
523 | 578 |
524 // Snapshot (under a lock) the profiled data for the tasks in each ThreadData | |
525 // instance. Also updates the |birth_counts| tally for each task to keep | |
526 // track of the number of living instances of the task. | |
527 static void SnapshotAllExecutedTasks( | |
528 ProcessDataPhaseSnapshot* process_data_phase, | |
529 BirthCountMap* birth_counts); | |
530 | |
531 // Fills |process_data_phase| with all the recursive results in our process. | |
532 static void SnapshotCurrentPhase( | |
533 ProcessDataPhaseSnapshot* process_data_phase); | |
534 | |
535 // Snapshots (under a lock) the profiled data for the tasks for this thread | 579 // Snapshots (under a lock) the profiled data for the tasks for this thread |
536 // and writes all of the executed tasks' data -- i.e. the data for the tasks | 580 // and writes all of the executed tasks' data -- i.e. the data for all |
537 // with with entries in the death_map_ -- into |process_data_phase|. Also | 581 // profiling phases (including the current one: |current_profiling_phase|) for |
538 // updates the |birth_counts| tally for each task to keep track of the number | 582 // the tasks with with entries in the death_map_ -- into |phased_snapshots|. |
539 // of living instances of the task -- that is, each task maps to the number of | 583 // Also updates the |birth_counts| tally for each task to keep track of the |
540 // births for the task that have not yet been balanced by a death. | 584 // number of living instances of the task -- that is, each task maps to the |
541 void SnapshotExecutedTasks(ProcessDataPhaseSnapshot* process_data_phase, | 585 // number of births for the task that have not yet been balanced by a death. |
| 586 void SnapshotExecutedTasks(int current_profiling_phase, |
| 587 PhasedProcessDataSnapshotMap* phased_snapshots, |
542 BirthCountMap* birth_counts); | 588 BirthCountMap* birth_counts); |
543 | 589 |
544 // 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 |
545 // 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 |
546 // the map(s) from being reallocated while they are copied. | 592 // the map(s) from being reallocated while they are copied. |
547 void SnapshotMaps(BirthMap* birth_map, | 593 void SnapshotMaps(int profiling_phase, |
548 DeathMap* death_map, | 594 BirthMap* birth_map, |
549 ParentChildSet* parent_child_set); | 595 DeathsSnapshot* deaths); |
| 596 |
| 597 // Called for this thread when the current profiling phase, identified by |
| 598 // |profiling_phase|, ends. |
| 599 void OnProfilingPhaseCompletedOnThread(int profiling_phase); |
550 | 600 |
551 // 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. |
552 // 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. |
553 static void OnThreadTermination(void* thread_data); | 603 static void OnThreadTermination(void* thread_data); |
554 | 604 |
555 // 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 |
556 // can save all the thread data into a cache of reusable ThreadData instances. | 606 // can save all the thread data into a cache of reusable ThreadData instances. |
557 void OnThreadTerminationCleanup(); | 607 void OnThreadTerminationCleanup(); |
558 | 608 |
559 // Cleans up data structures, and returns statics to near pristine (mostly | 609 // Cleans up data structures, and returns statics to near pristine (mostly |
(...skipping 11 matching lines...) Expand all Loading... |
571 // increasing time functcion. | 621 // increasing time functcion. |
572 static NowFunction* now_function_; | 622 static NowFunction* now_function_; |
573 | 623 |
574 // If true, now_function_ returns values that can be used to calculate queue | 624 // If true, now_function_ returns values that can be used to calculate queue |
575 // time. | 625 // time. |
576 static bool now_function_is_time_; | 626 static bool now_function_is_time_; |
577 | 627 |
578 // We use thread local store to identify which ThreadData to interact with. | 628 // We use thread local store to identify which ThreadData to interact with. |
579 static base::ThreadLocalStorage::StaticSlot tls_index_; | 629 static base::ThreadLocalStorage::StaticSlot tls_index_; |
580 | 630 |
581 // List of ThreadData instances for use with worker threads. When a worker | 631 // List of ThreadData instances for use with worker threads. When a worker |
582 // thread is done (terminated), we push it onto this list. When a new worker | 632 // thread is done (terminated), we push it onto this list. When a new worker |
583 // thread is created, we first try to re-use a ThreadData instance from the | 633 // thread is created, we first try to re-use a ThreadData instance from the |
584 // list, and if none are available, construct a new one. | 634 // list, and if none are available, construct a new one. |
585 // This is only accessed while list_lock_ is held. | 635 // This is only accessed while list_lock_ is held. |
586 static ThreadData* first_retired_worker_; | 636 static ThreadData* first_retired_worker_; |
587 | 637 |
588 // Link to the most recently created instance (starts a null terminated list). | 638 // Link to the most recently created instance (starts a null terminated list). |
589 // The list is traversed by about:profiler when it needs to snapshot data. | 639 // The list is traversed by about:profiler when it needs to snapshot data. |
590 // This is only accessed while list_lock_ is held. | 640 // This is only accessed while list_lock_ is held. |
591 static ThreadData* all_thread_data_list_head_; | 641 static ThreadData* all_thread_data_list_head_; |
592 | 642 |
593 // The next available worker thread number. This should only be accessed when | 643 // The next available worker thread number. This should only be accessed when |
594 // the list_lock_ is held. | 644 // the list_lock_ is held. |
595 static int worker_thread_data_creation_count_; | 645 static int worker_thread_data_creation_count_; |
596 | 646 |
597 // The number of times TLS has called us back to cleanup a ThreadData | 647 // The number of times TLS has called us back to cleanup a ThreadData |
598 // instance. This is only accessed while list_lock_ is held. | 648 // instance. This is only accessed while list_lock_ is held. |
599 static int cleanup_count_; | 649 static int cleanup_count_; |
600 | 650 |
601 // Incarnation sequence number, indicating how many times (during unittests) | 651 // Incarnation sequence number, indicating how many times (during unittests) |
602 // we've either transitioned out of UNINITIALIZED, or into that state. This | 652 // we've either transitioned out of UNINITIALIZED, or into that state. This |
603 // value is only accessed while the list_lock_ is held. | 653 // value is only accessed while the list_lock_ is held. |
604 static int incarnation_counter_; | 654 static int incarnation_counter_; |
605 | 655 |
606 // Protection for access to all_thread_data_list_head_, and to | 656 // Protection for access to all_thread_data_list_head_, and to |
607 // unregistered_thread_data_pool_. This lock is leaked at shutdown. | 657 // unregistered_thread_data_pool_. This lock is leaked at shutdown. |
608 // The lock is very infrequently used, so we can afford to just make a lazy | 658 // The lock is very infrequently used, so we can afford to just make a lazy |
609 // instance and be safe. | 659 // instance and be safe. |
610 static base::LazyInstance<base::Lock>::Leaky list_lock_; | 660 static base::LazyInstance<base::Lock>::Leaky list_lock_; |
611 | 661 |
612 // We set status_ to SHUTDOWN when we shut down the tracking service. | 662 // We set status_ to SHUTDOWN when we shut down the tracking service. |
613 static Status status_; | 663 static Status status_; |
614 | 664 |
615 // Link to next instance (null terminated list). Used to globally track all | 665 // Link to next instance (null terminated list). Used to globally track all |
616 // registered instances (corresponds to all registered threads where we keep | 666 // registered instances (corresponds to all registered threads where we keep |
617 // data). | 667 // data). |
618 ThreadData* next_; | 668 ThreadData* next_; |
619 | 669 |
620 // Pointer to another ThreadData instance for a Worker-Thread that has been | 670 // Pointer to another ThreadData instance for a Worker-Thread that has been |
621 // retired (its thread was terminated). This value is non-NULL only for a | 671 // retired (its thread was terminated). This value is non-NULL only for a |
622 // retired ThreadData associated with a Worker-Thread. | 672 // retired ThreadData associated with a Worker-Thread. |
623 ThreadData* next_retired_worker_; | 673 ThreadData* next_retired_worker_; |
624 | 674 |
625 // The name of the thread that is being recorded. If this thread has no | 675 // The name of the thread that is being recorded. If this thread has no |
(...skipping 11 matching lines...) Expand all Loading... |
637 // 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 |
638 // duration of the snapshotting activity. | 688 // duration of the snapshotting activity. |
639 BirthMap birth_map_; | 689 BirthMap birth_map_; |
640 | 690 |
641 // Similar to birth_map_, this records informations about death of tracked | 691 // Similar to birth_map_, this records informations about death of tracked |
642 // 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). |
643 // 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 |
644 // locking before reading it. | 694 // locking before reading it. |
645 DeathMap death_map_; | 695 DeathMap death_map_; |
646 | 696 |
647 // A set of parents that created children tasks on this thread. Each pair | |
648 // corresponds to potentially non-local Births (location and thread), and a | |
649 // local Births (that took place on this thread). | |
650 ParentChildSet parent_child_set_; | |
651 | |
652 // 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 |
653 // 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 |
654 // 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 |
655 // 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 |
656 // 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 |
657 // writing is only done from this thread. | 702 // writing is only done from this thread. |
658 mutable base::Lock map_lock_; | 703 mutable base::Lock map_lock_; |
659 | 704 |
660 // The stack of parents that are currently being profiled. This includes only | |
661 // tasks that have started a timer recently via PrepareForStartOfRun(), but | |
662 // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep, | |
663 // but if a scoped region is profiled, or <sigh> a task runs a nested-message | |
664 // loop, then the stack can grow larger. Note that we don't try to deduct | |
665 // time in nested profiles, as our current timer is based on wall-clock time, | |
666 // and not CPU time (and we're hopeful that nested timing won't be a | |
667 // significant additional cost). | |
668 ParentStack parent_stack_; | |
669 | |
670 // 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 |
671 // 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 |
672 // 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 |
673 // we stir in more and more as we go. | 708 // we stir in more and more as we go. |
674 uint32 random_number_; | 709 uint32 random_number_; |
675 | 710 |
676 // 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. |
677 // 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 |
678 // pool (this is only critical in tests which go through multiple | 713 // pool (this is only critical in tests which go through multiple |
679 // incarnations). | 714 // incarnations). |
680 int incarnation_count_for_pool_; | 715 int incarnation_count_for_pool_; |
681 | 716 |
682 // Most recently started (i.e. most nested) stopwatch on the current thread, | 717 // Most recently started (i.e. most nested) stopwatch on the current thread, |
683 // if it exists; NULL otherwise. | 718 // if it exists; NULL otherwise. |
684 TaskStopwatch* current_stopwatch_; | 719 TaskStopwatch* current_stopwatch_; |
685 | 720 |
686 DISALLOW_COPY_AND_ASSIGN(ThreadData); | 721 DISALLOW_COPY_AND_ASSIGN(ThreadData); |
687 }; | 722 }; |
688 | 723 |
689 //------------------------------------------------------------------------------ | 724 //------------------------------------------------------------------------------ |
690 // Stopwatch to measure task run time or simply create a time interval that will | 725 // Stopwatch to measure task run time or simply create a time interval that will |
691 // be subtracted from the current most nested task's run time. Stopwatches | 726 // be subtracted from the current most nested task's run time. Stopwatches |
692 // coordinate with the stopwatches in which they are nested to avoid | 727 // coordinate with the stopwatches in which they are nested to avoid |
693 // double-counting nested tasks run times. | 728 // double-counting nested tasks run times. |
694 | 729 |
695 class BASE_EXPORT TaskStopwatch { | 730 class BASE_EXPORT TaskStopwatch { |
696 public: | 731 public: |
697 // Starts the stopwatch. | 732 // Starts the stopwatch. |
698 TaskStopwatch(); | 733 TaskStopwatch(); |
699 ~TaskStopwatch(); | 734 ~TaskStopwatch(); |
700 | 735 |
701 // Starts stopwatch. | 736 // Starts stopwatch. |
(...skipping 27 matching lines...) Expand all Loading... |
729 // Sum of wallclock durations of all stopwatches that were directly nested in | 764 // Sum of wallclock durations of all stopwatches that were directly nested in |
730 // this one. | 765 // this one. |
731 int32 excluded_duration_ms_; | 766 int32 excluded_duration_ms_; |
732 | 767 |
733 // Stopwatch which was running on our thread when this stopwatch was started. | 768 // Stopwatch which was running on our thread when this stopwatch was started. |
734 // That preexisting stopwatch must be adjusted to the exclude the wallclock | 769 // That preexisting stopwatch must be adjusted to the exclude the wallclock |
735 // duration of this stopwatch. | 770 // duration of this stopwatch. |
736 TaskStopwatch* parent_; | 771 TaskStopwatch* parent_; |
737 | 772 |
738 #if DCHECK_IS_ON() | 773 #if DCHECK_IS_ON() |
739 // State of the stopwatch. Stopwatch is first constructed in a created state | 774 // State of the stopwatch. Stopwatch is first constructed in a created state |
740 // state, then is optionally started/stopped, then destructed. | 775 // state, then is optionally started/stopped, then destructed. |
741 enum { CREATED, RUNNING, STOPPED } state_; | 776 enum { CREATED, RUNNING, STOPPED } state_; |
742 | 777 |
743 // 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 |
744 // stopwatch exists. NULL otherwise. | 779 // stopwatch exists. NULL otherwise. |
745 TaskStopwatch* child_; | 780 TaskStopwatch* child_; |
746 #endif | 781 #endif |
747 }; | 782 }; |
748 | 783 |
749 //------------------------------------------------------------------------------ | 784 //------------------------------------------------------------------------------ |
750 // A snapshotted representation of a (parent, child) task pair, for tracking | |
751 // hierarchical profiles. | |
752 | |
753 struct BASE_EXPORT ParentChildPairSnapshot { | |
754 public: | |
755 ParentChildPairSnapshot(); | |
756 explicit ParentChildPairSnapshot( | |
757 const ThreadData::ParentChildPair& parent_child); | |
758 ~ParentChildPairSnapshot(); | |
759 | |
760 BirthOnThreadSnapshot parent; | |
761 BirthOnThreadSnapshot child; | |
762 }; | |
763 | |
764 //------------------------------------------------------------------------------ | |
765 // 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, |
766 // for a single profiling phase. | 786 // for a single profiling phase. |
767 | 787 |
768 struct BASE_EXPORT ProcessDataPhaseSnapshot { | 788 struct BASE_EXPORT ProcessDataPhaseSnapshot { |
769 public: | 789 public: |
770 ProcessDataPhaseSnapshot(); | 790 ProcessDataPhaseSnapshot(); |
771 ~ProcessDataPhaseSnapshot(); | 791 ~ProcessDataPhaseSnapshot(); |
772 | 792 |
773 std::vector<TaskSnapshot> tasks; | 793 std::vector<TaskSnapshot> tasks; |
774 std::vector<ParentChildPairSnapshot> descendants; | |
775 }; | 794 }; |
776 | 795 |
777 //------------------------------------------------------------------------------ | 796 //------------------------------------------------------------------------------ |
778 // 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, |
779 // for all profiling phases, including the current one. | 798 // for all profiling phases, including the current one. |
780 | 799 |
781 struct BASE_EXPORT ProcessDataSnapshot { | 800 struct BASE_EXPORT ProcessDataSnapshot { |
782 public: | 801 public: |
783 ProcessDataSnapshot(); | 802 ProcessDataSnapshot(); |
784 ~ProcessDataSnapshot(); | 803 ~ProcessDataSnapshot(); |
785 | 804 |
786 PhasedProcessDataSnapshotMap phased_process_data_snapshots; | 805 PhasedProcessDataSnapshotMap phased_snapshots; |
787 base::ProcessId process_id; | 806 base::ProcessId process_id; |
788 }; | 807 }; |
789 | 808 |
790 } // namespace tracked_objects | 809 } // namespace tracked_objects |
791 | 810 |
792 #endif // BASE_TRACKED_OBJECTS_H_ | 811 #endif // BASE_TRACKED_OBJECTS_H_ |
OLD | NEW |