OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_TRACKED_OBJECTS_H_ | 5 #ifndef BASE_TRACKED_OBJECTS_H_ |
6 #define BASE_TRACKED_OBJECTS_H_ | 6 #define BASE_TRACKED_OBJECTS_H_ |
7 | 7 |
8 #include <map> | 8 #include <map> |
9 #include <set> | 9 #include <set> |
10 #include <stack> | 10 #include <stack> |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 }; | 345 }; |
346 | 346 |
347 //------------------------------------------------------------------------------ | 347 //------------------------------------------------------------------------------ |
348 // For each thread, we have a ThreadData that stores all tracking info generated | 348 // For each thread, we have a ThreadData that stores all tracking info generated |
349 // on this thread. This prevents the need for locking as data accumulates. | 349 // on this thread. This prevents the need for locking as data accumulates. |
350 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. | 350 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. |
351 // We also have a linked list of ThreadData instances, and that list is used to | 351 // We also have a linked list of ThreadData instances, and that list is used to |
352 // harvest data from all existing instances. | 352 // harvest data from all existing instances. |
353 | 353 |
354 struct ProcessDataSnapshot; | 354 struct ProcessDataSnapshot; |
| 355 class BASE_EXPORT TaskStopwatch; |
| 356 |
355 class BASE_EXPORT ThreadData { | 357 class BASE_EXPORT ThreadData { |
356 public: | 358 public: |
357 // Current allowable states of the tracking system. The states can vary | 359 // Current allowable states of the tracking system. The states can vary |
358 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. | 360 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. |
359 enum Status { | 361 enum Status { |
360 UNINITIALIZED, // PRistine, link-time state before running. | 362 UNINITIALIZED, // PRistine, link-time state before running. |
361 DORMANT_DURING_TESTS, // Only used during testing. | 363 DORMANT_DURING_TESTS, // Only used during testing. |
362 DEACTIVATED, // No longer recording profling. | 364 DEACTIVATED, // No longer recording profling. |
363 PROFILING_ACTIVE, // Recording profiles (no parent-child links). | 365 PROFILING_ACTIVE, // Recording profiles (no parent-child links). |
364 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. | 366 PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 // Records the end of a timed run of an object. The |completed_task| contains | 398 // Records the end of a timed run of an object. The |completed_task| contains |
397 // a pointer to a Births, the time_posted, and a delayed_start_time if any. | 399 // a pointer to a Births, the time_posted, and a delayed_start_time if any. |
398 // The |start_of_run| indicates when we started to perform the run of the | 400 // The |start_of_run| indicates when we started to perform the run of the |
399 // task. The delayed_start_time is non-null for tasks that were posted as | 401 // task. The delayed_start_time is non-null for tasks that were posted as |
400 // delayed tasks, and it indicates when the task should have run (i.e., when | 402 // delayed tasks, and it indicates when the task should have run (i.e., when |
401 // it should have posted out of the timer queue, and into the work queue. | 403 // it should have posted out of the timer queue, and into the work queue. |
402 // The |end_of_run| was just obtained by a call to Now() (just after the task | 404 // The |end_of_run| was just obtained by a call to Now() (just after the task |
403 // finished). It is provided as an argument to help with testing. | 405 // finished). It is provided as an argument to help with testing. |
404 static void TallyRunOnNamedThreadIfTracking( | 406 static void TallyRunOnNamedThreadIfTracking( |
405 const base::TrackingInfo& completed_task, | 407 const base::TrackingInfo& completed_task, |
406 const TrackedTime& start_of_run, | 408 const TaskStopwatch& stopwatch); |
407 const TrackedTime& end_of_run); | |
408 | 409 |
409 // Record the end of a timed run of an object. The |birth| is the record for | 410 // Record the end of a timed run of an object. The |birth| is the record for |
410 // the instance, the |time_posted| records that instant, which is presumed to | 411 // the instance, the |time_posted| records that instant, which is presumed to |
411 // be when the task was posted into a queue to run on a worker thread. | 412 // be when the task was posted into a queue to run on a worker thread. |
412 // The |start_of_run| is when the worker thread started to perform the run of | 413 // The |start_of_run| is when the worker thread started to perform the run of |
413 // the task. | 414 // the task. |
414 // The |end_of_run| was just obtained by a call to Now() (just after the task | 415 // The |end_of_run| was just obtained by a call to Now() (just after the task |
415 // finished). | 416 // finished). |
416 static void TallyRunOnWorkerThreadIfTracking( | 417 static void TallyRunOnWorkerThreadIfTracking( |
417 const Births* birth, | 418 const Births* birth, |
418 const TrackedTime& time_posted, | 419 const TrackedTime& time_posted, |
419 const TrackedTime& start_of_run, | 420 const TaskStopwatch& stopwatch); |
420 const TrackedTime& end_of_run); | |
421 | 421 |
422 // 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 |
423 // being exited. | 423 // being exited. |
424 static void TallyRunInAScopedRegionIfTracking( | 424 static void TallyRunInAScopedRegionIfTracking( |
425 const Births* birth, | 425 const Births* birth, |
426 const TrackedTime& start_of_run, | 426 const TaskStopwatch& stopwatch); |
427 const TrackedTime& end_of_run); | |
428 | 427 |
429 const std::string& thread_name() const { return thread_name_; } | 428 const std::string& thread_name() const { return thread_name_; } |
430 | 429 |
431 // Hack: asynchronously clear all birth counts and death tallies data values | 430 // Hack: asynchronously clear all birth counts and death tallies data values |
432 // in all ThreadData instances. The numerical (zeroing) part is done without | 431 // in all ThreadData instances. The numerical (zeroing) part is done without |
433 // use of a locks or atomics exchanges, and may (for int64 values) produce | 432 // use of a locks or atomics exchanges, and may (for int64 values) produce |
434 // bogus counts VERY rarely. | 433 // bogus counts VERY rarely. |
435 static void ResetAllThreadData(); | 434 static void ResetAllThreadData(); |
436 | 435 |
437 // Initializes all statics if needed (this initialization call should be made | 436 // Initializes all statics if needed (this initialization call should be made |
(...skipping 15 matching lines...) Expand all Loading... |
453 static Status status(); | 452 static Status status(); |
454 | 453 |
455 // Indicate if any sort of profiling is being done (i.e., we are more than | 454 // Indicate if any sort of profiling is being done (i.e., we are more than |
456 // DEACTIVATED). | 455 // DEACTIVATED). |
457 static bool TrackingStatus(); | 456 static bool TrackingStatus(); |
458 | 457 |
459 // For testing only, indicate if the status of parent-child tracking is turned | 458 // For testing only, indicate if the status of parent-child tracking is turned |
460 // on. This is currently a compiled option, atop TrackingStatus(). | 459 // on. This is currently a compiled option, atop TrackingStatus(). |
461 static bool TrackingParentChildStatus(); | 460 static bool TrackingParentChildStatus(); |
462 | 461 |
463 // Special versions of Now() for getting times at start and end of a tracked | 462 // Marks a start of a tracked run. It's super fast when tracking is disabled, |
464 // run. They are super fast when tracking is disabled, and have some internal | 463 // and has some internal side effects when we are tracking, so that we can |
465 // side effects when we are tracking, so that we can deduce the amount of time | 464 // deduce the amount of time accumulated outside of execution of tracked runs. |
466 // accumulated outside of execution of tracked runs. | |
467 // The task that will be tracked is passed in as |parent| so that parent-child | 465 // The task that will be tracked is passed in as |parent| so that parent-child |
468 // relationships can be (optionally) calculated. | 466 // relationships can be (optionally) calculated. |
469 static TrackedTime NowForStartOfRun(const Births* parent); | 467 static void PrepareForStartOfRun(const Births* parent); |
470 static TrackedTime NowForEndOfRun(); | |
471 | 468 |
472 // Provide a time function that does nothing (runs fast) when we don't have | 469 // Provide a time function that does nothing (runs fast) when we don't have |
473 // the profiler enabled. It will generally be optimized away when it is | 470 // the profiler enabled. It will generally be optimized away when it is |
474 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of | 471 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of |
475 // the code). | 472 // the code). |
476 static TrackedTime Now(); | 473 static TrackedTime Now(); |
477 | 474 |
478 // Use the function |now| to provide current times, instead of calling the | 475 // Use the function |now| to provide current times, instead of calling the |
479 // TrackedTime::Now() function. Since this alternate function is being used, | 476 // TrackedTime::Now() function. Since this alternate function is being used, |
480 // the other time arguments (used for calculating queueing delay) will be | 477 // the other time arguments (used for calculating queueing delay) will be |
481 // ignored. | 478 // ignored. |
482 static void SetAlternateTimeSource(NowFunction* now); | 479 static void SetAlternateTimeSource(NowFunction* now); |
483 | 480 |
484 // This function can be called at process termination to validate that thread | 481 // This function can be called at process termination to validate that thread |
485 // cleanup routines have been called for at least some number of named | 482 // cleanup routines have been called for at least some number of named |
486 // threads. | 483 // threads. |
487 static void EnsureCleanupWasCalled(int major_threads_shutdown_count); | 484 static void EnsureCleanupWasCalled(int major_threads_shutdown_count); |
488 | 485 |
489 private: | 486 private: |
| 487 friend class TaskStopwatch; |
490 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it | 488 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it |
491 // in production code. | 489 // in production code. |
492 // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a | 490 // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a |
493 // better change of optimizing (inlining? etc.) private methods (knowing that | 491 // better change of optimizing (inlining? etc.) private methods (knowing that |
494 // there will be no need for an external entry point). | 492 // there will be no need for an external entry point). |
495 friend class TrackedObjectsTest; | 493 friend class TrackedObjectsTest; |
496 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); | 494 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); |
497 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); | 495 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
498 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest); | 496 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest); |
499 | 497 |
(...skipping 16 matching lines...) Expand all Loading... |
516 static ThreadData* first(); | 514 static ThreadData* first(); |
517 | 515 |
518 // Iterate through the null terminated list of ThreadData instances. | 516 // Iterate through the null terminated list of ThreadData instances. |
519 ThreadData* next() const; | 517 ThreadData* next() const; |
520 | 518 |
521 | 519 |
522 // In this thread's data, record a new birth. | 520 // In this thread's data, record a new birth. |
523 Births* TallyABirth(const Location& location); | 521 Births* TallyABirth(const Location& location); |
524 | 522 |
525 // Find a place to record a death on this thread. | 523 // Find a place to record a death on this thread. |
526 void TallyADeath(const Births& birth, int32 queue_duration, int32 duration); | 524 void TallyADeath(const Births& birth, |
| 525 int32 queue_duration, |
| 526 const TaskStopwatch& stopwatch); |
527 | 527 |
528 // Snapshot (under a lock) the profiled data for the tasks in each ThreadData | 528 // Snapshot (under a lock) the profiled data for the tasks in each ThreadData |
529 // instance. Also updates the |birth_counts| tally for each task to keep | 529 // instance. Also updates the |birth_counts| tally for each task to keep |
530 // track of the number of living instances of the task. If |reset_max| is | 530 // track of the number of living instances of the task. If |reset_max| is |
531 // true, then the max values in each DeathData instance are reset during the | 531 // true, then the max values in each DeathData instance are reset during the |
532 // scan. | 532 // scan. |
533 static void SnapshotAllExecutedTasks(bool reset_max, | 533 static void SnapshotAllExecutedTasks(bool reset_max, |
534 ProcessDataSnapshot* process_data, | 534 ProcessDataSnapshot* process_data, |
535 BirthCountMap* birth_counts); | 535 BirthCountMap* birth_counts); |
536 | 536 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 // threads since the time that InitializeAndSetTrackingStatus() was called, | 575 // threads since the time that InitializeAndSetTrackingStatus() was called, |
576 // then you can pass in a |leak| value of false, and this function will | 576 // then you can pass in a |leak| value of false, and this function will |
577 // delete recursively all data structures, starting with the list of | 577 // delete recursively all data structures, starting with the list of |
578 // ThreadData instances. | 578 // ThreadData instances. |
579 static void ShutdownSingleThreadedCleanup(bool leak); | 579 static void ShutdownSingleThreadedCleanup(bool leak); |
580 | 580 |
581 // When non-null, this specifies an external function that supplies monotone | 581 // When non-null, this specifies an external function that supplies monotone |
582 // increasing time functcion. | 582 // increasing time functcion. |
583 static NowFunction* now_function_; | 583 static NowFunction* now_function_; |
584 | 584 |
| 585 // If true, now_function_ returns values that can be used to calculate queue |
| 586 // time. |
| 587 static bool now_function_is_time_; |
| 588 |
585 // We use thread local store to identify which ThreadData to interact with. | 589 // We use thread local store to identify which ThreadData to interact with. |
586 static base::ThreadLocalStorage::StaticSlot tls_index_; | 590 static base::ThreadLocalStorage::StaticSlot tls_index_; |
587 | 591 |
588 // List of ThreadData instances for use with worker threads. When a worker | 592 // List of ThreadData instances for use with worker threads. When a worker |
589 // thread is done (terminated), we push it onto this llist. When a new worker | 593 // thread is done (terminated), we push it onto this llist. When a new worker |
590 // thread is created, we first try to re-use a ThreadData instance from the | 594 // thread is created, we first try to re-use a ThreadData instance from the |
591 // list, and if none are available, construct a new one. | 595 // list, and if none are available, construct a new one. |
592 // This is only accessed while list_lock_ is held. | 596 // This is only accessed while list_lock_ is held. |
593 static ThreadData* first_retired_worker_; | 597 static ThreadData* first_retired_worker_; |
594 | 598 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 | 662 |
659 // Lock to protect *some* access to BirthMap and DeathMap. The maps are | 663 // Lock to protect *some* access to BirthMap and DeathMap. The maps are |
660 // regularly read and written on this thread, but may only be read from other | 664 // regularly read and written on this thread, but may only be read from other |
661 // threads. To support this, we acquire this lock if we are writing from this | 665 // threads. To support this, we acquire this lock if we are writing from this |
662 // thread, or reading from another thread. For reading from this thread we | 666 // thread, or reading from another thread. For reading from this thread we |
663 // don't need a lock, as there is no potential for a conflict since the | 667 // don't need a lock, as there is no potential for a conflict since the |
664 // writing is only done from this thread. | 668 // writing is only done from this thread. |
665 mutable base::Lock map_lock_; | 669 mutable base::Lock map_lock_; |
666 | 670 |
667 // The stack of parents that are currently being profiled. This includes only | 671 // The stack of parents that are currently being profiled. This includes only |
668 // tasks that have started a timer recently via NowForStartOfRun(), but not | 672 // tasks that have started a timer recently via PrepareForStartOfRun(), but |
669 // yet concluded with a NowForEndOfRun(). Usually this stack is one deep, but | 673 // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep, |
670 // if a scoped region is profiled, or <sigh> a task runs a nested-message | 674 // but if a scoped region is profiled, or <sigh> a task runs a nested-message |
671 // loop, then the stack can grow larger. Note that we don't try to deduct | 675 // loop, then the stack can grow larger. Note that we don't try to deduct |
672 // time in nested porfiles, as our current timer is based on wall-clock time, | 676 // time in nested porfiles, as our current timer is based on wall-clock time, |
673 // and not CPU time (and we're hopeful that nested timing won't be a | 677 // and not CPU time (and we're hopeful that nested timing won't be a |
674 // significant additional cost). | 678 // significant additional cost). |
675 ParentStack parent_stack_; | 679 ParentStack parent_stack_; |
676 | 680 |
677 // A random number that we used to select decide which sample to keep as a | 681 // A random number that we used to select decide which sample to keep as a |
678 // representative sample in each DeathData instance. We can't start off with | 682 // representative sample in each DeathData instance. We can't start off with |
679 // much randomness (because we can't call RandInt() on all our threads), so | 683 // much randomness (because we can't call RandInt() on all our threads), so |
680 // we stir in more and more as we go. | 684 // we stir in more and more as we go. |
681 int32 random_number_; | 685 int32 random_number_; |
682 | 686 |
683 // Record of what the incarnation_counter_ was when this instance was created. | 687 // Record of what the incarnation_counter_ was when this instance was created. |
684 // If the incarnation_counter_ has changed, then we avoid pushing into the | 688 // If the incarnation_counter_ has changed, then we avoid pushing into the |
685 // pool (this is only critical in tests which go through multiple | 689 // pool (this is only critical in tests which go through multiple |
686 // incarnations). | 690 // incarnations). |
687 int incarnation_count_for_pool_; | 691 int incarnation_count_for_pool_; |
688 | 692 |
| 693 // Most recently started (i.e. most nested) stopwatch on the current thread, |
| 694 // if it exists; NULL otherwise. |
| 695 TaskStopwatch* current_stopwatch_; |
| 696 |
689 DISALLOW_COPY_AND_ASSIGN(ThreadData); | 697 DISALLOW_COPY_AND_ASSIGN(ThreadData); |
690 }; | 698 }; |
691 | 699 |
692 //------------------------------------------------------------------------------ | 700 //------------------------------------------------------------------------------ |
| 701 // Stopwatch to measure task run time or simply create a time interval that will |
| 702 // be subtracted from the current most nested task's run time. Stopwatches |
| 703 // coordinate with the stopwatches in which they are nested to avoid |
| 704 // double-counting nested tasks run times. |
| 705 |
| 706 class BASE_EXPORT TaskStopwatch { |
| 707 public: |
| 708 // Starts the stopwatch. |
| 709 TaskStopwatch(); |
| 710 ~TaskStopwatch(); |
| 711 |
| 712 // Stops stopwatch. |
| 713 void Stop(); |
| 714 |
| 715 // Returns the start time. |
| 716 TrackedTime StartTime() const; |
| 717 |
| 718 // Task's duration is calculated as the wallclock duration between starting |
| 719 // and stopping this stopwatch, minus the wallclock durations of any other |
| 720 // instances that are immediately nested in this one, started and stopped on |
| 721 // this thread during that period. |
| 722 int32 RunDurationMs() const; |
| 723 |
| 724 // Returns tracking info for the current thread. |
| 725 ThreadData* GetThreadData() const; |
| 726 |
| 727 private: |
| 728 // Time when the stopwatch was started. |
| 729 TrackedTime start_time_; |
| 730 |
| 731 // Wallclock duration of the task. |
| 732 int32 wallclock_duration_ms_; |
| 733 |
| 734 // Tracking info for the current thread. |
| 735 ThreadData* current_thread_data_; |
| 736 |
| 737 // Sum of wallclock durations of all stopwatches that were directly nested in |
| 738 // this one. |
| 739 int32 excluded_duration_ms_; |
| 740 |
| 741 // Stopwatch which was running on our thread when this stopwatch was started. |
| 742 // That preexisting stopwatch must be adjusted to the exclude the wallclock |
| 743 // duration of this stopwatch. |
| 744 TaskStopwatch* parent_; |
| 745 |
| 746 #if DCHECK_IS_ON |
| 747 // State of the stopwatch. Stopwatch is first constructed in a running state, |
| 748 // then stopped, then destructed. |
| 749 enum { |
| 750 RUNNING, |
| 751 STOPPED |
| 752 } state_; |
| 753 |
| 754 // Currently running stopwatch that is directly nested in this one, if such |
| 755 // stopwatch exists. NULL otherwise. |
| 756 TaskStopwatch* child_; |
| 757 #endif |
| 758 }; |
| 759 |
| 760 //------------------------------------------------------------------------------ |
693 // A snapshotted representation of a (parent, child) task pair, for tracking | 761 // A snapshotted representation of a (parent, child) task pair, for tracking |
694 // hierarchical profiles. | 762 // hierarchical profiles. |
695 | 763 |
696 struct BASE_EXPORT ParentChildPairSnapshot { | 764 struct BASE_EXPORT ParentChildPairSnapshot { |
697 public: | 765 public: |
698 ParentChildPairSnapshot(); | 766 ParentChildPairSnapshot(); |
699 explicit ParentChildPairSnapshot( | 767 explicit ParentChildPairSnapshot( |
700 const ThreadData::ParentChildPair& parent_child); | 768 const ThreadData::ParentChildPair& parent_child); |
701 ~ParentChildPairSnapshot(); | 769 ~ParentChildPairSnapshot(); |
702 | 770 |
(...skipping 10 matching lines...) Expand all Loading... |
713 ~ProcessDataSnapshot(); | 781 ~ProcessDataSnapshot(); |
714 | 782 |
715 std::vector<TaskSnapshot> tasks; | 783 std::vector<TaskSnapshot> tasks; |
716 std::vector<ParentChildPairSnapshot> descendants; | 784 std::vector<ParentChildPairSnapshot> descendants; |
717 int process_id; | 785 int process_id; |
718 }; | 786 }; |
719 | 787 |
720 } // namespace tracked_objects | 788 } // namespace tracked_objects |
721 | 789 |
722 #endif // BASE_TRACKED_OBJECTS_H_ | 790 #endif // BASE_TRACKED_OBJECTS_H_ |
OLD | NEW |