Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: base/tracked_objects.h

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

Powered by Google App Engine
This is Rietveld 408576698