OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/tracked_objects.h" | 5 #include "base/tracked_objects.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #include "base/atomicops.h" | 10 #include "base/atomicops.h" |
11 #include "base/base_switches.h" | 11 #include "base/base_switches.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/debug/leak_annotations.h" | 14 #include "base/debug/leak_annotations.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/process/process_handle.h" | 16 #include "base/process/process_handle.h" |
17 #include "base/profiler/alternate_timer.h" | 17 #include "base/profiler/alternate_timer.h" |
| 18 #include "base/stl_util.h" |
18 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
19 #include "base/third_party/valgrind/memcheck.h" | 20 #include "base/third_party/valgrind/memcheck.h" |
20 #include "base/tracking_info.h" | 21 #include "base/tracking_info.h" |
21 | 22 |
22 using base::TimeDelta; | 23 using base::TimeDelta; |
23 | 24 |
24 namespace base { | 25 namespace base { |
25 class TimeDelta; | 26 class TimeDelta; |
26 } | 27 } |
27 | 28 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 | 221 |
221 //------------------------------------------------------------------------------ | 222 //------------------------------------------------------------------------------ |
222 Births::Births(const Location& location, const ThreadData& current) | 223 Births::Births(const Location& location, const ThreadData& current) |
223 : BirthOnThread(location, current), | 224 : BirthOnThread(location, current), |
224 birth_count_(1) { } | 225 birth_count_(1) { } |
225 | 226 |
226 int Births::birth_count() const { return birth_count_; } | 227 int Births::birth_count() const { return birth_count_; } |
227 | 228 |
228 void Births::RecordBirth() { ++birth_count_; } | 229 void Births::RecordBirth() { ++birth_count_; } |
229 | 230 |
| 231 void Births::SubtractBirths(int count) { |
| 232 birth_count_ -= count; |
| 233 } |
| 234 |
230 //------------------------------------------------------------------------------ | 235 //------------------------------------------------------------------------------ |
231 // ThreadData maintains the central data for all births and deaths on a single | 236 // ThreadData maintains the central data for all births and deaths on a single |
232 // thread. | 237 // thread. |
233 | 238 |
234 // TODO(jar): We should pull all these static vars together, into a struct, and | 239 // TODO(jar): We should pull all these static vars together, into a struct, and |
235 // optimize layout so that we benefit from locality of reference during accesses | 240 // optimize layout so that we benefit from locality of reference during accesses |
236 // to them. | 241 // to them. |
237 | 242 |
238 // static | 243 // static |
239 NowFunction* ThreadData::now_function_ = NULL; | 244 NowFunction* ThreadData::now_function_ = NULL; |
(...skipping 22 matching lines...) Expand all Loading... |
262 // static | 267 // static |
263 ThreadData* ThreadData::first_retired_worker_ = NULL; | 268 ThreadData* ThreadData::first_retired_worker_ = NULL; |
264 | 269 |
265 // static | 270 // static |
266 base::LazyInstance<base::Lock>::Leaky | 271 base::LazyInstance<base::Lock>::Leaky |
267 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; | 272 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; |
268 | 273 |
269 // static | 274 // static |
270 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; | 275 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; |
271 | 276 |
| 277 // static |
| 278 base::LazyInstance<PhasedProcessDataSnapshotMap> |
| 279 ThreadData::completed_phases_snapshots_ = LAZY_INSTANCE_INITIALIZER; |
| 280 |
272 ThreadData::ThreadData(const std::string& suggested_name) | 281 ThreadData::ThreadData(const std::string& suggested_name) |
273 : next_(NULL), | 282 : next_(NULL), |
274 next_retired_worker_(NULL), | 283 next_retired_worker_(NULL), |
275 worker_thread_number_(0), | 284 worker_thread_number_(0), |
276 incarnation_count_for_pool_(-1), | 285 incarnation_count_for_pool_(-1), |
277 current_stopwatch_(NULL) { | 286 current_stopwatch_(NULL) { |
278 DCHECK_GE(suggested_name.size(), 0u); | 287 DCHECK_GE(suggested_name.size(), 0u); |
279 thread_name_ = suggested_name; | 288 thread_name_ = suggested_name; |
280 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 289 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
281 } | 290 } |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 return; | 392 return; |
384 } | 393 } |
385 // We must NOT do any allocations during this callback. | 394 // We must NOT do any allocations during this callback. |
386 // Using the simple linked lists avoids all allocations. | 395 // Using the simple linked lists avoids all allocations. |
387 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); | 396 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); |
388 this->next_retired_worker_ = first_retired_worker_; | 397 this->next_retired_worker_ = first_retired_worker_; |
389 first_retired_worker_ = this; | 398 first_retired_worker_ = this; |
390 } | 399 } |
391 | 400 |
392 // static | 401 // static |
393 void ThreadData::Snapshot(ProcessDataSnapshot* process_data_snapshot) { | 402 void ThreadData::Snapshot(int current_profiling_phase, |
| 403 ProcessDataSnapshot* process_data_snapshot) { |
| 404 process_data_snapshot->phased_process_data_snapshots = |
| 405 completed_phases_snapshots_.Get(); |
| 406 |
| 407 DCHECK(!ContainsKey(process_data_snapshot->phased_process_data_snapshots, |
| 408 current_profiling_phase)); |
394 ThreadData::SnapshotCurrentPhase( | 409 ThreadData::SnapshotCurrentPhase( |
395 &process_data_snapshot->phased_process_data_snapshots[0]); | 410 false, &process_data_snapshot |
| 411 ->phased_process_data_snapshots[current_profiling_phase]); |
| 412 } |
| 413 |
| 414 // static |
| 415 void ThreadData::OnProfilingPhaseCompletion(int profiling_phase) { |
| 416 if (!kTrackAllTaskObjects) |
| 417 return; // Not compiled in. |
| 418 |
| 419 PhasedProcessDataSnapshotMap& snapshots = completed_phases_snapshots_.Get(); |
| 420 DCHECK(!ContainsKey(snapshots, profiling_phase)); |
| 421 ThreadData::SnapshotCurrentPhase(true, &snapshots[profiling_phase]); |
396 } | 422 } |
397 | 423 |
398 Births* ThreadData::TallyABirth(const Location& location) { | 424 Births* ThreadData::TallyABirth(const Location& location) { |
399 BirthMap::iterator it = birth_map_.find(location); | 425 BirthMap::iterator it = birth_map_.find(location); |
400 Births* child; | 426 Births* child; |
401 if (it != birth_map_.end()) { | 427 if (it != birth_map_.end()) { |
402 child = it->second; | 428 child = it->second; |
403 child->RecordBirth(); | 429 child->RecordBirth(); |
404 } else { | 430 } else { |
405 child = new Births(location, *this); // Leak this. | 431 child = new Births(location, *this); // Leak this. |
(...skipping 11 matching lines...) Expand all Loading... |
417 // Lock since the map may get relocated now, and other threads sometimes | 443 // Lock since the map may get relocated now, and other threads sometimes |
418 // snapshot it (but they lock before copying it). | 444 // snapshot it (but they lock before copying it). |
419 base::AutoLock lock(map_lock_); | 445 base::AutoLock lock(map_lock_); |
420 parent_child_set_.insert(pair); | 446 parent_child_set_.insert(pair); |
421 } | 447 } |
422 } | 448 } |
423 | 449 |
424 return child; | 450 return child; |
425 } | 451 } |
426 | 452 |
427 void ThreadData::TallyADeath(const Births& birth, | 453 void ThreadData::TallyADeath(int32 queue_duration, |
428 int32 queue_duration, | 454 const TaskStopwatch& stopwatch, |
429 const TaskStopwatch& stopwatch) { | 455 Births* birth) { |
430 int32 run_duration = stopwatch.RunDurationMs(); | 456 int32 run_duration = stopwatch.RunDurationMs(); |
431 | 457 |
432 // Stir in some randomness, plus add constant in case durations are zero. | 458 // Stir in some randomness, plus add constant in case durations are zero. |
433 const uint32 kSomePrimeNumber = 2147483647; | 459 const uint32 kSomePrimeNumber = 2147483647; |
434 random_number_ += queue_duration + run_duration + kSomePrimeNumber; | 460 random_number_ += queue_duration + run_duration + kSomePrimeNumber; |
435 // An address is going to have some randomness to it as well ;-). | 461 // An address is going to have some randomness to it as well ;-). |
436 random_number_ ^= static_cast<uint32>(&birth - reinterpret_cast<Births*>(0)); | 462 random_number_ ^= static_cast<uint32>(birth - reinterpret_cast<Births*>(0)); |
437 | 463 |
438 // We don't have queue durations without OS timer. OS timer is automatically | 464 // We don't have queue durations without OS timer. OS timer is automatically |
439 // used for task-post-timing, so the use of an alternate timer implies all | 465 // used for task-post-timing, so the use of an alternate timer implies all |
440 // queue times are invalid, unless it was explicitly said that we can trust | 466 // queue times are invalid, unless it was explicitly said that we can trust |
441 // the alternate timer. | 467 // the alternate timer. |
442 if (kAllowAlternateTimeSourceHandling && | 468 if (kAllowAlternateTimeSourceHandling && |
443 now_function_ && | 469 now_function_ && |
444 !now_function_is_time_) { | 470 !now_function_is_time_) { |
445 queue_duration = 0; | 471 queue_duration = 0; |
446 } | 472 } |
447 | 473 |
448 DeathMap::iterator it = death_map_.find(&birth); | 474 DeathMap::iterator it = death_map_.find(birth); |
449 DeathData* death_data; | 475 DeathData* death_data; |
450 if (it != death_map_.end()) { | 476 if (it != death_map_.end()) { |
451 death_data = &it->second; | 477 death_data = &it->second; |
452 } else { | 478 } else { |
453 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 479 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
454 death_data = &death_map_[&birth]; | 480 death_data = &death_map_[birth]; |
455 } // Release lock ASAP. | 481 } // Release lock ASAP. |
456 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 482 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
457 | 483 |
458 if (!kTrackParentChildLinks) | 484 if (!kTrackParentChildLinks) |
459 return; | 485 return; |
460 if (!parent_stack_.empty()) { // We might get turned off. | 486 if (!parent_stack_.empty()) { // We might get turned off. |
461 DCHECK_EQ(parent_stack_.top(), &birth); | 487 DCHECK_EQ(parent_stack_.top(), birth); |
462 parent_stack_.pop(); | 488 parent_stack_.pop(); |
463 } | 489 } |
464 } | 490 } |
465 | 491 |
466 // static | 492 // static |
467 Births* ThreadData::TallyABirthIfActive(const Location& location) { | 493 Births* ThreadData::TallyABirthIfActive(const Location& location) { |
468 if (!kTrackAllTaskObjects) | 494 if (!kTrackAllTaskObjects) |
469 return NULL; // Not compiled in. | 495 return NULL; // Not compiled in. |
470 | 496 |
471 if (!TrackingStatus()) | 497 if (!TrackingStatus()) |
472 return NULL; | 498 return NULL; |
473 ThreadData* current_thread_data = Get(); | 499 ThreadData* current_thread_data = Get(); |
474 if (!current_thread_data) | 500 if (!current_thread_data) |
475 return NULL; | 501 return NULL; |
476 return current_thread_data->TallyABirth(location); | 502 return current_thread_data->TallyABirth(location); |
477 } | 503 } |
478 | 504 |
479 // static | 505 // static |
480 void ThreadData::TallyRunOnNamedThreadIfTracking( | 506 void ThreadData::TallyRunOnNamedThreadIfTracking( |
481 const base::TrackingInfo& completed_task, | 507 const base::TrackingInfo& completed_task, |
482 const TaskStopwatch& stopwatch) { | 508 const TaskStopwatch& stopwatch) { |
483 if (!kTrackAllTaskObjects) | 509 if (!kTrackAllTaskObjects) |
484 return; // Not compiled in. | 510 return; // Not compiled in. |
485 | 511 |
486 // Even if we have been DEACTIVATED, we will process any pending births so | 512 // Even if we have been DEACTIVATED, we will process any pending births so |
487 // that our data structures (which counted the outstanding births) remain | 513 // that our data structures (which counted the outstanding births) remain |
488 // consistent. | 514 // consistent. |
489 const Births* birth = completed_task.birth_tally; | 515 Births* birth = completed_task.birth_tally; |
490 if (!birth) | 516 if (!birth) |
491 return; | 517 return; |
492 ThreadData* current_thread_data = stopwatch.GetThreadData(); | 518 ThreadData* current_thread_data = stopwatch.GetThreadData(); |
493 if (!current_thread_data) | 519 if (!current_thread_data) |
494 return; | 520 return; |
495 | 521 |
496 // Watch out for a race where status_ is changing, and hence one or both | 522 // Watch out for a race where status_ is changing, and hence one or both |
497 // of start_of_run or end_of_run is zero. In that case, we didn't bother to | 523 // of start_of_run or end_of_run is zero. In that case, we didn't bother to |
498 // get a time value since we "weren't tracking" and we were trying to be | 524 // get a time value since we "weren't tracking" and we were trying to be |
499 // efficient by not calling for a genuine time value. For simplicity, we'll | 525 // efficient by not calling for a genuine time value. For simplicity, we'll |
500 // use a default zero duration when we can't calculate a true value. | 526 // use a default zero duration when we can't calculate a true value. |
501 TrackedTime start_of_run = stopwatch.StartTime(); | 527 TrackedTime start_of_run = stopwatch.StartTime(); |
502 int32 queue_duration = 0; | 528 int32 queue_duration = 0; |
503 if (!start_of_run.is_null()) { | 529 if (!start_of_run.is_null()) { |
504 queue_duration = (start_of_run - completed_task.EffectiveTimePosted()) | 530 queue_duration = (start_of_run - completed_task.EffectiveTimePosted()) |
505 .InMilliseconds(); | 531 .InMilliseconds(); |
506 } | 532 } |
507 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch); | 533 current_thread_data->TallyADeath(queue_duration, stopwatch, birth); |
508 } | 534 } |
509 | 535 |
510 // static | 536 // static |
511 void ThreadData::TallyRunOnWorkerThreadIfTracking( | 537 void ThreadData::TallyRunOnWorkerThreadIfTracking( |
512 const Births* birth, | |
513 const TrackedTime& time_posted, | 538 const TrackedTime& time_posted, |
514 const TaskStopwatch& stopwatch) { | 539 const TaskStopwatch& stopwatch, |
| 540 Births* birth) { |
515 if (!kTrackAllTaskObjects) | 541 if (!kTrackAllTaskObjects) |
516 return; // Not compiled in. | 542 return; // Not compiled in. |
517 | 543 |
518 // Even if we have been DEACTIVATED, we will process any pending births so | 544 // Even if we have been DEACTIVATED, we will process any pending births so |
519 // that our data structures (which counted the outstanding births) remain | 545 // that our data structures (which counted the outstanding births) remain |
520 // consistent. | 546 // consistent. |
521 if (!birth) | 547 if (!birth) |
522 return; | 548 return; |
523 | 549 |
524 // TODO(jar): Support the option to coalesce all worker-thread activity under | 550 // TODO(jar): Support the option to coalesce all worker-thread activity under |
525 // one ThreadData instance that uses locks to protect *all* access. This will | 551 // one ThreadData instance that uses locks to protect *all* access. This will |
526 // reduce memory (making it provably bounded), but run incrementally slower | 552 // reduce memory (making it provably bounded), but run incrementally slower |
527 // (since we'll use locks on TallyABirth and TallyADeath). The good news is | 553 // (since we'll use locks on TallyABirth and TallyADeath). The good news is |
528 // that the locks on TallyADeath will be *after* the worker thread has run, | 554 // that the locks on TallyADeath will be *after* the worker thread has run, |
529 // and hence nothing will be waiting for the completion (... besides some | 555 // and hence nothing will be waiting for the completion (... besides some |
530 // other thread that might like to run). Also, the worker threads tasks are | 556 // other thread that might like to run). Also, the worker threads tasks are |
531 // generally longer, and hence the cost of the lock may perchance be amortized | 557 // generally longer, and hence the cost of the lock may perchance be amortized |
532 // over the long task's lifetime. | 558 // over the long task's lifetime. |
533 ThreadData* current_thread_data = stopwatch.GetThreadData(); | 559 ThreadData* current_thread_data = stopwatch.GetThreadData(); |
534 if (!current_thread_data) | 560 if (!current_thread_data) |
535 return; | 561 return; |
536 | 562 |
537 TrackedTime start_of_run = stopwatch.StartTime(); | 563 TrackedTime start_of_run = stopwatch.StartTime(); |
538 int32 queue_duration = 0; | 564 int32 queue_duration = 0; |
539 if (!start_of_run.is_null()) { | 565 if (!start_of_run.is_null()) { |
540 queue_duration = (start_of_run - time_posted).InMilliseconds(); | 566 queue_duration = (start_of_run - time_posted).InMilliseconds(); |
541 } | 567 } |
542 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch); | 568 current_thread_data->TallyADeath(queue_duration, stopwatch, birth); |
543 } | 569 } |
544 | 570 |
545 // static | 571 // static |
546 void ThreadData::TallyRunInAScopedRegionIfTracking( | 572 void ThreadData::TallyRunInAScopedRegionIfTracking( |
547 const Births* birth, | 573 const TaskStopwatch& stopwatch, |
548 const TaskStopwatch& stopwatch) { | 574 Births* birth) { |
549 if (!kTrackAllTaskObjects) | 575 if (!kTrackAllTaskObjects) |
550 return; // Not compiled in. | 576 return; // Not compiled in. |
551 | 577 |
552 // Even if we have been DEACTIVATED, we will process any pending births so | 578 // Even if we have been DEACTIVATED, we will process any pending births so |
553 // that our data structures (which counted the outstanding births) remain | 579 // that our data structures (which counted the outstanding births) remain |
554 // consistent. | 580 // consistent. |
555 if (!birth) | 581 if (!birth) |
556 return; | 582 return; |
557 | 583 |
558 ThreadData* current_thread_data = stopwatch.GetThreadData(); | 584 ThreadData* current_thread_data = stopwatch.GetThreadData(); |
559 if (!current_thread_data) | 585 if (!current_thread_data) |
560 return; | 586 return; |
561 | 587 |
562 int32 queue_duration = 0; | 588 int32 queue_duration = 0; |
563 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch); | 589 current_thread_data->TallyADeath(queue_duration, stopwatch, birth); |
564 } | 590 } |
565 | 591 |
566 // static | 592 // static |
567 void ThreadData::SnapshotAllExecutedTasks( | 593 void ThreadData::SnapshotAllExecutedTasks( |
| 594 bool reset, |
568 ProcessDataPhaseSnapshot* process_data_phase, | 595 ProcessDataPhaseSnapshot* process_data_phase, |
569 BirthCountMap* birth_counts) { | 596 BirthCountMap* birth_counts) { |
570 if (!kTrackAllTaskObjects) | 597 if (!kTrackAllTaskObjects) |
571 return; // Not compiled in. | 598 return; // Not compiled in. |
572 | 599 |
573 // Get an unchanging copy of a ThreadData list. | 600 // Get an unchanging copy of a ThreadData list. |
574 ThreadData* my_list = ThreadData::first(); | 601 ThreadData* my_list = ThreadData::first(); |
575 | 602 |
576 // Gather data serially. | 603 // Gather data serially. |
577 // This hackish approach *can* get some slighly corrupt tallies, as we are | 604 // This hackish approach *can* get some slighly corrupt tallies, as we are |
578 // grabbing values without the protection of a lock, but it has the advantage | 605 // grabbing values without the protection of a lock, but it has the advantage |
579 // of working even with threads that don't have message loops. If a user | 606 // of working even with threads that don't have message loops. If a user |
580 // sees any strangeness, they can always just run their stats gathering a | 607 // sees any strangeness, they can always just run their stats gathering a |
581 // second time. | 608 // second time. |
582 for (ThreadData* thread_data = my_list; | 609 for (ThreadData* thread_data = my_list; |
583 thread_data; | 610 thread_data; |
584 thread_data = thread_data->next()) { | 611 thread_data = thread_data->next()) { |
585 thread_data->SnapshotExecutedTasks(process_data_phase, birth_counts); | 612 thread_data->SnapshotExecutedTasks(reset, process_data_phase, birth_counts); |
586 } | 613 } |
587 } | 614 } |
588 | 615 |
589 // static | 616 // static |
590 void ThreadData::SnapshotCurrentPhase( | 617 void ThreadData::SnapshotCurrentPhase( |
| 618 bool reset, |
591 ProcessDataPhaseSnapshot* process_data_phase) { | 619 ProcessDataPhaseSnapshot* process_data_phase) { |
592 // Add births that have run to completion to |collected_data|. | 620 // Add births that have run to completion to |collected_data|. |
593 // |birth_counts| tracks the total number of births recorded at each location | 621 // |birth_counts| tracks the total number of births recorded at each location |
594 // for which we have not seen a death count. | 622 // for which we have not seen a death count. |
595 BirthCountMap birth_counts; | 623 BirthCountMap birth_counts; |
596 ThreadData::SnapshotAllExecutedTasks(process_data_phase, &birth_counts); | 624 ThreadData::SnapshotAllExecutedTasks(reset, process_data_phase, |
| 625 &birth_counts); |
597 | 626 |
598 // Add births that are still active -- i.e. objects that have tallied a birth, | 627 // Add births that are still active -- i.e. objects that have tallied a birth, |
599 // but have not yet tallied a matching death, and hence must be either | 628 // but have not yet tallied a matching death, and hence must be either |
600 // running, queued up, or being held in limbo for future posting. | 629 // running, queued up, or being held in limbo for future posting. |
601 for (const auto& birth_count : birth_counts) { | 630 for (const auto& birth_count : birth_counts) { |
602 if (birth_count.second > 0) { | 631 if (birth_count.second > 0) { |
603 process_data_phase->tasks.push_back(TaskSnapshot( | 632 process_data_phase->tasks.push_back(TaskSnapshot( |
604 *birth_count.first, DeathData(birth_count.second), "Still_Alive")); | 633 *birth_count.first, DeathData(birth_count.second), "Still_Alive")); |
605 } | 634 } |
606 } | 635 } |
607 } | 636 } |
608 | 637 |
609 void ThreadData::SnapshotExecutedTasks( | 638 void ThreadData::SnapshotExecutedTasks( |
| 639 bool reset, |
610 ProcessDataPhaseSnapshot* process_data_phase, | 640 ProcessDataPhaseSnapshot* process_data_phase, |
611 BirthCountMap* birth_counts) { | 641 BirthCountMap* birth_counts) { |
612 // Get copy of data, so that the data will not change during the iterations | 642 // Get copy of data, so that the data will not change during the iterations |
613 // and processing. | 643 // and processing. |
614 ThreadData::BirthMap birth_map; | 644 ThreadData::BirthMap birth_map; |
615 ThreadData::DeathMap death_map; | 645 ThreadData::DeathMap death_map; |
616 ThreadData::ParentChildSet parent_child_set; | 646 ThreadData::ParentChildSet parent_child_set; |
617 SnapshotMaps(&birth_map, &death_map, &parent_child_set); | 647 SnapshotMaps(reset, &birth_map, &death_map, &parent_child_set); |
618 | 648 |
619 for (const auto& death : death_map) { | 649 for (const auto& death : death_map) { |
620 process_data_phase->tasks.push_back( | 650 process_data_phase->tasks.push_back( |
621 TaskSnapshot(*death.first, death.second, thread_name())); | 651 TaskSnapshot(*death.first, death.second, thread_name())); |
622 (*birth_counts)[death.first] -= death.first->birth_count(); | 652 // We don't populate birth_counts if |reset| is true. |
| 653 if (!reset) |
| 654 (*birth_counts)[death.first] -= death.first->birth_count(); |
623 } | 655 } |
624 | 656 |
625 for (const auto& birth : birth_map) { | 657 for (const auto& birth : birth_map) { |
626 (*birth_counts)[birth.second] += birth.second->birth_count(); | 658 (*birth_counts)[birth.second] += birth.second->birth_count(); |
627 } | 659 } |
628 | 660 |
629 if (!kTrackParentChildLinks) | 661 if (!kTrackParentChildLinks) |
630 return; | 662 return; |
631 | 663 |
632 for (const auto& parent_child : parent_child_set) { | 664 for (const auto& parent_child : parent_child_set) { |
633 process_data_phase->descendants.push_back( | 665 process_data_phase->descendants.push_back( |
634 ParentChildPairSnapshot(parent_child)); | 666 ParentChildPairSnapshot(parent_child)); |
635 } | 667 } |
636 } | 668 } |
637 | 669 |
638 // This may be called from another thread. | 670 // This may be called from another thread. |
639 void ThreadData::SnapshotMaps(BirthMap* birth_map, | 671 void ThreadData::SnapshotMaps(bool reset, |
| 672 BirthMap* birth_map, |
640 DeathMap* death_map, | 673 DeathMap* death_map, |
641 ParentChildSet* parent_child_set) { | 674 ParentChildSet* parent_child_set) { |
642 base::AutoLock lock(map_lock_); | 675 base::AutoLock lock(map_lock_); |
643 for (const auto& birth : birth_map_) | 676 if (!reset) { |
644 (*birth_map)[birth.first] = birth.second; | 677 // When reset is not requested, snapshot births. |
645 for (auto& death : death_map_) | 678 for (const auto& birth : birth_map_) |
| 679 (*birth_map)[birth.first] = birth.second; |
| 680 } |
| 681 for (auto& death : death_map_) { |
| 682 // Don't snapshot deaths with 0 count. Deaths with 0 count can result from |
| 683 // prior calls to SnapshotMaps with reset=true param. |
| 684 if (death.second.count() <= 0) |
| 685 continue; |
| 686 |
646 (*death_map)[death.first] = death.second; | 687 (*death_map)[death.first] = death.second; |
| 688 if (reset) { |
| 689 death.first->SubtractBirths(death.second.count()); |
| 690 death.second.Clear(); |
| 691 } |
| 692 } |
647 | 693 |
648 if (!kTrackParentChildLinks) | 694 if (!kTrackParentChildLinks) |
649 return; | 695 return; |
650 | 696 |
651 for (const auto& parent_child : parent_child_set_) | 697 for (const auto& parent_child : parent_child_set_) |
652 parent_child_set->insert(parent_child); | 698 parent_child_set->insert(parent_child); |
653 } | 699 } |
654 | 700 |
655 static void OptionallyInitializeAlternateTimer() { | 701 static void OptionallyInitializeAlternateTimer() { |
656 NowFunction* alternate_time_source = GetAlternateTimeSource(); | 702 NowFunction* alternate_time_source = GetAlternateTimeSource(); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
826 // Do actual recursive delete in all ThreadData instances. | 872 // Do actual recursive delete in all ThreadData instances. |
827 while (thread_data_list) { | 873 while (thread_data_list) { |
828 ThreadData* next_thread_data = thread_data_list; | 874 ThreadData* next_thread_data = thread_data_list; |
829 thread_data_list = thread_data_list->next(); | 875 thread_data_list = thread_data_list->next(); |
830 | 876 |
831 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 877 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
832 next_thread_data->birth_map_.end() != it; ++it) | 878 next_thread_data->birth_map_.end() != it; ++it) |
833 delete it->second; // Delete the Birth Records. | 879 delete it->second; // Delete the Birth Records. |
834 delete next_thread_data; // Includes all Death Records. | 880 delete next_thread_data; // Includes all Death Records. |
835 } | 881 } |
| 882 |
| 883 completed_phases_snapshots_.Get().clear(); |
836 } | 884 } |
837 | 885 |
838 //------------------------------------------------------------------------------ | 886 //------------------------------------------------------------------------------ |
839 TaskStopwatch::TaskStopwatch() | 887 TaskStopwatch::TaskStopwatch() |
840 : wallclock_duration_ms_(0), | 888 : wallclock_duration_ms_(0), |
841 current_thread_data_(NULL), | 889 current_thread_data_(NULL), |
842 excluded_duration_ms_(0), | 890 excluded_duration_ms_(0), |
843 parent_(NULL) { | 891 parent_(NULL) { |
844 #if DCHECK_IS_ON() | 892 #if DCHECK_IS_ON() |
845 state_ = CREATED; | 893 state_ = CREATED; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 : process_id(base::GetCurrentProcId()) { | 1025 : process_id(base::GetCurrentProcId()) { |
978 #else | 1026 #else |
979 : process_id(base::kNullProcessId) { | 1027 : process_id(base::kNullProcessId) { |
980 #endif | 1028 #endif |
981 } | 1029 } |
982 | 1030 |
983 ProcessDataSnapshot::~ProcessDataSnapshot() { | 1031 ProcessDataSnapshot::~ProcessDataSnapshot() { |
984 } | 1032 } |
985 | 1033 |
986 } // namespace tracked_objects | 1034 } // namespace tracked_objects |
OLD | NEW |