| 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 #include "base/tracked_objects.h" | 5 #include "base/tracked_objects.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 void ThreadData::OnThreadTerminationCleanup() const { | 213 void ThreadData::OnThreadTerminationCleanup() const { |
| 214 tls_index_.Set(NULL); | 214 tls_index_.Set(NULL); |
| 215 if (!is_a_worker_thread_) | 215 if (!is_a_worker_thread_) |
| 216 return; | 216 return; |
| 217 base::AutoLock lock(*list_lock_); | 217 base::AutoLock lock(*list_lock_); |
| 218 unregistered_thread_data_pool_->push(this); | 218 unregistered_thread_data_pool_->push(this); |
| 219 } | 219 } |
| 220 | 220 |
| 221 // static | 221 // static |
| 222 void ThreadData::WriteHTML(const std::string& query, std::string* output) { | 222 void ThreadData::WriteHTML(const std::string& query, std::string* output) { |
| 223 if (!ThreadData::tracking_status()) | 223 if (status_ == UNINITIALIZED) |
| 224 return; // Not yet initialized. | 224 return; // Not yet initialized. |
| 225 | 225 |
| 226 DataCollector collected_data; // Gather data. | 226 DataCollector collected_data; // Gather data. |
| 227 collected_data.AddListOfLivingObjects(); // Add births that are still alive. | 227 collected_data.AddListOfLivingObjects(); // Add births that are still alive. |
| 228 | 228 |
| 229 // Data Gathering is complete. Now to sort/process/render. | 229 // Data Gathering is complete. Now to sort/process/render. |
| 230 DataCollector::Collection* collection = collected_data.collection(); | 230 DataCollector::Collection* collection = collected_data.collection(); |
| 231 | 231 |
| 232 // Create filtering and sort comparison object. | 232 // Create filtering and sort comparison object. |
| 233 Comparator comparator; | 233 Comparator comparator; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 // To avoid conflating our stats with the delay duration in a PostDelayedTask, | 399 // To avoid conflating our stats with the delay duration in a PostDelayedTask, |
| 400 // we identify such tasks, and replace their post_time with the time they | 400 // we identify such tasks, and replace their post_time with the time they |
| 401 // were scheduled (requested?) to emerge from the delayed task queue. This | 401 // were scheduled (requested?) to emerge from the delayed task queue. This |
| 402 // means that queueing delay for such tasks will show how long they went | 402 // means that queueing delay for such tasks will show how long they went |
| 403 // unserviced, after they *could* be serviced. This is the same stat as we | 403 // unserviced, after they *could* be serviced. This is the same stat as we |
| 404 // have for non-delayed tasks, and we consistently call it queueing delay. | 404 // have for non-delayed tasks, and we consistently call it queueing delay. |
| 405 TrackedTime effective_post_time = completed_task.delayed_run_time.is_null() | 405 TrackedTime effective_post_time = completed_task.delayed_run_time.is_null() |
| 406 ? tracked_objects::TrackedTime(completed_task.time_posted) | 406 ? tracked_objects::TrackedTime(completed_task.time_posted) |
| 407 : tracked_objects::TrackedTime(completed_task.delayed_run_time); | 407 : tracked_objects::TrackedTime(completed_task.delayed_run_time); |
| 408 | 408 |
| 409 Duration queue_duration = start_of_run - effective_post_time; | 409 // Watch out for a race where status_ is changing, and hence one or both |
| 410 Duration run_duration = end_of_run - start_of_run; | 410 // of start_of_run or end_of_run is zero. IN that case, we didn't bother to |
| 411 // get a time value since we "weren't tracking" and we were trying to be |
| 412 // efficient by not calling for a genuine time value. For simplicity, we'll |
| 413 // use a default zero duration when we can't calculate a true value. |
| 414 Duration queue_duration; |
| 415 Duration run_duration; |
| 416 if (!start_of_run.is_null()) { |
| 417 queue_duration = start_of_run - effective_post_time; |
| 418 if (!end_of_run.is_null()) |
| 419 run_duration = end_of_run - start_of_run; |
| 420 } |
| 411 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); | 421 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); |
| 412 } | 422 } |
| 413 | 423 |
| 414 // static | 424 // static |
| 415 void ThreadData::TallyRunOnWorkerThreadIfTracking( | 425 void ThreadData::TallyRunOnWorkerThreadIfTracking( |
| 416 const Births* birth, | 426 const Births* birth, |
| 417 const TrackedTime& time_posted, | 427 const TrackedTime& time_posted, |
| 418 const TrackedTime& start_of_run, | 428 const TrackedTime& start_of_run, |
| 419 const TrackedTime& end_of_run) { | 429 const TrackedTime& end_of_run) { |
| 420 if (!kTrackAllTaskObjects) | 430 if (!kTrackAllTaskObjects) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 432 // (since we'll use locks on TallyBirth and TallyDeath). The good news is | 442 // (since we'll use locks on TallyBirth and TallyDeath). The good news is |
| 433 // that the locks on TallyDeath will be *after* the worker thread has run, and | 443 // that the locks on TallyDeath will be *after* the worker thread has run, and |
| 434 // hence nothing will be waiting for the completion (... besides some other | 444 // hence nothing will be waiting for the completion (... besides some other |
| 435 // thread that might like to run). Also, the worker threads tasks are | 445 // thread that might like to run). Also, the worker threads tasks are |
| 436 // generally longer, and hence the cost of the lock may perchance be amortized | 446 // generally longer, and hence the cost of the lock may perchance be amortized |
| 437 // over the long task's lifetime. | 447 // over the long task's lifetime. |
| 438 ThreadData* current_thread_data = Get(); | 448 ThreadData* current_thread_data = Get(); |
| 439 if (!current_thread_data) | 449 if (!current_thread_data) |
| 440 return; | 450 return; |
| 441 | 451 |
| 442 Duration queue_duration = start_of_run - time_posted; | 452 Duration queue_duration; |
| 443 Duration run_duration = end_of_run - start_of_run; | 453 Duration run_duration; |
| 454 if (!start_of_run.is_null()) { |
| 455 queue_duration = start_of_run - time_posted; |
| 456 if (!end_of_run.is_null()) |
| 457 run_duration = end_of_run - start_of_run; |
| 458 } |
| 444 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); | 459 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); |
| 445 } | 460 } |
| 446 | 461 |
| 447 // static | 462 // static |
| 448 ThreadData* ThreadData::first() { | 463 ThreadData* ThreadData::first() { |
| 449 base::AutoLock lock(*list_lock_); | 464 base::AutoLock lock(*list_lock_); |
| 450 return all_thread_data_list_head_; | 465 return all_thread_data_list_head_; |
| 451 } | 466 } |
| 452 | 467 |
| 453 // This may be called from another thread. | 468 // This may be called from another thread. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 return true; | 532 return true; |
| 518 } | 533 } |
| 519 | 534 |
| 520 // static | 535 // static |
| 521 bool ThreadData::tracking_status() { | 536 bool ThreadData::tracking_status() { |
| 522 return status_ == ACTIVE; | 537 return status_ == ACTIVE; |
| 523 } | 538 } |
| 524 | 539 |
| 525 // static | 540 // static |
| 526 TrackedTime ThreadData::Now() { | 541 TrackedTime ThreadData::Now() { |
| 527 if (!kTrackAllTaskObjects || status_ != ACTIVE) | 542 if (kTrackAllTaskObjects && tracking_status()) |
| 528 return TrackedTime(); // Super fast when disabled, or not compiled. | 543 return TrackedTime::Now(); |
| 529 return TrackedTime::Now(); | 544 return TrackedTime(); // Super fast when disabled, or not compiled. |
| 530 } | 545 } |
| 531 | 546 |
| 532 // static | 547 // static |
| 533 void ThreadData::ShutdownSingleThreadedCleanup() { | 548 void ThreadData::ShutdownSingleThreadedCleanup() { |
| 534 // This is only called from test code, where we need to cleanup so that | 549 // This is only called from test code, where we need to cleanup so that |
| 535 // additional tests can be run. | 550 // additional tests can be run. |
| 536 // We must be single threaded... but be careful anyway. | 551 // We must be single threaded... but be careful anyway. |
| 537 if (!InitializeAndSetTrackingStatus(false)) | 552 if (!InitializeAndSetTrackingStatus(false)) |
| 538 return; | 553 return; |
| 539 ThreadData* thread_data_list; | 554 ThreadData* thread_data_list; |
| 540 ThreadDataPool* final_pool; | 555 ThreadDataPool* final_pool; |
| 541 { | 556 { |
| 542 base::AutoLock lock(*list_lock_); | 557 base::AutoLock lock(*list_lock_); |
| 543 thread_data_list = all_thread_data_list_head_; | 558 thread_data_list = all_thread_data_list_head_; |
| 544 all_thread_data_list_head_ = NULL; | 559 all_thread_data_list_head_ = NULL; |
| 545 final_pool = unregistered_thread_data_pool_; | 560 final_pool = unregistered_thread_data_pool_; |
| 546 unregistered_thread_data_pool_ = NULL; | 561 unregistered_thread_data_pool_ = NULL; |
| 547 } | 562 } |
| 548 | 563 |
| 564 // Put most global static back in pristine shape. |
| 565 thread_number_counter_ = 0; |
| 566 tls_index_.Set(NULL); |
| 567 status_ = UNINITIALIZED; |
| 568 |
| 569 // To avoid any chance of racing in unit tests, which is the only place we |
| 570 // call this function, we will leak all the data structures we recovered. |
| 571 // These structures could plausibly be used by other threads in earlier tests |
| 572 // that are still running. |
| 573 return; |
| 574 |
| 575 // If we wanted to cleanup (on a single thread), here is what we would do. |
| 576 |
| 549 if (final_pool) { | 577 if (final_pool) { |
| 550 // The thread_data_list contains *all* the instances, and we'll use it to | 578 // The thread_data_list contains *all* the instances, and we'll use it to |
| 551 // delete them. This pool has pointers to some instances, and we just | 579 // delete them. This pool has pointers to some instances, and we just |
| 552 // have to drop those pointers (and not do the deletes here). | 580 // have to drop those pointers (and not do the deletes here). |
| 553 while (!final_pool->empty()) | 581 while (!final_pool->empty()) |
| 554 final_pool->pop(); | 582 final_pool->pop(); |
| 555 delete final_pool; | 583 delete final_pool; |
| 556 } | 584 } |
| 557 | 585 |
| 558 // Do actual recursive delete in all ThreadData instances. | 586 // Do actual recursive delete in all ThreadData instances. |
| 559 while (thread_data_list) { | 587 while (thread_data_list) { |
| 560 ThreadData* next_thread_data = thread_data_list; | 588 ThreadData* next_thread_data = thread_data_list; |
| 561 thread_data_list = thread_data_list->next(); | 589 thread_data_list = thread_data_list->next(); |
| 562 | 590 |
| 563 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 591 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
| 564 next_thread_data->birth_map_.end() != it; ++it) | 592 next_thread_data->birth_map_.end() != it; ++it) |
| 565 delete it->second; // Delete the Birth Records. | 593 delete it->second; // Delete the Birth Records. |
| 566 next_thread_data->birth_map_.clear(); | 594 next_thread_data->birth_map_.clear(); |
| 567 next_thread_data->death_map_.clear(); | 595 next_thread_data->death_map_.clear(); |
| 568 delete next_thread_data; // Includes all Death Records. | 596 delete next_thread_data; // Includes all Death Records. |
| 569 } | 597 } |
| 570 // Put most global static back in pristine shape. | |
| 571 thread_number_counter_ = 0; | |
| 572 tls_index_.Set(NULL); | |
| 573 status_ = UNINITIALIZED; | |
| 574 } | 598 } |
| 575 | 599 |
| 576 //------------------------------------------------------------------------------ | 600 //------------------------------------------------------------------------------ |
| 577 // Individual 3-tuple of birth (place and thread) along with death thread, and | 601 // Individual 3-tuple of birth (place and thread) along with death thread, and |
| 578 // the accumulated stats for instances (DeathData). | 602 // the accumulated stats for instances (DeathData). |
| 579 | 603 |
| 580 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, | 604 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, |
| 581 const ThreadData& death_thread, | 605 const ThreadData& death_thread, |
| 582 const DeathData& death_data) | 606 const DeathData& death_data) |
| 583 : birth_(&birth_on_thread), | 607 : birth_(&birth_on_thread), |
| (...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 (combined_selectors_ & BIRTH_THREAD) ? "*" : | 1138 (combined_selectors_ & BIRTH_THREAD) ? "*" : |
| 1115 sample.birth().birth_thread()->thread_name().c_str(), | 1139 sample.birth().birth_thread()->thread_name().c_str(), |
| 1116 (combined_selectors_ & DEATH_THREAD) ? "*" : | 1140 (combined_selectors_ & DEATH_THREAD) ? "*" : |
| 1117 sample.DeathThreadName().c_str()); | 1141 sample.DeathThreadName().c_str()); |
| 1118 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), | 1142 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), |
| 1119 !(combined_selectors_ & BIRTH_FUNCTION), | 1143 !(combined_selectors_ & BIRTH_FUNCTION), |
| 1120 output); | 1144 output); |
| 1121 } | 1145 } |
| 1122 | 1146 |
| 1123 } // namespace tracked_objects | 1147 } // namespace tracked_objects |
| OLD | NEW |