| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef BASE_TRACKED_OBJECTS_H_ | |
| 6 #define BASE_TRACKED_OBJECTS_H_ | |
| 7 | |
| 8 #include <map> | |
| 9 #include <set> | |
| 10 #include <stack> | |
| 11 #include <string> | |
| 12 #include <utility> | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "base/base_export.h" | |
| 16 #include "base/basictypes.h" | |
| 17 #include "base/containers/hash_tables.h" | |
| 18 #include "base/gtest_prod_util.h" | |
| 19 #include "base/lazy_instance.h" | |
| 20 #include "base/location.h" | |
| 21 #include "base/process/process_handle.h" | |
| 22 #include "base/profiler/alternate_timer.h" | |
| 23 #include "base/profiler/tracked_time.h" | |
| 24 #include "base/synchronization/lock.h" | |
| 25 #include "base/threading/thread_checker.h" | |
| 26 #include "base/threading/thread_local_storage.h" | |
| 27 | |
| 28 namespace base { | |
| 29 struct TrackingInfo; | |
| 30 } | |
| 31 | |
| 32 // TrackedObjects provides a database of stats about objects (generally Tasks) | |
| 33 // that are tracked. Tracking means their birth, death, duration, birth thread, | |
| 34 // death thread, and birth place are recorded. This data is carefully spread | |
| 35 // across a series of objects so that the counts and times can be rapidly | |
| 36 // updated without (usually) having to lock the data, and hence there is usually | |
| 37 // very little contention caused by the tracking. The data can be viewed via | |
| 38 // the about:profiler URL, with a variety of sorting and filtering choices. | |
| 39 // | |
| 40 // These classes serve as the basis of a profiler of sorts for the Tasks system. | |
| 41 // As a result, design decisions were made to maximize speed, by minimizing | |
| 42 // recurring allocation/deallocation, lock contention and data copying. In the | |
| 43 // "stable" state, which is reached relatively quickly, there is no separate | |
| 44 // marginal allocation cost associated with construction or destruction of | |
| 45 // tracked objects, no locks are generally employed, and probably the largest | |
| 46 // computational cost is associated with obtaining start and stop times for | |
| 47 // instances as they are created and destroyed. | |
| 48 // | |
| 49 // The following describes the life cycle of tracking an instance. | |
| 50 // | |
| 51 // First off, when the instance is created, the FROM_HERE macro is expanded | |
| 52 // to specify the birth place (file, line, function) where the instance was | |
| 53 // created. That data is used to create a transient Location instance | |
| 54 // encapsulating the above triple of information. The strings (like __FILE__) | |
| 55 // are passed around by reference, with the assumption that they are static, and | |
| 56 // will never go away. This ensures that the strings can be dealt with as atoms | |
| 57 // with great efficiency (i.e., copying of strings is never needed, and | |
| 58 // comparisons for equality can be based on pointer comparisons). | |
| 59 // | |
| 60 // Next, a Births instance is created for use ONLY on the thread where this | |
| 61 // instance was created. That Births instance records (in a base class | |
| 62 // BirthOnThread) references to the static data provided in a Location instance, | |
| 63 // as well as a pointer specifying the thread on which the birth takes place. | |
| 64 // Hence there is at most one Births instance for each Location on each thread. | |
| 65 // The derived Births class contains slots for recording statistics about all | |
| 66 // instances born at the same location. Statistics currently include only the | |
| 67 // count of instances constructed. | |
| 68 // | |
| 69 // Since the base class BirthOnThread contains only constant data, it can be | |
| 70 // freely accessed by any thread at any time (i.e., only the statistic needs to | |
| 71 // be handled carefully, and stats are updated exclusively on the birth thread). | |
| 72 // | |
| 73 // For Tasks, having now either constructed or found the Births instance | |
| 74 // described above, a pointer to the Births instance is then recorded into the | |
| 75 // PendingTask structure in MessageLoop. This fact alone is very useful in | |
| 76 // debugging, when there is a question of where an instance came from. In | |
| 77 // addition, the birth time is also recorded and used to later evaluate the | |
| 78 // lifetime duration of the whole Task. As a result of the above embedding, we | |
| 79 // can find out a Task's location of birth, and thread of birth, without using | |
| 80 // any locks, as all that data is constant across the life of the process. | |
| 81 // | |
| 82 // The above work *could* also be done for any other object as well by calling | |
| 83 // TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate. | |
| 84 // | |
| 85 // The amount of memory used in the above data structures depends on how many | |
| 86 // threads there are, and how many Locations of construction there are. | |
| 87 // Fortunately, we don't use memory that is the product of those two counts, but | |
| 88 // rather we only need one Births instance for each thread that constructs an | |
| 89 // instance at a Location. In many cases, instances are only created on one | |
| 90 // thread, so the memory utilization is actually fairly restrained. | |
| 91 // | |
| 92 // Lastly, when an instance is deleted, the final tallies of statistics are | |
| 93 // carefully accumulated. That tallying writes into slots (members) in a | |
| 94 // collection of DeathData instances. For each birth place Location that is | |
| 95 // destroyed on a thread, there is a DeathData instance to record the additional | |
| 96 // death count, as well as accumulate the run-time and queue-time durations for | |
| 97 // the instance as it is destroyed (dies). By maintaining a single place to | |
| 98 // aggregate this running sum *only* for the given thread, we avoid the need to | |
| 99 // lock such DeathData instances. (i.e., these accumulated stats in a DeathData | |
| 100 // instance are exclusively updated by the singular owning thread). | |
| 101 // | |
| 102 // With the above life cycle description complete, the major remaining detail | |
| 103 // is explaining how each thread maintains a list of DeathData instances, and | |
| 104 // of Births instances, and is able to avoid additional (redundant/unnecessary) | |
| 105 // allocations. | |
| 106 // | |
| 107 // Each thread maintains a list of data items specific to that thread in a | |
| 108 // ThreadData instance (for that specific thread only). The two critical items | |
| 109 // are lists of DeathData and Births instances. These lists are maintained in | |
| 110 // STL maps, which are indexed by Location. As noted earlier, we can compare | |
| 111 // locations very efficiently as we consider the underlying data (file, | |
| 112 // function, line) to be atoms, and hence pointer comparison is used rather than | |
| 113 // (slow) string comparisons. | |
| 114 // | |
| 115 // To provide a mechanism for iterating over all "known threads," which means | |
| 116 // threads that have recorded a birth or a death, we create a singly linked list | |
| 117 // of ThreadData instances. Each such instance maintains a pointer to the next | |
| 118 // one. A static member of ThreadData provides a pointer to the first item on | |
| 119 // this global list, and access via that all_thread_data_list_head_ item | |
| 120 // requires the use of the list_lock_. | |
| 121 // When new ThreadData instances is added to the global list, it is pre-pended, | |
| 122 // which ensures that any prior acquisition of the list is valid (i.e., the | |
| 123 // holder can iterate over it without fear of it changing, or the necessity of | |
| 124 // using an additional lock. Iterations are actually pretty rare (used | |
| 125 // primarily for cleanup, or snapshotting data for display), so this lock has | |
| 126 // very little global performance impact. | |
| 127 // | |
| 128 // The above description tries to define the high performance (run time) | |
| 129 // portions of these classes. After gathering statistics, calls instigated | |
| 130 // by visiting about:profiler will assemble and aggregate data for display. The | |
| 131 // following data structures are used for producing such displays. They are | |
| 132 // not performance critical, and their only major constraint is that they should | |
| 133 // be able to run concurrently with ongoing augmentation of the birth and death | |
| 134 // data. | |
| 135 // | |
| 136 // This header also exports collection of classes that provide "snapshotted" | |
| 137 // representations of the core tracked_objects:: classes. These snapshotted | |
| 138 // representations are designed for safe transmission of the tracked_objects:: | |
| 139 // data across process boundaries. Each consists of: | |
| 140 // (1) a default constructor, to support the IPC serialization macros, | |
| 141 // (2) a constructor that extracts data from the type being snapshotted, and | |
| 142 // (3) the snapshotted data. | |
| 143 // | |
| 144 // For a given birth location, information about births is spread across data | |
| 145 // structures that are asynchronously changing on various threads. For | |
| 146 // serialization and display purposes, we need to construct TaskSnapshot | |
| 147 // instances for each combination of birth thread, death thread, and location, | |
| 148 // along with the count of such lifetimes. We gather such data into a | |
| 149 // TaskSnapshot instances, so that such instances can be sorted and | |
| 150 // aggregated (and remain frozen during our processing). | |
| 151 // | |
| 152 // Profiling consists of phases. The concrete phase in the sequence of phases | |
| 153 // is identified by its 0-based index. | |
| 154 // | |
| 155 // The ProcessDataPhaseSnapshot struct is a serialized representation of the | |
| 156 // list of ThreadData objects for a process for a concrete profiling phase. It | |
| 157 // holds a set of TaskSnapshots. The statistics in a snapshot are gathered | |
| 158 // asynhcronously relative to their ongoing updates. | |
| 159 // It is possible, though highly unlikely, that stats could be incorrectly | |
| 160 // recorded by this process (all data is held in 32 bit ints, but we are not | |
| 161 // atomically collecting all data, so we could have count that does not, for | |
| 162 // example, match with the number of durations we accumulated). The advantage | |
| 163 // to having fast (non-atomic) updates of the data outweighs the minimal risk of | |
| 164 // a singular corrupt statistic snapshot (only the snapshot could be corrupt, | |
| 165 // not the underlying and ongoing statistic). In contrast, pointer data that | |
| 166 // is accessed during snapshotting is completely invariant, and hence is | |
| 167 // perfectly acquired (i.e., no potential corruption, and no risk of a bad | |
| 168 // memory reference). | |
| 169 // | |
| 170 // TODO(jar): We can implement a Snapshot system that *tries* to grab the | |
| 171 // snapshots on the source threads *when* they have MessageLoops available | |
| 172 // (worker threads don't have message loops generally, and hence gathering from | |
| 173 // them will continue to be asynchronous). We had an implementation of this in | |
| 174 // the past, but the difficulty is dealing with message loops being terminated. | |
| 175 // We can *try* to spam the available threads via some message loop proxy to | |
| 176 // achieve this feat, and it *might* be valuable when we are collecting data | |
| 177 // for upload via UMA (where correctness of data may be more significant than | |
| 178 // for a single screen of about:profiler). | |
| 179 // | |
| 180 // TODO(jar): We need to store DataCollections, and provide facilities for | |
| 181 // taking the difference between two gathered DataCollections. For now, we're | |
| 182 // just adding a hack that Reset()s to zero all counts and stats. This is also | |
| 183 // done in a slightly thread-unsafe fashion, as the resetting is done | |
| 184 // asynchronously relative to ongoing updates (but all data is 32 bit in size). | |
| 185 // For basic profiling, this will work "most of the time," and should be | |
| 186 // sufficient... but storing away DataCollections is the "right way" to do this. | |
| 187 // We'll accomplish this via JavaScript storage of snapshots, and then we'll | |
| 188 // remove the Reset() methods. We may also need a short-term-max value in | |
| 189 // DeathData that is reset (as synchronously as possible) during each snapshot. | |
| 190 // This will facilitate displaying a max value for each snapshot period. | |
| 191 | |
| 192 namespace tracked_objects { | |
| 193 | |
| 194 //------------------------------------------------------------------------------ | |
| 195 // For a specific thread, and a specific birth place, the collection of all | |
| 196 // death info (with tallies for each death thread, to prevent access conflicts). | |
| 197 class ThreadData; | |
| 198 class BASE_EXPORT BirthOnThread { | |
| 199 public: | |
| 200 BirthOnThread(const Location& location, const ThreadData& current); | |
| 201 | |
| 202 const Location location() const { return location_; } | |
| 203 const ThreadData* birth_thread() const { return birth_thread_; } | |
| 204 | |
| 205 private: | |
| 206 // File/lineno of birth. This defines the essence of the task, as the context | |
| 207 // of the birth (construction) often tell what the item is for. This field | |
| 208 // is const, and hence safe to access from any thread. | |
| 209 const Location location_; | |
| 210 | |
| 211 // The thread that records births into this object. Only this thread is | |
| 212 // allowed to update birth_count_ (which changes over time). | |
| 213 const ThreadData* const birth_thread_; | |
| 214 | |
| 215 DISALLOW_COPY_AND_ASSIGN(BirthOnThread); | |
| 216 }; | |
| 217 | |
| 218 //------------------------------------------------------------------------------ | |
| 219 // A "snapshotted" representation of the BirthOnThread class. | |
| 220 | |
| 221 struct BASE_EXPORT BirthOnThreadSnapshot { | |
| 222 BirthOnThreadSnapshot(); | |
| 223 explicit BirthOnThreadSnapshot(const BirthOnThread& birth); | |
| 224 ~BirthOnThreadSnapshot(); | |
| 225 | |
| 226 LocationSnapshot location; | |
| 227 std::string thread_name; | |
| 228 }; | |
| 229 | |
| 230 //------------------------------------------------------------------------------ | |
| 231 // A class for accumulating counts of births (without bothering with a map<>). | |
| 232 | |
| 233 class BASE_EXPORT Births: public BirthOnThread { | |
| 234 public: | |
| 235 Births(const Location& location, const ThreadData& current); | |
| 236 | |
| 237 int birth_count() const; | |
| 238 | |
| 239 // When we have a birth we update the count for this birthplace. | |
| 240 void RecordBirth(); | |
| 241 | |
| 242 private: | |
| 243 // The number of births on this thread for our location_. | |
| 244 int birth_count_; | |
| 245 | |
| 246 DISALLOW_COPY_AND_ASSIGN(Births); | |
| 247 }; | |
| 248 | |
| 249 //------------------------------------------------------------------------------ | |
| 250 // A "snapshotted" representation of the DeathData class. | |
| 251 | |
| 252 struct BASE_EXPORT DeathDataSnapshot { | |
| 253 DeathDataSnapshot(); | |
| 254 | |
| 255 // Constructs the snapshot from individual values. | |
| 256 // The alternative would be taking a DeathData parameter, but this would | |
| 257 // create a loop since DeathData indirectly refers DeathDataSnapshot. Passing | |
| 258 // a wrapper structure as a param or using an empty constructor for | |
| 259 // snapshotting DeathData would be less efficient. | |
| 260 DeathDataSnapshot(int count, | |
| 261 int32 run_duration_sum, | |
| 262 int32 run_duration_max, | |
| 263 int32 run_duration_sample, | |
| 264 int32 queue_duration_sum, | |
| 265 int32 queue_duration_max, | |
| 266 int32 queue_duration_sample); | |
| 267 ~DeathDataSnapshot(); | |
| 268 | |
| 269 // Calculates and returns the delta between this snapshot and an earlier | |
| 270 // snapshot of the same task |older|. | |
| 271 DeathDataSnapshot Delta(const DeathDataSnapshot& older) const; | |
| 272 | |
| 273 int count; | |
| 274 int32 run_duration_sum; | |
| 275 int32 run_duration_max; | |
| 276 int32 run_duration_sample; | |
| 277 int32 queue_duration_sum; | |
| 278 int32 queue_duration_max; | |
| 279 int32 queue_duration_sample; | |
| 280 }; | |
| 281 | |
| 282 //------------------------------------------------------------------------------ | |
| 283 // A "snapshotted" representation of the DeathData for a particular profiling | |
| 284 // phase. Used as an element of the list of phase snapshots owned by DeathData. | |
| 285 | |
| 286 struct DeathDataPhaseSnapshot { | |
| 287 DeathDataPhaseSnapshot(int profiling_phase, | |
| 288 int count, | |
| 289 int32 run_duration_sum, | |
| 290 int32 run_duration_max, | |
| 291 int32 run_duration_sample, | |
| 292 int32 queue_duration_sum, | |
| 293 int32 queue_duration_max, | |
| 294 int32 queue_duration_sample, | |
| 295 const DeathDataPhaseSnapshot* prev); | |
| 296 | |
| 297 // Profiling phase at which completion this snapshot was taken. | |
| 298 int profiling_phase; | |
| 299 | |
| 300 // Death data snapshot. | |
| 301 DeathDataSnapshot death_data; | |
| 302 | |
| 303 // Pointer to a snapshot from the previous phase. | |
| 304 const DeathDataPhaseSnapshot* prev; | |
| 305 }; | |
| 306 | |
| 307 //------------------------------------------------------------------------------ | |
| 308 // Information about deaths of a task on a given thread, called "death thread". | |
| 309 // Access to members of this class is never protected by a lock. The fields | |
| 310 // are accessed in such a way that corruptions resulting from race conditions | |
| 311 // are not significant, and don't accumulate as a result of multiple accesses. | |
| 312 // All invocations of DeathData::OnProfilingPhaseCompleted and | |
| 313 // ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process | |
| 314 // must be called from the same thread. It doesn't matter what thread it is, but | |
| 315 // it's important the same thread is used as a snapshot thread during the whole | |
| 316 // process lifetime. All fields except sample_probability_count_ can be | |
| 317 // snapshotted. | |
| 318 | |
| 319 class BASE_EXPORT DeathData { | |
| 320 public: | |
| 321 DeathData(); | |
| 322 DeathData(const DeathData& other); | |
| 323 ~DeathData(); | |
| 324 | |
| 325 // Update stats for a task destruction (death) that had a Run() time of | |
| 326 // |duration|, and has had a queueing delay of |queue_duration|. | |
| 327 void RecordDeath(const int32 queue_duration, | |
| 328 const int32 run_duration, | |
| 329 const uint32 random_number); | |
| 330 | |
| 331 // Metrics and past snapshots accessors, used only for serialization and in | |
| 332 // tests. | |
| 333 int count() const { return count_; } | |
| 334 int32 run_duration_sum() const { return run_duration_sum_; } | |
| 335 int32 run_duration_max() const { return run_duration_max_; } | |
| 336 int32 run_duration_sample() const { return run_duration_sample_; } | |
| 337 int32 queue_duration_sum() const { return queue_duration_sum_; } | |
| 338 int32 queue_duration_max() const { return queue_duration_max_; } | |
| 339 int32 queue_duration_sample() const { return queue_duration_sample_; } | |
| 340 const DeathDataPhaseSnapshot* last_phase_snapshot() const { | |
| 341 return last_phase_snapshot_; | |
| 342 } | |
| 343 | |
| 344 // Called when the current profiling phase, identified by |profiling_phase|, | |
| 345 // ends. | |
| 346 // Must be called only on the snapshot thread. | |
| 347 void OnProfilingPhaseCompleted(int profiling_phase); | |
| 348 | |
| 349 private: | |
| 350 // Members are ordered from most regularly read and updated, to least | |
| 351 // frequently used. This might help a bit with cache lines. | |
| 352 // Number of runs seen (divisor for calculating averages). | |
| 353 // Can be incremented only on the death thread. | |
| 354 int count_; | |
| 355 | |
| 356 // Count used in determining probability of selecting exec/queue times from a | |
| 357 // recorded death as samples. | |
| 358 // Gets incremented only on the death thread, but can be set to 0 by | |
| 359 // OnProfilingPhaseCompleted() on the snapshot thread. | |
| 360 int sample_probability_count_; | |
| 361 | |
| 362 // Basic tallies, used to compute averages. Can be incremented only on the | |
| 363 // death thread. | |
| 364 int32 run_duration_sum_; | |
| 365 int32 queue_duration_sum_; | |
| 366 // Max values, used by local visualization routines. These are often read, | |
| 367 // but rarely updated. The max values get assigned only on the death thread, | |
| 368 // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the | |
| 369 // snapshot thread. | |
| 370 int32 run_duration_max_; | |
| 371 int32 queue_duration_max_; | |
| 372 // Samples, used by crowd sourcing gatherers. These are almost never read, | |
| 373 // and rarely updated. They can be modified only on the death thread. | |
| 374 int32 run_duration_sample_; | |
| 375 int32 queue_duration_sample_; | |
| 376 | |
| 377 // Snapshot of this death data made at the last profiling phase completion, if | |
| 378 // any. DeathData owns the whole list starting with this pointer. | |
| 379 // Can be accessed only on the snapshot thread. | |
| 380 const DeathDataPhaseSnapshot* last_phase_snapshot_; | |
| 381 | |
| 382 DISALLOW_ASSIGN(DeathData); | |
| 383 }; | |
| 384 | |
| 385 //------------------------------------------------------------------------------ | |
| 386 // A temporary collection of data that can be sorted and summarized. It is | |
| 387 // gathered (carefully) from many threads. Instances are held in arrays and | |
| 388 // processed, filtered, and rendered. | |
| 389 // The source of this data was collected on many threads, and is asynchronously | |
| 390 // changing. The data in this instance is not asynchronously changing. | |
| 391 | |
| 392 struct BASE_EXPORT TaskSnapshot { | |
| 393 TaskSnapshot(); | |
| 394 TaskSnapshot(const BirthOnThreadSnapshot& birth, | |
| 395 const DeathDataSnapshot& death_data, | |
| 396 const std::string& death_thread_name); | |
| 397 ~TaskSnapshot(); | |
| 398 | |
| 399 BirthOnThreadSnapshot birth; | |
| 400 // Delta between death data for a thread for a certain profiling phase and the | |
| 401 // snapshot for the pervious phase, if any. Otherwise, just a snapshot. | |
| 402 DeathDataSnapshot death_data; | |
| 403 std::string death_thread_name; | |
| 404 }; | |
| 405 | |
| 406 //------------------------------------------------------------------------------ | |
| 407 // For each thread, we have a ThreadData that stores all tracking info generated | |
| 408 // on this thread. This prevents the need for locking as data accumulates. | |
| 409 // We use ThreadLocalStorage to quickly identfy the current ThreadData context. | |
| 410 // We also have a linked list of ThreadData instances, and that list is used to | |
| 411 // harvest data from all existing instances. | |
| 412 | |
| 413 struct ProcessDataPhaseSnapshot; | |
| 414 struct ProcessDataSnapshot; | |
| 415 class BASE_EXPORT TaskStopwatch; | |
| 416 | |
| 417 // Map from profiling phase number to the process-wide snapshotted | |
| 418 // representation of the list of ThreadData objects that died during the given | |
| 419 // phase. | |
| 420 typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap; | |
| 421 | |
| 422 class BASE_EXPORT ThreadData { | |
| 423 public: | |
| 424 // Current allowable states of the tracking system. The states can vary | |
| 425 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED. | |
| 426 enum Status { | |
| 427 UNINITIALIZED, // Pristine, link-time state before running. | |
| 428 DORMANT_DURING_TESTS, // Only used during testing. | |
| 429 DEACTIVATED, // No longer recording profiling. | |
| 430 PROFILING_ACTIVE, // Recording profiles. | |
| 431 STATUS_LAST = PROFILING_ACTIVE | |
| 432 }; | |
| 433 | |
| 434 typedef base::hash_map<Location, Births*, Location::Hash> BirthMap; | |
| 435 typedef std::map<const Births*, DeathData> DeathMap; | |
| 436 | |
| 437 // Initialize the current thread context with a new instance of ThreadData. | |
| 438 // This is used by all threads that have names, and should be explicitly | |
| 439 // set *before* any births on the threads have taken place. It is generally | |
| 440 // only used by the message loop, which has a well defined thread name. | |
| 441 static void InitializeThreadContext(const std::string& suggested_name); | |
| 442 | |
| 443 // Using Thread Local Store, find the current instance for collecting data. | |
| 444 // If an instance does not exist, construct one (and remember it for use on | |
| 445 // this thread. | |
| 446 // This may return NULL if the system is disabled for any reason. | |
| 447 static ThreadData* Get(); | |
| 448 | |
| 449 // Fills |process_data_snapshot| with phased snapshots of all profiling | |
| 450 // phases, including the current one, identified by |current_profiling_phase|. | |
| 451 // |current_profiling_phase| is necessary because a child process can start | |
| 452 // after several phase-changing events, so it needs to receive the current | |
| 453 // phase number from the browser process to fill the correct entry for the | |
| 454 // current phase in the |process_data_snapshot| map. | |
| 455 static void Snapshot(int current_profiling_phase, | |
| 456 ProcessDataSnapshot* process_data_snapshot); | |
| 457 | |
| 458 // Called when the current profiling phase, identified by |profiling_phase|, | |
| 459 // ends. | |
| 460 // |profiling_phase| is necessary because a child process can start after | |
| 461 // several phase-changing events, so it needs to receive the phase number from | |
| 462 // the browser process to fill the correct entry in the | |
| 463 // completed_phases_snapshots_ map. | |
| 464 static void OnProfilingPhaseCompleted(int profiling_phase); | |
| 465 | |
| 466 // Finds (or creates) a place to count births from the given location in this | |
| 467 // thread, and increment that tally. | |
| 468 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. | |
| 469 static Births* TallyABirthIfActive(const Location& location); | |
| 470 | |
| 471 // Records the end of a timed run of an object. The |completed_task| contains | |
| 472 // a pointer to a Births, the time_posted, and a delayed_start_time if any. | |
| 473 // The |start_of_run| indicates when we started to perform the run of the | |
| 474 // task. The delayed_start_time is non-null for tasks that were posted as | |
| 475 // delayed tasks, and it indicates when the task should have run (i.e., when | |
| 476 // it should have posted out of the timer queue, and into the work queue. | |
| 477 // The |end_of_run| was just obtained by a call to Now() (just after the task | |
| 478 // finished). It is provided as an argument to help with testing. | |
| 479 static void TallyRunOnNamedThreadIfTracking( | |
| 480 const base::TrackingInfo& completed_task, | |
| 481 const TaskStopwatch& stopwatch); | |
| 482 | |
| 483 // Record the end of a timed run of an object. The |birth| is the record for | |
| 484 // the instance, the |time_posted| records that instant, which is presumed to | |
| 485 // be when the task was posted into a queue to run on a worker thread. | |
| 486 // The |start_of_run| is when the worker thread started to perform the run of | |
| 487 // the task. | |
| 488 // The |end_of_run| was just obtained by a call to Now() (just after the task | |
| 489 // finished). | |
| 490 static void TallyRunOnWorkerThreadIfTracking(const Births* births, | |
| 491 const TrackedTime& time_posted, | |
| 492 const TaskStopwatch& stopwatch); | |
| 493 | |
| 494 // Record the end of execution in region, generally corresponding to a scope | |
| 495 // being exited. | |
| 496 static void TallyRunInAScopedRegionIfTracking(const Births* births, | |
| 497 const TaskStopwatch& stopwatch); | |
| 498 | |
| 499 const std::string& thread_name() const { return thread_name_; } | |
| 500 | |
| 501 // Initializes all statics if needed (this initialization call should be made | |
| 502 // while we are single threaded). | |
| 503 static void Initialize(); | |
| 504 | |
| 505 // Sets internal status_. | |
| 506 // If |status| is false, then status_ is set to DEACTIVATED. | |
| 507 // If |status| is true, then status_ is set to PROFILING_ACTIVE. | |
| 508 static void InitializeAndSetTrackingStatus(Status status); | |
| 509 | |
| 510 static Status status(); | |
| 511 | |
| 512 // Indicate if any sort of profiling is being done (i.e., we are more than | |
| 513 // DEACTIVATED). | |
| 514 static bool TrackingStatus(); | |
| 515 | |
| 516 // Enables profiler timing. | |
| 517 static void EnableProfilerTiming(); | |
| 518 | |
| 519 // Provide a time function that does nothing (runs fast) when we don't have | |
| 520 // the profiler enabled. It will generally be optimized away when it is | |
| 521 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of | |
| 522 // the code). | |
| 523 static TrackedTime Now(); | |
| 524 | |
| 525 // Use the function |now| to provide current times, instead of calling the | |
| 526 // TrackedTime::Now() function. Since this alternate function is being used, | |
| 527 // the other time arguments (used for calculating queueing delay) will be | |
| 528 // ignored. | |
| 529 static void SetAlternateTimeSource(NowFunction* now); | |
| 530 | |
| 531 // This function can be called at process termination to validate that thread | |
| 532 // cleanup routines have been called for at least some number of named | |
| 533 // threads. | |
| 534 static void EnsureCleanupWasCalled(int major_threads_shutdown_count); | |
| 535 | |
| 536 private: | |
| 537 friend class TaskStopwatch; | |
| 538 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it | |
| 539 // in production code. | |
| 540 // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a | |
| 541 // better change of optimizing (inlining? etc.) private methods (knowing that | |
| 542 // there will be no need for an external entry point). | |
| 543 friend class TrackedObjectsTest; | |
| 544 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); | |
| 545 FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); | |
| 546 | |
| 547 typedef std::map<const BirthOnThread*, int> BirthCountMap; | |
| 548 | |
| 549 typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>> | |
| 550 DeathsSnapshot; | |
| 551 | |
| 552 // Worker thread construction creates a name since there is none. | |
| 553 explicit ThreadData(int thread_number); | |
| 554 | |
| 555 // Message loop based construction should provide a name. | |
| 556 explicit ThreadData(const std::string& suggested_name); | |
| 557 | |
| 558 ~ThreadData(); | |
| 559 | |
| 560 // Push this instance to the head of all_thread_data_list_head_, linking it to | |
| 561 // the previous head. This is performed after each construction, and leaves | |
| 562 // the instance permanently on that list. | |
| 563 void PushToHeadOfList(); | |
| 564 | |
| 565 // (Thread safe) Get start of list of all ThreadData instances using the lock. | |
| 566 static ThreadData* first(); | |
| 567 | |
| 568 // Iterate through the null terminated list of ThreadData instances. | |
| 569 ThreadData* next() const; | |
| 570 | |
| 571 | |
| 572 // In this thread's data, record a new birth. | |
| 573 Births* TallyABirth(const Location& location); | |
| 574 | |
| 575 // Find a place to record a death on this thread. | |
| 576 void TallyADeath(const Births& births, | |
| 577 int32 queue_duration, | |
| 578 const TaskStopwatch& stopwatch); | |
| 579 | |
| 580 // Snapshots (under a lock) the profiled data for the tasks for this thread | |
| 581 // and writes all of the executed tasks' data -- i.e. the data for all | |
| 582 // profiling phases (including the current one: |current_profiling_phase|) for | |
| 583 // the tasks with with entries in the death_map_ -- into |phased_snapshots|. | |
| 584 // Also updates the |birth_counts| tally for each task to keep track of the | |
| 585 // number of living instances of the task -- that is, each task maps to the | |
| 586 // number of births for the task that have not yet been balanced by a death. | |
| 587 void SnapshotExecutedTasks(int current_profiling_phase, | |
| 588 PhasedProcessDataSnapshotMap* phased_snapshots, | |
| 589 BirthCountMap* birth_counts); | |
| 590 | |
| 591 // Using our lock, make a copy of the specified maps. This call may be made | |
| 592 // on non-local threads, which necessitate the use of the lock to prevent | |
| 593 // the map(s) from being reallocated while they are copied. | |
| 594 void SnapshotMaps(int profiling_phase, | |
| 595 BirthMap* birth_map, | |
| 596 DeathsSnapshot* deaths); | |
| 597 | |
| 598 // Called for this thread when the current profiling phase, identified by | |
| 599 // |profiling_phase|, ends. | |
| 600 void OnProfilingPhaseCompletedOnThread(int profiling_phase); | |
| 601 | |
| 602 // This method is called by the TLS system when a thread terminates. | |
| 603 // The argument may be NULL if this thread has never tracked a birth or death. | |
| 604 static void OnThreadTermination(void* thread_data); | |
| 605 | |
| 606 // This method should be called when a worker thread terminates, so that we | |
| 607 // can save all the thread data into a cache of reusable ThreadData instances. | |
| 608 void OnThreadTerminationCleanup(); | |
| 609 | |
| 610 // Cleans up data structures, and returns statics to near pristine (mostly | |
| 611 // uninitialized) state. If there is any chance that other threads are still | |
| 612 // using the data structures, then the |leak| argument should be passed in as | |
| 613 // true, and the data structures (birth maps, death maps, ThreadData | |
| 614 // insntances, etc.) will be leaked and not deleted. If you have joined all | |
| 615 // threads since the time that InitializeAndSetTrackingStatus() was called, | |
| 616 // then you can pass in a |leak| value of false, and this function will | |
| 617 // delete recursively all data structures, starting with the list of | |
| 618 // ThreadData instances. | |
| 619 static void ShutdownSingleThreadedCleanup(bool leak); | |
| 620 | |
| 621 // When non-null, this specifies an external function that supplies monotone | |
| 622 // increasing time functcion. | |
| 623 static NowFunction* now_function_; | |
| 624 | |
| 625 // If true, now_function_ returns values that can be used to calculate queue | |
| 626 // time. | |
| 627 static bool now_function_is_time_; | |
| 628 | |
| 629 // We use thread local store to identify which ThreadData to interact with. | |
| 630 static base::ThreadLocalStorage::StaticSlot tls_index_; | |
| 631 | |
| 632 // List of ThreadData instances for use with worker threads. When a worker | |
| 633 // thread is done (terminated), we push it onto this list. When a new worker | |
| 634 // thread is created, we first try to re-use a ThreadData instance from the | |
| 635 // list, and if none are available, construct a new one. | |
| 636 // This is only accessed while list_lock_ is held. | |
| 637 static ThreadData* first_retired_worker_; | |
| 638 | |
| 639 // Link to the most recently created instance (starts a null terminated list). | |
| 640 // The list is traversed by about:profiler when it needs to snapshot data. | |
| 641 // This is only accessed while list_lock_ is held. | |
| 642 static ThreadData* all_thread_data_list_head_; | |
| 643 | |
| 644 // The next available worker thread number. This should only be accessed when | |
| 645 // the list_lock_ is held. | |
| 646 static int worker_thread_data_creation_count_; | |
| 647 | |
| 648 // The number of times TLS has called us back to cleanup a ThreadData | |
| 649 // instance. This is only accessed while list_lock_ is held. | |
| 650 static int cleanup_count_; | |
| 651 | |
| 652 // Incarnation sequence number, indicating how many times (during unittests) | |
| 653 // we've either transitioned out of UNINITIALIZED, or into that state. This | |
| 654 // value is only accessed while the list_lock_ is held. | |
| 655 static int incarnation_counter_; | |
| 656 | |
| 657 // Protection for access to all_thread_data_list_head_, and to | |
| 658 // unregistered_thread_data_pool_. This lock is leaked at shutdown. | |
| 659 // The lock is very infrequently used, so we can afford to just make a lazy | |
| 660 // instance and be safe. | |
| 661 static base::LazyInstance<base::Lock>::Leaky list_lock_; | |
| 662 | |
| 663 // We set status_ to SHUTDOWN when we shut down the tracking service. | |
| 664 static Status status_; | |
| 665 | |
| 666 // Link to next instance (null terminated list). Used to globally track all | |
| 667 // registered instances (corresponds to all registered threads where we keep | |
| 668 // data). | |
| 669 ThreadData* next_; | |
| 670 | |
| 671 // Pointer to another ThreadData instance for a Worker-Thread that has been | |
| 672 // retired (its thread was terminated). This value is non-NULL only for a | |
| 673 // retired ThreadData associated with a Worker-Thread. | |
| 674 ThreadData* next_retired_worker_; | |
| 675 | |
| 676 // The name of the thread that is being recorded. If this thread has no | |
| 677 // message_loop, then this is a worker thread, with a sequence number postfix. | |
| 678 std::string thread_name_; | |
| 679 | |
| 680 // Indicate if this is a worker thread, and the ThreadData contexts should be | |
| 681 // stored in the unregistered_thread_data_pool_ when not in use. | |
| 682 // Value is zero when it is not a worker thread. Value is a positive integer | |
| 683 // corresponding to the created thread name if it is a worker thread. | |
| 684 int worker_thread_number_; | |
| 685 | |
| 686 // A map used on each thread to keep track of Births on this thread. | |
| 687 // This map should only be accessed on the thread it was constructed on. | |
| 688 // When a snapshot is needed, this structure can be locked in place for the | |
| 689 // duration of the snapshotting activity. | |
| 690 BirthMap birth_map_; | |
| 691 | |
| 692 // Similar to birth_map_, this records informations about death of tracked | |
| 693 // instances (i.e., when a tracked instance was destroyed on this thread). | |
| 694 // It is locked before changing, and hence other threads may access it by | |
| 695 // locking before reading it. | |
| 696 DeathMap death_map_; | |
| 697 | |
| 698 // Lock to protect *some* access to BirthMap and DeathMap. The maps are | |
| 699 // regularly read and written on this thread, but may only be read from other | |
| 700 // threads. To support this, we acquire this lock if we are writing from this | |
| 701 // thread, or reading from another thread. For reading from this thread we | |
| 702 // don't need a lock, as there is no potential for a conflict since the | |
| 703 // writing is only done from this thread. | |
| 704 mutable base::Lock map_lock_; | |
| 705 | |
| 706 // A random number that we used to select decide which sample to keep as a | |
| 707 // representative sample in each DeathData instance. We can't start off with | |
| 708 // much randomness (because we can't call RandInt() on all our threads), so | |
| 709 // we stir in more and more as we go. | |
| 710 uint32 random_number_; | |
| 711 | |
| 712 // Record of what the incarnation_counter_ was when this instance was created. | |
| 713 // If the incarnation_counter_ has changed, then we avoid pushing into the | |
| 714 // pool (this is only critical in tests which go through multiple | |
| 715 // incarnations). | |
| 716 int incarnation_count_for_pool_; | |
| 717 | |
| 718 // Most recently started (i.e. most nested) stopwatch on the current thread, | |
| 719 // if it exists; NULL otherwise. | |
| 720 TaskStopwatch* current_stopwatch_; | |
| 721 | |
| 722 DISALLOW_COPY_AND_ASSIGN(ThreadData); | |
| 723 }; | |
| 724 | |
| 725 //------------------------------------------------------------------------------ | |
| 726 // Stopwatch to measure task run time or simply create a time interval that will | |
| 727 // be subtracted from the current most nested task's run time. Stopwatches | |
| 728 // coordinate with the stopwatches in which they are nested to avoid | |
| 729 // double-counting nested tasks run times. | |
| 730 | |
| 731 class BASE_EXPORT TaskStopwatch { | |
| 732 public: | |
| 733 // Starts the stopwatch. | |
| 734 TaskStopwatch(); | |
| 735 ~TaskStopwatch(); | |
| 736 | |
| 737 // Starts stopwatch. | |
| 738 void Start(); | |
| 739 | |
| 740 // Stops stopwatch. | |
| 741 void Stop(); | |
| 742 | |
| 743 // Returns the start time. | |
| 744 TrackedTime StartTime() const; | |
| 745 | |
| 746 // Task's duration is calculated as the wallclock duration between starting | |
| 747 // and stopping this stopwatch, minus the wallclock durations of any other | |
| 748 // instances that are immediately nested in this one, started and stopped on | |
| 749 // this thread during that period. | |
| 750 int32 RunDurationMs() const; | |
| 751 | |
| 752 // Returns tracking info for the current thread. | |
| 753 ThreadData* GetThreadData() const; | |
| 754 | |
| 755 private: | |
| 756 // Time when the stopwatch was started. | |
| 757 TrackedTime start_time_; | |
| 758 | |
| 759 // Wallclock duration of the task. | |
| 760 int32 wallclock_duration_ms_; | |
| 761 | |
| 762 // Tracking info for the current thread. | |
| 763 ThreadData* current_thread_data_; | |
| 764 | |
| 765 // Sum of wallclock durations of all stopwatches that were directly nested in | |
| 766 // this one. | |
| 767 int32 excluded_duration_ms_; | |
| 768 | |
| 769 // Stopwatch which was running on our thread when this stopwatch was started. | |
| 770 // That preexisting stopwatch must be adjusted to the exclude the wallclock | |
| 771 // duration of this stopwatch. | |
| 772 TaskStopwatch* parent_; | |
| 773 | |
| 774 #if DCHECK_IS_ON() | |
| 775 // State of the stopwatch. Stopwatch is first constructed in a created state | |
| 776 // state, then is optionally started/stopped, then destructed. | |
| 777 enum { CREATED, RUNNING, STOPPED } state_; | |
| 778 | |
| 779 // Currently running stopwatch that is directly nested in this one, if such | |
| 780 // stopwatch exists. NULL otherwise. | |
| 781 TaskStopwatch* child_; | |
| 782 #endif | |
| 783 }; | |
| 784 | |
| 785 //------------------------------------------------------------------------------ | |
| 786 // A snapshotted representation of the list of ThreadData objects for a process, | |
| 787 // for a single profiling phase. | |
| 788 | |
| 789 struct BASE_EXPORT ProcessDataPhaseSnapshot { | |
| 790 public: | |
| 791 ProcessDataPhaseSnapshot(); | |
| 792 ~ProcessDataPhaseSnapshot(); | |
| 793 | |
| 794 std::vector<TaskSnapshot> tasks; | |
| 795 }; | |
| 796 | |
| 797 //------------------------------------------------------------------------------ | |
| 798 // A snapshotted representation of the list of ThreadData objects for a process, | |
| 799 // for all profiling phases, including the current one. | |
| 800 | |
| 801 struct BASE_EXPORT ProcessDataSnapshot { | |
| 802 public: | |
| 803 ProcessDataSnapshot(); | |
| 804 ~ProcessDataSnapshot(); | |
| 805 | |
| 806 PhasedProcessDataSnapshotMap phased_snapshots; | |
| 807 base::ProcessId process_id; | |
| 808 }; | |
| 809 | |
| 810 } // namespace tracked_objects | |
| 811 | |
| 812 #endif // BASE_TRACKED_OBJECTS_H_ | |
| OLD | NEW |