| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/profiler/stack_sampling_profiler.h" | 5 #include "base/profiler/stack_sampling_profiler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 callback(callback), | 150 callback(callback), |
| 151 finished(finished), | 151 finished(finished), |
| 152 native_sampler(std::move(sampler)) {} | 152 native_sampler(std::move(sampler)) {} |
| 153 ~CollectionContext() {} | 153 ~CollectionContext() {} |
| 154 | 154 |
| 155 // An identifier for this collection, used to uniquely identify it to | 155 // An identifier for this collection, used to uniquely identify it to |
| 156 // outside interests. | 156 // outside interests. |
| 157 const int collection_id; | 157 const int collection_id; |
| 158 | 158 |
| 159 const PlatformThreadId target; // ID of The thread being sampled. | 159 const PlatformThreadId target; // ID of The thread being sampled. |
| 160 const SamplingParams params; // Information about how to sample. | 160 |
| 161 // Information about how to sample. Not const because they can be updated |
| 162 // upon collection completion by |callback|. |
| 163 SamplingParams params; |
| 164 |
| 161 const CompletedCallback callback; // Callback made when sampling complete. | 165 const CompletedCallback callback; // Callback made when sampling complete. |
| 162 WaitableEvent* const finished; // Signaled when all sampling complete. | 166 WaitableEvent* const finished; // Signaled when all sampling complete. |
| 163 | 167 |
| 164 // Platform-specific module that does the actual sampling. | 168 // Platform-specific module that does the actual sampling. |
| 165 std::unique_ptr<NativeStackSampler> native_sampler; | 169 std::unique_ptr<NativeStackSampler> native_sampler; |
| 166 | 170 |
| 167 // The absolute time for the next sample. | 171 // The absolute time for the next sample. |
| 168 Time next_sample_time; | 172 Time next_sample_time; |
| 169 | 173 |
| 170 // The time that a profile was started, for calculating the total duration. | 174 // The time that a profile was started, for calculating the total duration. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 ~SamplingThread() override; | 225 ~SamplingThread() override; |
| 222 | 226 |
| 223 // Get task runner that is usable from the outside. | 227 // Get task runner that is usable from the outside. |
| 224 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd(); | 228 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd(); |
| 225 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner( | 229 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner( |
| 226 ThreadExecutionState* out_state); | 230 ThreadExecutionState* out_state); |
| 227 | 231 |
| 228 // Get task runner that is usable from the sampling thread itself. | 232 // Get task runner that is usable from the sampling thread itself. |
| 229 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); | 233 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); |
| 230 | 234 |
| 231 // Finishes a collection and reports collected data via callback. | 235 // Finishes a collection and reports collected data via callback. Returns |
| 232 void FinishCollection(CollectionContext* collection); | 236 // whether collection should be restarted per the callback. |
| 237 bool FinishCollection(CollectionContext* collection); |
| 233 | 238 |
| 234 // Records a single sample of a collection. | 239 // Records a single sample of a collection. |
| 235 void RecordSample(CollectionContext* collection); | 240 void RecordSample(CollectionContext* collection); |
| 236 | 241 |
| 237 // Check if the sampling thread is idle and begin a shutdown if it is. | 242 // Check if the sampling thread is idle and begin a shutdown if it is. |
| 238 void ScheduleShutdownIfIdle(); | 243 void ScheduleShutdownIfIdle(); |
| 239 | 244 |
| 240 // These methods are tasks that get posted to the internal message queue. | 245 // These methods are tasks that get posted to the internal message queue. |
| 241 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); | 246 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); |
| 242 void RemoveCollectionTask(int id); | 247 void RemoveCollectionTask(int id); |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 | 471 |
| 467 scoped_refptr<SingleThreadTaskRunner> | 472 scoped_refptr<SingleThreadTaskRunner> |
| 468 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { | 473 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { |
| 469 // This should be called only from the sampling thread as it has limited | 474 // This should be called only from the sampling thread as it has limited |
| 470 // accessibility. | 475 // accessibility. |
| 471 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 476 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 472 | 477 |
| 473 return Thread::task_runner(); | 478 return Thread::task_runner(); |
| 474 } | 479 } |
| 475 | 480 |
| 476 void StackSamplingProfiler::SamplingThread::FinishCollection( | 481 bool StackSamplingProfiler::SamplingThread::FinishCollection( |
| 477 CollectionContext* collection) { | 482 CollectionContext* collection) { |
| 478 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 483 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 479 | 484 |
| 480 // If there is no duration for the final profile (because it was stopped), | 485 // If there is no duration for the final profile (because it was stopped), |
| 481 // calculate it now. | 486 // calculate it now. |
| 482 if (!collection->profiles.empty() && | 487 if (!collection->profiles.empty() && |
| 483 collection->profiles.back().profile_duration == TimeDelta()) { | 488 collection->profiles.back().profile_duration == TimeDelta()) { |
| 484 collection->profiles.back().profile_duration = | 489 collection->profiles.back().profile_duration = |
| 485 Time::Now() - collection->profile_start_time; | 490 Time::Now() - collection->profile_start_time; |
| 486 } | 491 } |
| 487 | 492 |
| 488 // Extract some information so callback and event-signalling can still be | 493 // Extract some information so callback and event-signalling can still be |
| 489 // done after the collection has been removed from the list of "active" ones. | 494 // done after the collection has been removed from the list of "active" ones. |
| 490 // This allows the the controlling object (and tests using it) to be confident | 495 // This allows the the controlling object (and tests using it) to be confident |
| 491 // that collection is fully finished when those things occur. | 496 // that collection is fully finished when those things occur. |
| 492 const CompletedCallback callback = collection->callback; | 497 const CompletedCallback callback = collection->callback; |
| 493 CallStackProfiles profiles = std::move(collection->profiles); | 498 CallStackProfiles profiles = std::move(collection->profiles); |
| 494 WaitableEvent* finished = collection->finished; | 499 WaitableEvent* finished = collection->finished; |
| 495 | 500 |
| 496 // Remove this collection from the map of known ones. The |collection| | |
| 497 // parameter is invalid after this point. | |
| 498 size_t count = active_collections_.erase(collection->collection_id); | |
| 499 DCHECK_EQ(1U, count); | |
| 500 | |
| 501 // Run the associated callback, passing the collected profiles. | 501 // Run the associated callback, passing the collected profiles. |
| 502 callback.Run(std::move(profiles)); | 502 bool restart_collection = |
| 503 callback.Run(std::move(profiles), &collection->params); |
| 503 | 504 |
| 504 // Signal that this collection is finished. | 505 // Signal that this collection is finished. |
| 505 finished->Signal(); | 506 finished->Signal(); |
| 507 |
| 508 return restart_collection; |
| 506 } | 509 } |
| 507 | 510 |
| 508 void StackSamplingProfiler::SamplingThread::RecordSample( | 511 void StackSamplingProfiler::SamplingThread::RecordSample( |
| 509 CollectionContext* collection) { | 512 CollectionContext* collection) { |
| 510 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 513 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 511 DCHECK(collection->native_sampler); | 514 DCHECK(collection->native_sampler); |
| 512 | 515 |
| 513 // If this is the first sample of a burst, a new Profile needs to be created | 516 // If this is the first sample of a burst, a new Profile needs to be created |
| 514 // and filled. | 517 // and filled. |
| 515 if (collection->sample == 0) { | 518 if (collection->sample == 0) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 } | 583 } |
| 581 } | 584 } |
| 582 | 585 |
| 583 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { | 586 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { |
| 584 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 587 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 585 | 588 |
| 586 auto found = active_collections_.find(id); | 589 auto found = active_collections_.find(id); |
| 587 if (found == active_collections_.end()) | 590 if (found == active_collections_.end()) |
| 588 return; | 591 return; |
| 589 | 592 |
| 590 FinishCollection(found->second.get()); | 593 auto* collection = found->second.get(); |
| 594 FinishCollection(collection); |
| 595 |
| 596 // Remove this collection from the map of known ones. The |collection| |
| 597 // parameter is invalid after this point. |
| 598 size_t count = active_collections_.erase(collection->collection_id); |
| 599 DCHECK_EQ(1U, count); |
| 600 |
| 591 ScheduleShutdownIfIdle(); | 601 ScheduleShutdownIfIdle(); |
| 592 } | 602 } |
| 593 | 603 |
| 594 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { | 604 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { |
| 595 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 605 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 596 | 606 |
| 597 auto found = active_collections_.find(id); | 607 auto found = active_collections_.find(id); |
| 598 | 608 |
| 599 // The task won't be found if it has been stopped. | 609 // The task won't be found if it has been stopped. |
| 600 if (found == active_collections_.end()) | 610 if (found == active_collections_.end()) |
| 601 return; | 611 return; |
| 602 | 612 |
| 603 CollectionContext* collection = found->second.get(); | 613 CollectionContext* collection = found->second.get(); |
| 604 | 614 |
| 605 // Handle first-run with no "next time". | 615 // Handle first-run with no "next time". |
| 606 if (collection->next_sample_time == Time()) | 616 if (collection->next_sample_time == Time()) |
| 607 collection->next_sample_time = Time::Now(); | 617 collection->next_sample_time = Time::Now(); |
| 608 | 618 |
| 609 // Do the collection of a single sample. | 619 // Do the collection of a single sample. |
| 610 RecordSample(collection); | 620 RecordSample(collection); |
| 611 | 621 |
| 612 // Update the time of the next sample recording. | 622 // Update the time of the next sample recording. |
| 613 if (UpdateNextSampleTime(collection)) { | 623 bool collection_finished = !UpdateNextSampleTime(collection); |
| 614 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 624 if (collection_finished) { |
| 615 FROM_HERE, | 625 // All capturing has completed so finish the collection. |
| 616 Bind(&SamplingThread::PerformCollectionTask, Unretained(this), id), | 626 collection_finished = !FinishCollection(collection); |
| 617 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); | 627 if (!collection_finished) { |
| 618 DCHECK(success); | 628 // Attempt to restart the collection with the new params. |
| 619 } else { | 629 collection->next_sample_time = |
| 620 // All capturing has completed so finish the collection. By not re-adding | 630 Time::Now() + collection->params.initial_delay; |
| 621 // it to the task queue, the collection will "expire" (i.e. no further work | 631 collection->burst = 0; |
| 622 // will be done). The |collection| variable will be invalid after this call. | 632 collection->sample = 0; |
| 623 FinishCollection(collection); | 633 } |
| 634 } |
| 635 |
| 636 if (collection_finished) { |
| 637 // Remove this collection from the map of known ones. The |collection| |
| 638 // parameter is invalid after this point. |
| 639 size_t count = active_collections_.erase(collection->collection_id); |
| 640 DCHECK_EQ(1U, count); |
| 641 |
| 642 // By not adding it to the task queue, the collection will "expire" (i.e. |
| 643 // no further work will be done). The |collection| variable will be invalid |
| 644 // after this call. |
| 624 ScheduleShutdownIfIdle(); | 645 ScheduleShutdownIfIdle(); |
| 646 return; |
| 625 } | 647 } |
| 648 |
| 649 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
| 650 FROM_HERE, |
| 651 Bind(&SamplingThread::PerformCollectionTask, Unretained(this), id), |
| 652 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); |
| 653 DCHECK(success); |
| 626 } | 654 } |
| 627 | 655 |
| 628 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { | 656 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { |
| 629 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 657 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 630 | 658 |
| 631 // Holding this lock ensures that any attempt to start another job will | 659 // Holding this lock ensures that any attempt to start another job will |
| 632 // get postponed until |thread_execution_state_| is updated, thus eliminating | 660 // get postponed until |thread_execution_state_| is updated, thus eliminating |
| 633 // the race in starting a new thread while the previous one is exiting. | 661 // the race in starting a new thread while the previous one is exiting. |
| 634 AutoLock lock(thread_execution_state_lock_); | 662 AutoLock lock(thread_execution_state_lock_); |
| 635 | 663 |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 } | 871 } |
| 844 | 872 |
| 845 bool operator<(const StackSamplingProfiler::Frame &a, | 873 bool operator<(const StackSamplingProfiler::Frame &a, |
| 846 const StackSamplingProfiler::Frame &b) { | 874 const StackSamplingProfiler::Frame &b) { |
| 847 return (a.module_index < b.module_index) || | 875 return (a.module_index < b.module_index) || |
| 848 (a.module_index == b.module_index && | 876 (a.module_index == b.module_index && |
| 849 a.instruction_pointer < b.instruction_pointer); | 877 a.instruction_pointer < b.instruction_pointer); |
| 850 } | 878 } |
| 851 | 879 |
| 852 } // namespace base | 880 } // namespace base |
| OLD | NEW |