Chromium Code Reviews| 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 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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_stopwatch_; | |
| 745 | |
| 746 #ifndef NDEBUG | |
| 747 // State of the stopwatch. Stopwatch is reusable, i.e. it can be started after | |
| 748 // it was stopped. | |
| 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* running_child_; | |
|
jar (doing other things)
2014/09/05 04:36:05
nit: Clean up names. This is really a backward li
vadimt
2014/09/05 20:25:55
Done.
| |
| 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 |