Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #pragma once | 7 #pragma once |
| 8 | 8 |
| 9 #include <map> | 9 #include <map> |
| 10 #include <stack> | |
| 10 #include <string> | 11 #include <string> |
| 11 #include <vector> | 12 #include <vector> |
| 12 | 13 |
| 13 #include "base/base_export.h" | 14 #include "base/base_export.h" |
| 14 #include "base/location.h" | 15 #include "base/location.h" |
| 15 #include "base/time.h" | 16 #include "base/time.h" |
| 16 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
| 17 #include "base/threading/thread_local_storage.h" | 18 #include "base/threading/thread_local_storage.h" |
| 19 #include "base/values.h" | |
| 18 | 20 |
| 19 // TrackedObjects provides a database of stats about objects (generally Tasks) | 21 // TrackedObjects provides a database of stats about objects (generally Tasks) |
| 20 // that are tracked. Tracking means their birth, death, duration, birth thread, | 22 // that are tracked. Tracking means their birth, death, duration, birth thread, |
| 21 // death thread, and birth place are recorded. This data is carefully spread | 23 // death thread, and birth place are recorded. This data is carefully spread |
| 22 // across a series of objects so that the counts and times can be rapidly | 24 // across a series of objects so that the counts and times can be rapidly |
| 23 // updated without (usually) having to lock the data, and hence there is usually | 25 // updated without (usually) having to lock the data, and hence there is usually |
| 24 // very little contention caused by the tracking. The data can be viewed via | 26 // very little contention caused by the tracking. The data can be viewed via |
| 25 // the about:tracking URL, with a variety of sorting and filtering choices. | 27 // the about:tracking URL, with a variety of sorting and filtering choices. |
| 26 // | 28 // |
| 27 // These classes serve as the basis of a profiler of sorts for the Tasks system. | 29 // These classes serve as the basis of a profiler of sorts for the Tasks system. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 // ThreadData instance (for that specific thread only). The two critical items | 97 // ThreadData instance (for that specific thread only). The two critical items |
| 96 // are lists of DeathData and Births instances. These lists are maintained in | 98 // are lists of DeathData and Births instances. These lists are maintained in |
| 97 // STL maps, which are indexed by Location. As noted earlier, we can compare | 99 // STL maps, which are indexed by Location. As noted earlier, we can compare |
| 98 // locations very efficiently as we consider the underlying data (file, | 100 // locations very efficiently as we consider the underlying data (file, |
| 99 // function, line) to be atoms, and hence pointer comparison is used rather than | 101 // function, line) to be atoms, and hence pointer comparison is used rather than |
| 100 // (slow) string comparisons. | 102 // (slow) string comparisons. |
| 101 // | 103 // |
| 102 // To provide a mechanism for iterating over all "known threads," which means | 104 // To provide a mechanism for iterating over all "known threads," which means |
| 103 // threads that have recorded a birth or a death, we create a singly linked list | 105 // threads that have recorded a birth or a death, we create a singly linked list |
| 104 // of ThreadData instances. Each such instance maintains a pointer to the next | 106 // of ThreadData instances. Each such instance maintains a pointer to the next |
| 105 // one. A static member of ThreadData provides a pointer to the first_ item on | 107 // one. A static member of ThreadData provides a pointer to the first item on |
| 106 // this global list, and access to that first_ item requires the use of a lock_. | 108 // this global list, and access via that all_thread_data_list_head_ item |
| 109 // requires the use of the list_lock_. | |
| 107 // When new ThreadData instances is added to the global list, it is pre-pended, | 110 // When new ThreadData instances is added to the global list, it is pre-pended, |
| 108 // which ensures that any prior acquisition of the list is valid (i.e., the | 111 // which ensures that any prior acquisition of the list is valid (i.e., the |
| 109 // holder can iterate over it without fear of it changing, or the necessity of | 112 // holder can iterate over it without fear of it changing, or the necessity of |
| 110 // using an additional lock. Iterations are actually pretty rare (used | 113 // using an additional lock. Iterations are actually pretty rare (used |
| 111 // primarilly for cleanup, or snapshotting data for display), so this lock has | 114 // primarilly for cleanup, or snapshotting data for display), so this lock has |
| 112 // very little global performance impact. | 115 // very little global performance impact. |
| 113 // | 116 // |
| 114 // The above description tries to define the high performance (run time) | 117 // The above description tries to define the high performance (run time) |
| 115 // portions of these classes. After gathering statistics, calls instigated | 118 // portions of these classes. After gathering statistics, calls instigated |
| 116 // by visiting about:tracking will assemble and aggregate data for display. The | 119 // by visiting about:tracking will assemble and aggregate data for display. The |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 class MessageLoop; | 165 class MessageLoop; |
| 163 | 166 |
| 164 namespace tracked_objects { | 167 namespace tracked_objects { |
| 165 | 168 |
| 166 //------------------------------------------------------------------------------ | 169 //------------------------------------------------------------------------------ |
| 167 // For a specific thread, and a specific birth place, the collection of all | 170 // For a specific thread, and a specific birth place, the collection of all |
| 168 // death info (with tallies for each death thread, to prevent access conflicts). | 171 // death info (with tallies for each death thread, to prevent access conflicts). |
| 169 class ThreadData; | 172 class ThreadData; |
| 170 class BASE_EXPORT BirthOnThread { | 173 class BASE_EXPORT BirthOnThread { |
| 171 public: | 174 public: |
| 172 explicit BirthOnThread(const Location& location); | 175 BirthOnThread(const Location& location, const ThreadData& current); |
| 173 | 176 |
| 174 const Location location() const { return location_; } | 177 const Location location() const { return location_; } |
| 175 const ThreadData* birth_thread() const { return birth_thread_; } | 178 const ThreadData* birth_thread() const { return birth_thread_; } |
| 176 | 179 |
| 177 private: | 180 private: |
| 178 // File/lineno of birth. This defines the essence of the task, as the context | 181 // File/lineno of birth. This defines the essence of the task, as the context |
| 179 // of the birth (construction) often tell what the item is for. This field | 182 // of the birth (construction) often tell what the item is for. This field |
| 180 // is const, and hence safe to access from any thread. | 183 // is const, and hence safe to access from any thread. |
| 181 const Location location_; | 184 const Location location_; |
| 182 | 185 |
| 183 // The thread that records births into this object. Only this thread is | 186 // The thread that records births into this object. Only this thread is |
| 184 // allowed to access birth_count_ (which changes over time). | 187 // allowed to update birth_count_ (which changes over time). |
| 185 const ThreadData* birth_thread_; // The thread this birth took place on. | 188 const ThreadData* const birth_thread_; |
| 186 | 189 |
| 187 DISALLOW_COPY_AND_ASSIGN(BirthOnThread); | 190 DISALLOW_COPY_AND_ASSIGN(BirthOnThread); |
| 188 }; | 191 }; |
| 189 | 192 |
| 190 //------------------------------------------------------------------------------ | 193 //------------------------------------------------------------------------------ |
| 191 // A class for accumulating counts of births (without bothering with a map<>). | 194 // A class for accumulating counts of births (without bothering with a map<>). |
| 192 | 195 |
| 193 class BASE_EXPORT Births: public BirthOnThread { | 196 class BASE_EXPORT Births: public BirthOnThread { |
| 194 public: | 197 public: |
| 195 explicit Births(const Location& location); | 198 Births(const Location& location, const ThreadData& current); |
| 196 | 199 |
| 197 int birth_count() const { return birth_count_; } | 200 int birth_count() const { return birth_count_; } |
| 198 | 201 |
| 199 // When we have a birth we update the count for this BirhPLace. | 202 // When we have a birth we update the count for this BirhPLace. |
| 200 void RecordBirth() { ++birth_count_; } | 203 void RecordBirth() { ++birth_count_; } |
| 201 | 204 |
| 202 // When a birthplace is changed (updated), we need to decrement the counter | 205 // When a birthplace is changed (updated), we need to decrement the counter |
| 203 // for the old instance. | 206 // for the old instance. |
| 204 void ForgetBirth() { --birth_count_; } // We corrected a birth place. | 207 void ForgetBirth() { --birth_count_; } // We corrected a birth place. |
| 205 | 208 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 int count() const { return count_; } | 240 int count() const { return count_; } |
| 238 base::TimeDelta run_duration() const { return run_duration_; } | 241 base::TimeDelta run_duration() const { return run_duration_; } |
| 239 int AverageMsRunDuration() const; | 242 int AverageMsRunDuration() const; |
| 240 base::TimeDelta queue_duration() const { return queue_duration_; } | 243 base::TimeDelta queue_duration() const { return queue_duration_; } |
| 241 int AverageMsQueueDuration() const; | 244 int AverageMsQueueDuration() const; |
| 242 | 245 |
| 243 // Accumulate metrics from other into this. This method is never used on | 246 // Accumulate metrics from other into this. This method is never used on |
| 244 // realtime statistics, and only used in snapshots and aggregatinos. | 247 // realtime statistics, and only used in snapshots and aggregatinos. |
| 245 void AddDeathData(const DeathData& other); | 248 void AddDeathData(const DeathData& other); |
| 246 | 249 |
| 247 // Simple print of internal state. | 250 // Simple print of internal state for use in line of HTML. |
| 248 void Write(std::string* output) const; | 251 void WriteHTML(std::string* output) const; |
| 252 | |
| 253 // Constructe a DictionaryValue instance containing all our stats. The caller | |
|
eroman
2011/10/24 22:23:04
typo: construct
jar (doing other things)
2011/10/27 06:23:35
Done.
| |
| 254 // assumes ownership of the returned instance. | |
| 255 base::DictionaryValue* ToValue() const; | |
| 249 | 256 |
| 250 // Reset all tallies to zero. This is used as a hack on realtime data. | 257 // Reset all tallies to zero. This is used as a hack on realtime data. |
| 251 void Clear(); | 258 void Clear(); |
| 252 | 259 |
| 253 private: | 260 private: |
| 254 int count_; // Number of destructions. | 261 int count_; // Number of destructions. |
| 255 base::TimeDelta run_duration_; // Sum of all Run()time durations. | 262 base::TimeDelta run_duration_; // Sum of all Run()time durations. |
| 256 base::TimeDelta queue_duration_; // Sum of all queue time durations. | 263 base::TimeDelta queue_duration_; // Sum of all queue time durations. |
| 257 }; | 264 }; |
| 258 | 265 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 284 int AverageMsRunDuration() const { | 291 int AverageMsRunDuration() const { |
| 285 return death_data_.AverageMsRunDuration(); | 292 return death_data_.AverageMsRunDuration(); |
| 286 } | 293 } |
| 287 base::TimeDelta queue_duration() const { | 294 base::TimeDelta queue_duration() const { |
| 288 return death_data_.queue_duration(); | 295 return death_data_.queue_duration(); |
| 289 } | 296 } |
| 290 int AverageMsQueueDuration() const { | 297 int AverageMsQueueDuration() const { |
| 291 return death_data_.AverageMsQueueDuration(); | 298 return death_data_.AverageMsQueueDuration(); |
| 292 } | 299 } |
| 293 | 300 |
| 294 void Write(std::string* output) const; | 301 // Emit contents for use in a line of HTML |
| 302 void WriteHTML(std::string* output) const; | |
| 303 | |
| 304 // Construct a DictionaryValue instance containing all our data recursively. | |
| 305 // The caller assumes ownership of the memory in the returned instance. | |
| 306 base::DictionaryValue* ToValue() const; | |
| 295 | 307 |
| 296 void Add(const Snapshot& other); | 308 void Add(const Snapshot& other); |
| 297 | 309 |
| 298 private: | 310 private: |
| 299 const BirthOnThread* birth_; // Includes Location and birth_thread. | 311 const BirthOnThread* birth_; // Includes Location and birth_thread. |
| 300 const ThreadData* death_thread_; | 312 const ThreadData* death_thread_; |
| 301 DeathData death_data_; | 313 DeathData death_data_; |
| 302 }; | 314 }; |
| 303 | 315 |
| 304 //------------------------------------------------------------------------------ | 316 //------------------------------------------------------------------------------ |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 320 void Append(const ThreadData& thread_data); | 332 void Append(const ThreadData& thread_data); |
| 321 | 333 |
| 322 // After the accumulation phase, the following accessor is used to process the | 334 // After the accumulation phase, the following accessor is used to process the |
| 323 // data. | 335 // data. |
| 324 Collection* collection(); | 336 Collection* collection(); |
| 325 | 337 |
| 326 // After collection of death data is complete, we can add entries for all the | 338 // After collection of death data is complete, we can add entries for all the |
| 327 // remaining living objects. | 339 // remaining living objects. |
| 328 void AddListOfLivingObjects(); | 340 void AddListOfLivingObjects(); |
| 329 | 341 |
| 342 // Generate a ListValue representation of the vector of snapshots. The caller | |
|
eroman
2011/10/24 22:23:04
nit: style guide says to use passive tense for fun
jar (doing other things)
2011/10/27 06:23:35
Done.
| |
| 343 // assumes ownership of the memory in the returned instance. | |
| 344 base::ListValue* ToValue() const; | |
| 345 | |
| 330 private: | 346 private: |
| 331 typedef std::map<const BirthOnThread*, int> BirthCount; | 347 typedef std::map<const BirthOnThread*, int> BirthCount; |
| 332 | 348 |
| 333 // The array that we collect data into. | 349 // The array that we collect data into. |
| 334 Collection collection_; | 350 Collection collection_; |
| 335 | 351 |
| 336 // The total number of births recorded at each location for which we have not | 352 // The total number of births recorded at each location for which we have not |
| 337 // seen a death count. | 353 // seen a death count. |
| 338 BirthCount global_birth_count_; | 354 BirthCount global_birth_count_; |
| 339 | 355 |
| 340 DISALLOW_COPY_AND_ASSIGN(DataCollector); | 356 DISALLOW_COPY_AND_ASSIGN(DataCollector); |
| 341 }; | 357 }; |
| 342 | 358 |
| 343 //------------------------------------------------------------------------------ | 359 //------------------------------------------------------------------------------ |
| 344 // Aggregation contains summaries (totals and subtotals) of groups of Snapshot | 360 // Aggregation contains summaries (totals and subtotals) of groups of Snapshot |
| 345 // instances to provide printing of these collections on a single line. | 361 // instances to provide printing of these collections on a single line. |
| 346 | 362 |
| 347 class BASE_EXPORT Aggregation: public DeathData { | 363 class BASE_EXPORT Aggregation: public DeathData { |
| 348 public: | 364 public: |
| 349 Aggregation(); | 365 Aggregation(); |
| 350 ~Aggregation(); | 366 ~Aggregation(); |
| 351 | 367 |
| 352 void AddDeathSnapshot(const Snapshot& snapshot); | 368 void AddDeathSnapshot(const Snapshot& snapshot); |
| 353 void AddBirths(const Births& births); | 369 void AddBirths(const Births& births); |
| 354 void AddBirth(const BirthOnThread& birth); | 370 void AddBirth(const BirthOnThread& birth); |
| 355 void AddBirthPlace(const Location& location); | 371 void AddBirthPlace(const Location& location); |
| 356 void Write(std::string* output) const; | 372 void WriteHTML(std::string* output) const; |
| 357 void Clear(); | 373 void Clear(); |
| 358 | 374 |
| 359 private: | 375 private: |
| 360 int birth_count_; | 376 int birth_count_; |
| 361 std::map<std::string, int> birth_files_; | 377 std::map<std::string, int> birth_files_; |
| 362 std::map<Location, int> locations_; | 378 std::map<Location, int> locations_; |
| 363 std::map<const ThreadData*, int> birth_threads_; | 379 std::map<const ThreadData*, int> birth_threads_; |
| 364 DeathData death_data_; | 380 DeathData death_data_; |
| 365 std::map<const ThreadData*, int> death_threads_; | 381 std::map<const ThreadData*, int> death_threads_; |
| 366 | 382 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 | 456 |
| 441 // Parse a query to decide on sort ordering. | 457 // Parse a query to decide on sort ordering. |
| 442 bool ParseQuery(const std::string& query); | 458 bool ParseQuery(const std::string& query); |
| 443 | 459 |
| 444 // Output a header line that can be used to indicated what items will be | 460 // Output a header line that can be used to indicated what items will be |
| 445 // collected in the group. It lists all (potentially) tested attributes and | 461 // collected in the group. It lists all (potentially) tested attributes and |
| 446 // their values (in the sample item). | 462 // their values (in the sample item). |
| 447 bool WriteSortGrouping(const Snapshot& sample, std::string* output) const; | 463 bool WriteSortGrouping(const Snapshot& sample, std::string* output) const; |
| 448 | 464 |
| 449 // Output a sample, with SortGroup details not displayed. | 465 // Output a sample, with SortGroup details not displayed. |
| 450 void WriteSnapshot(const Snapshot& sample, std::string* output) const; | 466 void WriteSnapshotHTML(const Snapshot& sample, std::string* output) const; |
| 451 | 467 |
| 452 private: | 468 private: |
| 453 // The selector directs this instance to compare based on the specified | 469 // The selector directs this instance to compare based on the specified |
| 454 // members of the tested elements. | 470 // members of the tested elements. |
| 455 enum Selector selector_; | 471 enum Selector selector_; |
| 456 | 472 |
| 457 // For filtering into acceptable and unacceptable snapshot instance, the | 473 // For filtering into acceptable and unacceptable snapshot instance, the |
| 458 // following is required to be a substring of the selector_ field. | 474 // following is required to be a substring of the selector_ field. |
| 459 std::string required_; | 475 std::string required_; |
| 460 | 476 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 485 | 501 |
| 486 // Initialize the current thread context with a new instance of ThreadData. | 502 // Initialize the current thread context with a new instance of ThreadData. |
| 487 // This is used by all threads that have names, and can be explicitly | 503 // This is used by all threads that have names, and can be explicitly |
| 488 // set *before* any births are threads have taken place. It is generally | 504 // set *before* any births are threads have taken place. It is generally |
| 489 // only used by the message loop, which has a well defined name. | 505 // only used by the message loop, which has a well defined name. |
| 490 static void InitializeThreadContext(const std::string& suggested_name); | 506 static void InitializeThreadContext(const std::string& suggested_name); |
| 491 | 507 |
| 492 // Using Thread Local Store, find the current instance for collecting data. | 508 // Using Thread Local Store, find the current instance for collecting data. |
| 493 // If an instance does not exist, construct one (and remember it for use on | 509 // If an instance does not exist, construct one (and remember it for use on |
| 494 // this thread. | 510 // this thread. |
| 495 // If shutdown has already started, and we don't yet have an instance, then | 511 // This may return NULL if the system is disabled for any reason. |
| 496 // return null. | |
| 497 static ThreadData* Get(); | 512 static ThreadData* Get(); |
| 498 | 513 |
| 499 // For a given (unescaped) about:tracking query, develop resulting HTML, and | 514 // For a given (unescaped) about:tracking query, develop resulting HTML, and |
| 500 // append to output. | 515 // append to output. |
| 501 static void WriteHTML(const std::string& query, std::string* output); | 516 static void WriteHTML(const std::string& query, std::string* output); |
| 502 | 517 |
| 518 // Constructe a ListValue instance containing all recursive results in our | |
|
eroman
2011/10/24 22:23:04
typo construct.
jar (doing other things)
2011/10/27 06:23:35
Done.
| |
| 519 // process. The caller assumes ownership of the memory in the returned | |
| 520 // instance. The |process_type| should become an enum, which corresponds | |
| 521 // to all possible process types. I'm using an int as a placeholder. | |
| 522 static base::Value* ToValue(int process_type); | |
|
eroman
2011/10/24 22:23:04
not sure about this process_type parameter.
jar (doing other things)
2011/10/27 06:23:35
Rephrased as a TODO task.
| |
| 523 | |
| 503 // For a given accumulated array of results, use the comparator to sort and | 524 // For a given accumulated array of results, use the comparator to sort and |
| 504 // subtotal, writing the results to the output. | 525 // subtotal, writing the results to the output. |
| 505 static void WriteHTMLTotalAndSubtotals( | 526 static void WriteHTMLTotalAndSubtotals( |
| 506 const DataCollector::Collection& match_array, | 527 const DataCollector::Collection& match_array, |
| 507 const Comparator& comparator, std::string* output); | 528 const Comparator& comparator, std::string* output); |
| 508 | 529 |
| 509 // In this thread's data, record a new birth. | 530 // Find (or create) a place to count births from the given location in this |
| 510 Births* TallyABirth(const Location& location); | 531 // thread, and increment that tally. |
| 511 | |
| 512 // Find a place to record a death on this thread. | |
| 513 void TallyADeath(const Births& the_birth, | |
| 514 const base::TimeDelta& queue_duration, | |
| 515 const base::TimeDelta& duration); | |
| 516 | |
| 517 // Helper methods to only tally if the current thread has tracking active. | |
| 518 // | |
| 519 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. | 532 // TallyABirthIfActive will returns NULL if the birth cannot be tallied. |
| 520 static Births* TallyABirthIfActive(const Location& location); | 533 static Births* TallyABirthIfActive(const Location& location); |
| 521 | 534 |
| 522 // Record the end of a timed run of an object. The |the_birth| is the record | 535 // Record the end of a timed run of an object. The |birth| is the record for |
| 523 // for the instance, the |time_posted| and |start_of_run| are times of posting | 536 // the instance, the |time_posted| and |start_of_run| are times of posting |
| 524 // into a message loop queue, and of starting to perform the run of the task. | 537 // into a message loop queue, and of starting to perform the run of the task. |
| 525 // Implied is that the run just (Now()) ended. The current_message_loop is | 538 // The |end_of_run| was just obtained by a call to Now() (just after the task |
| 526 // optional, and only used in DEBUG mode (when supplied) to verify that the | 539 // finished). |
| 527 // ThreadData has a thread name that does indeed match the given loop's | 540 static void TallyADeathIfActive(const Births* birth, |
| 528 // associated thread name (in RELEASE mode, its use is compiled away). | |
| 529 static void TallyADeathIfActive(const Births* the_birth, | |
| 530 const base::TimeTicks& time_posted, | 541 const base::TimeTicks& time_posted, |
| 531 const base::TimeTicks& delayed_start_time, | 542 const base::TimeTicks& delayed_start_time, |
| 532 const base::TimeTicks& start_of_run); | 543 const base::TimeTicks& start_of_run, |
| 533 | 544 const base::TimeTicks& end_of_run); |
| 534 // (Thread safe) Get start of list of instances. | |
| 535 static ThreadData* first(); | |
| 536 // Iterate through the null terminated list of instances. | |
| 537 ThreadData* next() const { return next_; } | |
| 538 | 545 |
| 539 const std::string thread_name() const { return thread_name_; } | 546 const std::string thread_name() const { return thread_name_; } |
| 540 | 547 |
| 548 // --------------------- | |
| 549 // The following functions should all be private, and are only public because | |
| 550 // the collection is done externally. We need to relocate that code from the | |
| 551 // collection class into this class, and then all these methods can be made | |
| 552 // private. | |
| 553 // (Thread safe) Get start of list of all ThreadData instances. | |
| 554 static ThreadData* first(); | |
| 555 // Iterate through the null terminated list of ThreadData instances. | |
| 556 ThreadData* next() const { return next_; } | |
| 541 // Using our lock, make a copy of the specified maps. These calls may arrive | 557 // Using our lock, make a copy of the specified maps. These calls may arrive |
| 542 // from non-local threads, and are used to quickly scan data from all threads | 558 // from non-local threads, and are used to quickly scan data from all threads |
| 543 // in order to build an HTML page for about:tracking. | 559 // in order to build an HTML page for about:tracking. |
| 544 void SnapshotBirthMap(BirthMap *output) const; | 560 void SnapshotBirthMap(BirthMap *output) const; |
| 545 void SnapshotDeathMap(DeathMap *output) const; | 561 void SnapshotDeathMap(DeathMap *output) const; |
| 562 // -------- end of should be private methods. | |
| 546 | 563 |
| 547 // Hack: asynchronously clear all birth counts and death tallies data values | 564 // Hack: asynchronously clear all birth counts and death tallies data values |
| 548 // in all ThreadData instances. The numerical (zeroing) part is done without | 565 // in all ThreadData instances. The numerical (zeroing) part is done without |
| 549 // use of a locks or atomics exchanges, and may (for int64 values) produce | 566 // use of a locks or atomics exchanges, and may (for int64 values) produce |
| 550 // bogus counts VERY rarely. | 567 // bogus counts VERY rarely. |
| 551 static void ResetAllThreadData(); | 568 static void ResetAllThreadData(); |
| 552 | 569 |
| 553 // Using our lock to protect the iteration, Clear all birth and death data. | |
| 554 void Reset(); | |
| 555 | |
| 556 // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN, | 570 // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN, |
| 557 // based on argument being true or false respectively. | 571 // based on argument being true or false respectively. |
| 558 // IF tracking is not compiled in, this function will return false. | 572 // IF tracking is not compiled in, this function will return false. |
| 559 static bool StartTracking(bool status); | 573 static bool StartTracking(bool status); |
| 560 static bool IsActive(); | 574 static bool IsActive(); |
| 561 | 575 |
| 562 // Provide a time function that does nothing (runs fast) when we don't have | 576 // Provide a time function that does nothing (runs fast) when we don't have |
| 563 // the profiler enabled. It will generally be optimized away when it is | 577 // the profiler enabled. It will generally be optimized away when it is |
| 564 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of | 578 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of |
| 565 // the code). | 579 // the code). |
| 566 static base::TimeTicks Now(); | 580 static base::TimeTicks Now(); |
| 567 | 581 |
| 568 // WARNING: ONLY call this function when you are running single threaded | 582 // WARNING: ONLY call this function when you are running single threaded |
| 569 // (again) and all message loops and threads have terminated. Until that | 583 // (again) and all message loops and threads have terminated. Until that |
| 570 // point some threads may still attempt to write into our data structures. | 584 // point some threads may still attempt to write into our data structures. |
| 571 // Delete recursively all data structures, starting with the list of | 585 // Delete recursively all data structures, starting with the list of |
| 572 // ThreadData instances. | 586 // ThreadData instances. |
| 573 static void ShutdownSingleThreadedCleanup(); | 587 static void ShutdownSingleThreadedCleanup(); |
| 574 | 588 |
| 575 private: | 589 private: |
| 576 // Worker thread construction creates a name. | |
| 577 ThreadData(); | |
| 578 // Message loop based construction should provide a name. | |
| 579 explicit ThreadData(const std::string& suggested_name); | |
| 580 | |
| 581 ~ThreadData(); | |
| 582 | |
| 583 // Enter a new instance into Thread Local Store. | |
| 584 // Return the instance, or null if we can't register it (because we're | |
| 585 // shutting down). | |
| 586 static ThreadData* RegisterCurrentContext(ThreadData* unregistered); | |
| 587 | |
| 588 // Current allowable states of the tracking system. The states always | 590 // Current allowable states of the tracking system. The states always |
| 589 // proceed towards SHUTDOWN, and never go backwards. | 591 // proceed towards SHUTDOWN, and never go backwards. |
| 590 enum Status { | 592 enum Status { |
| 591 UNINITIALIZED, | 593 UNINITIALIZED, |
| 592 ACTIVE, | 594 ACTIVE, |
| 593 SHUTDOWN, | 595 SHUTDOWN, |
| 594 }; | 596 }; |
| 595 | 597 |
| 598 typedef std::stack<const ThreadData*> ThreadDataPool; | |
| 599 | |
| 600 // Worker thread construction creates a name since there is none. | |
| 601 ThreadData(); | |
| 602 // Message loop based construction should provide a name. | |
| 603 explicit ThreadData(const std::string& suggested_name); | |
| 604 | |
| 605 ~ThreadData(); | |
| 606 | |
| 607 // Push this instance to the head of all_thread_data_list_head_, linking it to | |
| 608 // the previous head. This is performed after each construction, and leaves | |
| 609 // the instance permanently on that list. | |
| 610 void PushToHeadOfList(); | |
| 611 | |
| 612 // In this thread's data, record a new birth. | |
| 613 Births* TallyABirth(const Location& location); | |
| 614 | |
| 615 // Find a place to record a death on this thread. | |
| 616 void TallyADeath(const Births& birth, | |
| 617 const base::TimeDelta& queue_duration, | |
| 618 const base::TimeDelta& duration); | |
| 619 | |
| 620 // Using our lock to protect the iteration, Clear all birth and death data. | |
| 621 void Reset(); | |
| 622 | |
| 623 // This method is called by the TLS system when a thread terminates. | |
| 624 // The argument may be NULL if this thread has never tracked a birth or death. | |
| 625 static void OnThreadTermination(void* thread_data); | |
| 626 | |
| 627 // This method should be called when a worker thread terminates, so that we | |
| 628 // can save all the thread data into a cache of reusable ThreadData instances. | |
| 629 void OnThreadTerminationCleanup() const; | |
| 630 | |
| 596 // We use thread local store to identify which ThreadData to interact with. | 631 // We use thread local store to identify which ThreadData to interact with. |
| 597 static base::ThreadLocalStorage::Slot tls_index_; | 632 static base::ThreadLocalStorage::Slot tls_index_; |
| 598 | 633 |
| 599 // Link to the most recently created instance (starts a null terminated list). | 634 // Link to the most recently created instance (starts a null terminated list). |
| 600 static ThreadData* first_; | 635 // The list is traversed by about:tracking when it needs to snapshot data. |
| 601 // Protection for access to first_. | 636 static ThreadData* all_thread_data_list_head_; |
| 637 // Set of ThreadData instances for use with worker threads. When a worker | |
| 638 // thread is done (terminating), we push it into this pool. When a new worker | |
| 639 // thread is created, we first try to re-use a ThreadData instance from the | |
| 640 // pool, and if none are available, construct a new one. | |
| 641 static ThreadDataPool* unregistered_thread_data_pool_; | |
| 642 // Protection for access to all_thread_data_list_head_, and to | |
| 643 // unregistered_thread_data_pool_. | |
| 602 static base::Lock list_lock_; | 644 static base::Lock list_lock_; |
| 603 | 645 |
| 604 // We set status_ to SHUTDOWN when we shut down the tracking service. | 646 // We set status_ to SHUTDOWN when we shut down the tracking service. |
| 605 static Status status_; | 647 static Status status_; |
| 606 | 648 |
| 607 // Link to next instance (null terminated list). Used to globally track all | 649 // Link to next instance (null terminated list). Used to globally track all |
| 608 // registered instances (corresponds to all registered threads where we keep | 650 // registered instances (corresponds to all registered threads where we keep |
| 609 // data). | 651 // data). |
| 610 ThreadData* next_; | 652 ThreadData* next_; |
| 611 | 653 |
| 612 // The name of the thread that is being recorded. If this thread has no | 654 // The name of the thread that is being recorded. If this thread has no |
| 613 // message_loop, then this is a worker thread, with a sequence number postfix. | 655 // message_loop, then this is a worker thread, with a sequence number postfix. |
| 614 std::string thread_name_; | 656 std::string thread_name_; |
| 615 | 657 |
| 658 // Indicate if this is a worker thread, and the ThreadData contexts should be | |
| 659 // stored in the unregistered_thread_data_pool_ when not in use. | |
| 660 bool is_a_worker_thread_; | |
| 661 | |
| 616 // A map used on each thread to keep track of Births on this thread. | 662 // A map used on each thread to keep track of Births on this thread. |
| 617 // This map should only be accessed on the thread it was constructed on. | 663 // This map should only be accessed on the thread it was constructed on. |
| 618 // When a snapshot is needed, this structure can be locked in place for the | 664 // When a snapshot is needed, this structure can be locked in place for the |
| 619 // duration of the snapshotting activity. | 665 // duration of the snapshotting activity. |
| 620 BirthMap birth_map_; | 666 BirthMap birth_map_; |
| 621 | 667 |
| 622 // Similar to birth_map_, this records informations about death of tracked | 668 // Similar to birth_map_, this records informations about death of tracked |
| 623 // instances (i.e., when a tracked instance was destroyed on this thread). | 669 // instances (i.e., when a tracked instance was destroyed on this thread). |
| 624 // It is locked before changing, and hence other threads may access it by | 670 // It is locked before changing, and hence other threads may access it by |
| 625 // locking before reading it. | 671 // locking before reading it. |
| 626 DeathMap death_map_; | 672 DeathMap death_map_; |
| 627 | 673 |
| 628 // Lock to protect *some* access to BirthMap and DeathMap. The maps are | 674 // Lock to protect *some* access to BirthMap and DeathMap. The maps are |
| 629 // regularly read and written on this thread, but may only be read from other | 675 // regularly read and written on this thread, but may only be read from other |
| 630 // threads. To support this, we acquire this lock if we are writing from this | 676 // threads. To support this, we acquire this lock if we are writing from this |
| 631 // thread, or reading from another thread. For reading from this thread we | 677 // thread, or reading from another thread. For reading from this thread we |
| 632 // don't need a lock, as there is no potential for a conflict since the | 678 // don't need a lock, as there is no potential for a conflict since the |
| 633 // writing is only done from this thread. | 679 // writing is only done from this thread. |
| 634 mutable base::Lock lock_; | 680 mutable base::Lock lock_; |
| 635 | 681 |
| 636 // The next available thread number. This should only be accessed when the | 682 // The next available thread number. This should only be accessed when the |
| 637 // list_lock_ is held. | 683 // list_lock_ is held. |
| 638 static int thread_number_counter; | 684 static int thread_number_counter_; |
| 639 | 685 |
| 640 DISALLOW_COPY_AND_ASSIGN(ThreadData); | 686 DISALLOW_COPY_AND_ASSIGN(ThreadData); |
| 641 }; | 687 }; |
| 642 | 688 |
| 643 //------------------------------------------------------------------------------ | 689 //------------------------------------------------------------------------------ |
| 644 // Provide simple way to to start global tracking, and to tear down tracking | 690 // Provide simple way to to start global tracking, and to tear down tracking |
| 645 // when done. Note that construction and destruction of this object must be | 691 // when done. The design has evolved to *not* do any teardown (and just leak |
| 646 // done when running in threaded mode (before spawning a lot of threads | 692 // all allocated data structures). As a result, we don't have any code in this |
| 647 // for construction, and after shutting down all the threads for destruction). | 693 // destructor, and perhaps this whole class should go away. |
| 648 | |
| 649 // To prevent grabbing thread local store resources time and again if someone | |
| 650 // chooses to try to re-run the browser many times, we maintain global state and | |
| 651 // only allow the tracking system to be started up at most once, and shutdown | |
| 652 // at most once. See bug 31344 for an example. | |
| 653 | 694 |
| 654 class BASE_EXPORT AutoTracking { | 695 class BASE_EXPORT AutoTracking { |
| 655 public: | 696 public: |
| 656 AutoTracking() { | 697 AutoTracking() { |
| 657 if (state_ != kNeverBeenRun) | 698 if (state_ != kNeverBeenRun) |
| 658 return; | 699 return; |
| 659 ThreadData::StartTracking(true); | 700 ThreadData::StartTracking(true); |
| 660 state_ = kRunning; | 701 state_ = kRunning; |
| 661 } | 702 } |
| 662 | 703 |
| 663 ~AutoTracking() { | 704 ~AutoTracking() { |
| 664 #ifndef NDEBUG | |
| 665 if (state_ != kRunning) | |
| 666 return; | |
| 667 // We don't do cleanup of any sort in Release build because it is a | |
| 668 // complete waste of time. Since Chromium doesn't join all its thread and | |
| 669 // guarantee we're in a single threaded mode, we don't even do cleanup in | |
| 670 // debug mode, as it will generate race-checker warnings. | |
| 671 #endif | |
| 672 } | 705 } |
| 673 | 706 |
| 674 private: | 707 private: |
| 675 enum State { | 708 enum State { |
| 676 kNeverBeenRun, | 709 kNeverBeenRun, |
| 677 kRunning, | 710 kRunning, |
| 678 kTornDownAndStopped, | |
| 679 }; | 711 }; |
| 680 static State state_; | 712 static State state_; |
| 681 | 713 |
| 682 DISALLOW_COPY_AND_ASSIGN(AutoTracking); | 714 DISALLOW_COPY_AND_ASSIGN(AutoTracking); |
| 683 }; | 715 }; |
| 684 | 716 |
| 685 | |
| 686 } // namespace tracked_objects | 717 } // namespace tracked_objects |
| 687 | 718 |
| 688 #endif // BASE_TRACKED_OBJECTS_H_ | 719 #endif // BASE_TRACKED_OBJECTS_H_ |
| OLD | NEW |