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/profiler/alternate_timer.h" | 22 #include "base/profiler/alternate_timer.h" |
22 #include "base/profiler/tracked_time.h" | 23 #include "base/profiler/tracked_time.h" |
23 #include "base/synchronization/lock.h" | 24 #include "base/synchronization/lock.h" |
24 #include "base/threading/thread_local_storage.h" | 25 #include "base/threading/thread_local_storage.h" |
25 | 26 |
26 namespace base { | 27 namespace base { |
27 struct TrackingInfo; | 28 struct TrackingInfo; |
28 } | 29 } |
29 | 30 |
30 // TrackedObjects provides a database of stats about objects (generally Tasks) | 31 // TrackedObjects provides a database of stats about objects (generally Tasks) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 // (3) the snapshotted data. | 141 // (3) the snapshotted data. |
141 // | 142 // |
142 // For a given birth location, information about births is spread across data | 143 // For a given birth location, information about births is spread across data |
143 // structures that are asynchronously changing on various threads. For | 144 // structures that are asynchronously changing on various threads. For |
144 // serialization and display purposes, we need to construct TaskSnapshot | 145 // serialization and display purposes, we need to construct TaskSnapshot |
145 // instances for each combination of birth thread, death thread, and location, | 146 // instances for each combination of birth thread, death thread, and location, |
146 // along with the count of such lifetimes. We gather such data into a | 147 // along with the count of such lifetimes. We gather such data into a |
147 // TaskSnapshot instances, so that such instances can be sorted and | 148 // TaskSnapshot instances, so that such instances can be sorted and |
148 // aggregated (and remain frozen during our processing). | 149 // aggregated (and remain frozen during our processing). |
149 // | 150 // |
150 // The ProcessDataSnapshot struct is a serialized representation of the list | 151 // Profiling consists of phases. The concrete phase in the sequence of phases is |
151 // of ThreadData objects for a process. It holds a set of TaskSnapshots | 152 // identified by its 0-based index. |
152 // and tracks parent/child relationships for the executed tasks. The statistics | 153 // |
153 // in a snapshot are gathered asynhcronously relative to their ongoing updates. | 154 // The ProcessDataPhaseSnapshot struct is a serialized representation of the |
| 155 // 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 // executed tasks. The statistics in a snapshot are gathered asynhcronously |
| 158 // relative to their ongoing updates. |
154 // It is possible, though highly unlikely, that stats could be incorrectly | 159 // It is possible, though highly unlikely, that stats could be incorrectly |
155 // 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 |
156 // 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 |
157 // example, match with the number of durations we accumulated). The advantage | 162 // example, match with the number of durations we accumulated). The advantage |
158 // 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 |
159 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, | 164 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, |
160 // not the underlying and ongoing statistic). In contrast, pointer data that | 165 // not the underlying and ongoing statistic). In contrast, pointer data that |
161 // is accessed during snapshotting is completely invariant, and hence is | 166 // is accessed during snapshotting is completely invariant, and hence is |
162 // 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 |
163 // memory reference). | 168 // memory reference). |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 std::string death_thread_name; | 340 std::string death_thread_name; |
336 }; | 341 }; |
337 | 342 |
338 //------------------------------------------------------------------------------ | 343 //------------------------------------------------------------------------------ |
339 // For each thread, we have a ThreadData that stores all tracking info generated | 344 // For each thread, we have a ThreadData that stores all tracking info generated |
340 // on this thread. This prevents the need for locking as data accumulates. | 345 // on this thread. This prevents the need for locking as data accumulates. |
341 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. | 346 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. |
342 // We also have a linked list of ThreadData instances, and that list is used to | 347 // We also have a linked list of ThreadData instances, and that list is used to |
343 // harvest data from all existing instances. | 348 // harvest data from all existing instances. |
344 | 349 |
| 350 struct ProcessDataPhaseSnapshot; |
345 struct ProcessDataSnapshot; | 351 struct ProcessDataSnapshot; |
346 class BASE_EXPORT TaskStopwatch; | 352 class BASE_EXPORT TaskStopwatch; |
347 | 353 |
| 354 // Map from profiling phase number to the process-wide snapshotted |
| 355 // representation of the list of ThreadData objects that died during the given |
| 356 // phase. |
| 357 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; |
| 358 |
348 class BASE_EXPORT ThreadData { | 359 class BASE_EXPORT ThreadData { |
349 public: | 360 public: |
350 // Current allowable states of the tracking system. The states can vary | 361 // Current allowable states of the tracking system. The states can vary |
351 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. | 362 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. |
352 enum Status { | 363 enum Status { |
353 UNINITIALIZED, // PRistine, link-time state before running. | 364 UNINITIALIZED, // PRistine, link-time state before running. |
354 DORMANT_DURING_TESTS, // Only used during testing. | 365 DORMANT_DURING_TESTS, // Only used during testing. |
355 DEACTIVATED, // No longer recording profiling. | 366 DEACTIVATED, // No longer recording profiling. |
356 PROFILING_ACTIVE, // Recording profiles (no parent-child links). | 367 PROFILING_ACTIVE, // Recording profiles (no parent-child links). |
357 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. | 368 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. |
(...skipping 11 matching lines...) Expand all Loading... |
369 // set *before* any births on the threads have taken place. It is generally | 380 // set *before* any births on the threads have taken place. It is generally |
370 // only used by the message loop, which has a well defined thread name. | 381 // only used by the message loop, which has a well defined thread name. |
371 static void InitializeThreadContext(const std::string& suggested_name); | 382 static void InitializeThreadContext(const std::string& suggested_name); |
372 | 383 |
373 // Using Thread Local Store, find the current instance for collecting data. | 384 // Using Thread Local Store, find the current instance for collecting data. |
374 // If an instance does not exist, construct one (and remember it for use on | 385 // If an instance does not exist, construct one (and remember it for use on |
375 // this thread. | 386 // this thread. |
376 // This may return NULL if the system is disabled for any reason. | 387 // This may return NULL if the system is disabled for any reason. |
377 static ThreadData* Get(); | 388 static ThreadData* Get(); |
378 | 389 |
379 // Fills |process_data| with all the recursive results in our process. | 390 // Fills |process_data_snapshot| with phased snapshots of all profiling |
380 static void Snapshot(ProcessDataSnapshot* process_data); | 391 // phases, including the current one. |
| 392 static void Snapshot(ProcessDataSnapshot* process_data_snapshot); |
381 | 393 |
382 // Finds (or creates) a place to count births from the given location in this | 394 // Finds (or creates) a place to count births from the given location in this |
383 // thread, and increment that tally. | 395 // thread, and increment that tally. |
384 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. | 396 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. |
385 static Births* TallyABirthIfActive(const Location& location); | 397 static Births* TallyABirthIfActive(const Location& location); |
386 | 398 |
387 // Records the end of a timed run of an object. The |completed_task| contains | 399 // Records the end of a timed run of an object. The |completed_task| contains |
388 // a pointer to a Births, the time_posted, and a delayed_start_time if any. | 400 // a pointer to a Births, the time_posted, and a delayed_start_time if any. |
389 // The |start_of_run| indicates when we started to perform the run of the | 401 // The |start_of_run| indicates when we started to perform the run of the |
390 // task. The delayed_start_time is non-null for tasks that were posted as | 402 // task. The delayed_start_time is non-null for tasks that were posted as |
391 // delayed tasks, and it indicates when the task should have run (i.e., when | 403 // delayed tasks, and it indicates when the task should have run (i.e., when |
392 // it should have posted out of the timer queue, and into the work queue. | 404 // it should have posted out of the timer queue, and into the work queue. |
393 // The |end_of_run| was just obtained by a call to Now() (just after the task | 405 // The |end_of_run| was just obtained by a call to Now() (just after the task |
394 // finished). It is provided as an argument to help with testing. | 406 // finished). It is provided as an argument to help with testing. |
395 static void TallyRunOnNamedThreadIfTracking( | 407 static void TallyRunOnNamedThreadIfTracking( |
396 const base::TrackingInfo& completed_task, | 408 const base::TrackingInfo& completed_task, |
397 const TaskStopwatch& stopwatch); | 409 const TaskStopwatch& stopwatch); |
398 | 410 |
399 // Record the end of a timed run of an object. The |birth| is the record for | 411 // Record the end of a timed run of an object. The |birth| is the record for |
400 // the instance, the |time_posted| records that instant, which is presumed to | 412 // the instance, the |time_posted| records that instant, which is presumed to |
401 // be when the task was posted into a queue to run on a worker thread. | 413 // be when the task was posted into a queue to run on a worker thread. |
402 // The |start_of_run| is when the worker thread started to perform the run of | 414 // The |start_of_run| is when the worker thread started to perform the run of |
403 // the task. | 415 // the task. |
404 // The |end_of_run| was just obtained by a call to Now() (just after the task | 416 // The |end_of_run| was just obtained by a call to Now() (just after the task |
405 // finished). | 417 // finished). |
406 static void TallyRunOnWorkerThreadIfTracking( | 418 static void TallyRunOnWorkerThreadIfTracking(const Births* birth, |
407 const Births* birth, | 419 const TrackedTime& time_posted, |
408 const TrackedTime& time_posted, | 420 const TaskStopwatch& stopwatch); |
409 const TaskStopwatch& stopwatch); | |
410 | 421 |
411 // Record the end of execution in region, generally corresponding to a scope | 422 // Record the end of execution in region, generally corresponding to a scope |
412 // being exited. | 423 // being exited. |
413 static void TallyRunInAScopedRegionIfTracking( | 424 static void TallyRunInAScopedRegionIfTracking(const Births* birth, |
414 const Births* birth, | 425 const TaskStopwatch& stopwatch); |
415 const TaskStopwatch& stopwatch); | |
416 | 426 |
417 const std::string& thread_name() const { return thread_name_; } | 427 const std::string& thread_name() const { return thread_name_; } |
418 | 428 |
419 // Initializes all statics if needed (this initialization call should be made | 429 // Initializes all statics if needed (this initialization call should be made |
420 // while we are single threaded). Returns false if unable to initialize. | 430 // while we are single threaded). Returns false if unable to initialize. |
421 static bool Initialize(); | 431 static bool Initialize(); |
422 | 432 |
423 // Sets internal status_. | 433 // Sets internal status_. |
424 // If |status| is false, then status_ is set to DEACTIVATED. | 434 // If |status| is false, then status_ is set to DEACTIVATED. |
425 // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or | 435 // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 Births* TallyABirth(const Location& location); | 517 Births* TallyABirth(const Location& location); |
508 | 518 |
509 // Find a place to record a death on this thread. | 519 // Find a place to record a death on this thread. |
510 void TallyADeath(const Births& birth, | 520 void TallyADeath(const Births& birth, |
511 int32 queue_duration, | 521 int32 queue_duration, |
512 const TaskStopwatch& stopwatch); | 522 const TaskStopwatch& stopwatch); |
513 | 523 |
514 // Snapshot (under a lock) the profiled data for the tasks in each ThreadData | 524 // Snapshot (under a lock) the profiled data for the tasks in each ThreadData |
515 // instance. Also updates the |birth_counts| tally for each task to keep | 525 // instance. Also updates the |birth_counts| tally for each task to keep |
516 // track of the number of living instances of the task. | 526 // track of the number of living instances of the task. |
517 static void SnapshotAllExecutedTasks(ProcessDataSnapshot* process_data, | 527 static void SnapshotAllExecutedTasks( |
518 BirthCountMap* birth_counts); | 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); |
519 | 534 |
520 // Snapshots (under a lock) the profiled data for the tasks for this thread | 535 // Snapshots (under a lock) the profiled data for the tasks for this thread |
521 // and writes all of the executed tasks' data -- i.e. the data for the tasks | 536 // and writes all of the executed tasks' data -- i.e. the data for the tasks |
522 // with with entries in the death_map_ -- into |process_data|. Also updates | 537 // with with entries in the death_map_ -- into |process_data_phase|. Also |
523 // the |birth_counts| tally for each task to keep track of the number of | 538 // updates the |birth_counts| tally for each task to keep track of the number |
524 // living instances of the task -- that is, each task maps to the number of | 539 // of living instances of the task -- that is, each task maps to the number of |
525 // births for the task that have not yet been balanced by a death. | 540 // births for the task that have not yet been balanced by a death. |
526 void SnapshotExecutedTasks(ProcessDataSnapshot* process_data, | 541 void SnapshotExecutedTasks(ProcessDataPhaseSnapshot* process_data_phase, |
527 BirthCountMap* birth_counts); | 542 BirthCountMap* birth_counts); |
528 | 543 |
529 // Using our lock, make a copy of the specified maps. This call may be made | 544 // Using our lock, make a copy of the specified maps. This call may be made |
530 // on non-local threads, which necessitate the use of the lock to prevent | 545 // on non-local threads, which necessitate the use of the lock to prevent |
531 // the map(s) from being reallocated while they are copied. | 546 // the map(s) from being reallocated while they are copied. |
532 void SnapshotMaps(BirthMap* birth_map, | 547 void SnapshotMaps(BirthMap* birth_map, |
533 DeathMap* death_map, | 548 DeathMap* death_map, |
534 ParentChildSet* parent_child_set); | 549 ParentChildSet* parent_child_set); |
535 | 550 |
536 // This method is called by the TLS system when a thread terminates. | 551 // This method is called by the TLS system when a thread terminates. |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 ParentChildPairSnapshot(); | 755 ParentChildPairSnapshot(); |
741 explicit ParentChildPairSnapshot( | 756 explicit ParentChildPairSnapshot( |
742 const ThreadData::ParentChildPair& parent_child); | 757 const ThreadData::ParentChildPair& parent_child); |
743 ~ParentChildPairSnapshot(); | 758 ~ParentChildPairSnapshot(); |
744 | 759 |
745 BirthOnThreadSnapshot parent; | 760 BirthOnThreadSnapshot parent; |
746 BirthOnThreadSnapshot child; | 761 BirthOnThreadSnapshot child; |
747 }; | 762 }; |
748 | 763 |
749 //------------------------------------------------------------------------------ | 764 //------------------------------------------------------------------------------ |
750 // A snapshotted representation of the list of ThreadData objects for a process. | 765 // A snapshotted representation of the list of ThreadData objects for a process, |
| 766 // for a single profiling phase. |
| 767 |
| 768 struct BASE_EXPORT ProcessDataPhaseSnapshot { |
| 769 public: |
| 770 ProcessDataPhaseSnapshot(); |
| 771 ~ProcessDataPhaseSnapshot(); |
| 772 |
| 773 std::vector<TaskSnapshot> tasks; |
| 774 std::vector<ParentChildPairSnapshot> descendants; |
| 775 }; |
| 776 |
| 777 //------------------------------------------------------------------------------ |
| 778 // A snapshotted representation of the list of ThreadData objects for a process, |
| 779 // for all profiling phases, including the current one. |
751 | 780 |
752 struct BASE_EXPORT ProcessDataSnapshot { | 781 struct BASE_EXPORT ProcessDataSnapshot { |
753 public: | 782 public: |
754 ProcessDataSnapshot(); | 783 ProcessDataSnapshot(); |
755 ~ProcessDataSnapshot(); | 784 ~ProcessDataSnapshot(); |
756 | 785 |
757 std::vector<TaskSnapshot> tasks; | 786 PhasedProcessDataSnapshotMap phased_process_data_snapshots; |
758 std::vector<ParentChildPairSnapshot> descendants; | 787 base::ProcessId process_id; |
759 int process_id; | |
760 }; | 788 }; |
761 | 789 |
762 } // namespace tracked_objects | 790 } // namespace tracked_objects |
763 | 791 |
764 #endif // BASE_TRACKED_OBJECTS_H_ | 792 #endif // BASE_TRACKED_OBJECTS_H_ |
OLD | NEW |