Chromium Code Reviews| 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 13 matching lines...) Expand all Loading... | |
| 24 #include "base/threading/thread_restrictions.h" | 24 #include "base/threading/thread_restrictions.h" |
| 25 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
| 26 #include "base/timer/elapsed_timer.h" | 26 #include "base/timer/elapsed_timer.h" |
| 27 | 27 |
| 28 namespace base { | 28 namespace base { |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 // This value is used when there is no collection in progress and thus no ID | 32 // This value is used when there is no collection in progress and thus no ID |
| 33 // for referencing the active collection to the SamplingThread. | 33 // for referencing the active collection to the SamplingThread. |
| 34 const int NULL_COLLECTION_ID = -1; | 34 const int NULL_PROFILER_ID = -1; |
| 35 | 35 |
| 36 void ChangeAtomicFlags(subtle::Atomic32* flags, | 36 void ChangeAtomicFlags(subtle::Atomic32* flags, |
| 37 subtle::Atomic32 set, | 37 subtle::Atomic32 set, |
| 38 subtle::Atomic32 clear) { | 38 subtle::Atomic32 clear) { |
| 39 DCHECK(set != 0 || clear != 0); | 39 DCHECK(set != 0 || clear != 0); |
| 40 DCHECK_EQ(0, set & clear); | 40 DCHECK_EQ(0, set & clear); |
| 41 | 41 |
| 42 subtle::Atomic32 bits = subtle::NoBarrier_Load(flags); | 42 subtle::Atomic32 bits = subtle::NoBarrier_Load(flags); |
| 43 while (true) { | 43 while (true) { |
| 44 subtle::Atomic32 existing = | 44 subtle::Atomic32 existing = |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 static void ShutdownAssumingIdle(bool simulate_intervening_add); | 132 static void ShutdownAssumingIdle(bool simulate_intervening_add); |
| 133 | 133 |
| 134 private: | 134 private: |
| 135 // Calls the sampling threads ShutdownTask and then signals an event. | 135 // Calls the sampling threads ShutdownTask and then signals an event. |
| 136 static void ShutdownTaskAndSignalEvent(SamplingThread* sampler, | 136 static void ShutdownTaskAndSignalEvent(SamplingThread* sampler, |
| 137 int add_events, | 137 int add_events, |
| 138 WaitableEvent* event); | 138 WaitableEvent* event); |
| 139 }; | 139 }; |
| 140 | 140 |
| 141 struct CollectionContext { | 141 struct CollectionContext { |
| 142 CollectionContext(PlatformThreadId target, | 142 CollectionContext(int profiler_id, |
| 143 PlatformThreadId target, | |
| 143 const SamplingParams& params, | 144 const SamplingParams& params, |
| 144 const CompletedCallback& callback, | 145 const CompletedCallback& callback, |
| 145 WaitableEvent* finished, | 146 WaitableEvent* finished, |
| 146 std::unique_ptr<NativeStackSampler> sampler) | 147 std::unique_ptr<NativeStackSampler> sampler) |
| 147 : collection_id(next_collection_id_.GetNext()), | 148 : profiler_id(profiler_id), |
| 148 target(target), | 149 target(target), |
| 149 params(params), | 150 params(params), |
| 150 callback(callback), | 151 callback(callback), |
| 151 finished(finished), | 152 finished(finished), |
| 152 native_sampler(std::move(sampler)) {} | 153 native_sampler(std::move(sampler)) {} |
| 153 ~CollectionContext() {} | 154 ~CollectionContext() {} |
| 154 | 155 |
| 155 // An identifier for this collection, used to uniquely identify it to | 156 // An identifier for the profiler associated with this collection, used to |
| 156 // outside interests. | 157 // uniquely identify the collection to outside interests. |
| 157 const int collection_id; | 158 const int profiler_id; |
| 158 | 159 |
| 159 const PlatformThreadId target; // ID of The thread being sampled. | 160 const PlatformThreadId target; // ID of The thread being sampled. |
| 160 const SamplingParams params; // Information about how to sample. | 161 const SamplingParams params; // Information about how to sample. |
| 161 const CompletedCallback callback; // Callback made when sampling complete. | 162 const CompletedCallback callback; // Callback made when sampling complete. |
| 162 WaitableEvent* const finished; // Signaled when all sampling complete. | 163 WaitableEvent* const finished; // Signaled when all sampling complete. |
| 163 | 164 |
| 164 // Platform-specific module that does the actual sampling. | 165 // Platform-specific module that does the actual sampling. |
| 165 std::unique_ptr<NativeStackSampler> native_sampler; | 166 std::unique_ptr<NativeStackSampler> native_sampler; |
| 166 | 167 |
| 167 // The absolute time for the next sample. | 168 // The absolute time for the next sample. |
| 168 Time next_sample_time; | 169 Time next_sample_time; |
| 169 | 170 |
| 170 // The time that a profile was started, for calculating the total duration. | 171 // The time that a profile was started, for calculating the total duration. |
| 171 Time profile_start_time; | 172 Time profile_start_time; |
| 172 | 173 |
| 173 // Counters that indicate the current position along the acquisition. | 174 // Counters that indicate the current position along the acquisition. |
| 174 int burst = 0; | 175 int burst = 0; |
| 175 int sample = 0; | 176 int sample = 0; |
| 176 | 177 |
| 177 // The collected stack samples. The active profile is always at the back(). | 178 // The collected stack samples. The active profile is always at the back(). |
| 178 CallStackProfiles profiles; | 179 CallStackProfiles profiles; |
| 179 | 180 |
| 180 private: | 181 // Sequence number for generating new profiler ids. |
| 181 static StaticAtomicSequenceNumber next_collection_id_; | 182 static StaticAtomicSequenceNumber next_profiler_id; |
| 182 }; | 183 }; |
| 183 | 184 |
| 184 // Gets the single instance of this class. | 185 // Gets the single instance of this class. |
| 185 static SamplingThread* GetInstance(); | 186 static SamplingThread* GetInstance(); |
| 186 | 187 |
| 187 // Adds a new CollectionContext to the thread. This can be called externally | 188 // Adds a new CollectionContext to the thread. This can be called externally |
| 188 // from any thread. This returns an ID that can later be used to stop | 189 // from any thread. This returns an ID that can later be used to stop |
| 189 // the sampling. | 190 // the sampling. |
| 190 int Add(std::unique_ptr<CollectionContext> collection); | 191 int Add(std::unique_ptr<CollectionContext> collection); |
| 191 | 192 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 221 ~SamplingThread() override; | 222 ~SamplingThread() override; |
| 222 | 223 |
| 223 // Get task runner that is usable from the outside. | 224 // Get task runner that is usable from the outside. |
| 224 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd(); | 225 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd(); |
| 225 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner( | 226 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner( |
| 226 ThreadExecutionState* out_state); | 227 ThreadExecutionState* out_state); |
| 227 | 228 |
| 228 // Get task runner that is usable from the sampling thread itself. | 229 // Get task runner that is usable from the sampling thread itself. |
| 229 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); | 230 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); |
| 230 | 231 |
| 231 // Finishes a collection and reports collected data via callback. | 232 // Finishes a collection and reports collected data via callback. Returns |
| 232 void FinishCollection(CollectionContext* collection); | 233 // the new collection params, if a new collection should be started. |
| 234 Optional<SamplingParams> FinishCollection(CollectionContext* collection); | |
| 233 | 235 |
| 234 // Records a single sample of a collection. | 236 // Records a single sample of a collection. |
| 235 void RecordSample(CollectionContext* collection); | 237 void RecordSample(CollectionContext* collection); |
| 236 | 238 |
| 237 // Check if the sampling thread is idle and begin a shutdown if it is. | 239 // Check if the sampling thread is idle and begin a shutdown if it is. |
| 238 void ScheduleShutdownIfIdle(); | 240 void ScheduleShutdownIfIdle(); |
| 239 | 241 |
| 240 // These methods are tasks that get posted to the internal message queue. | 242 // These methods are tasks that get posted to the internal message queue. |
| 241 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); | 243 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); |
| 242 void RemoveCollectionTask(int id); | 244 void RemoveCollectionTask(int id); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 | 356 |
| 355 // static | 357 // static |
| 356 void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent( | 358 void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent( |
| 357 SamplingThread* sampler, | 359 SamplingThread* sampler, |
| 358 int add_events, | 360 int add_events, |
| 359 WaitableEvent* event) { | 361 WaitableEvent* event) { |
| 360 sampler->ShutdownTask(add_events); | 362 sampler->ShutdownTask(add_events); |
| 361 event->Signal(); | 363 event->Signal(); |
| 362 } | 364 } |
| 363 | 365 |
| 364 StaticAtomicSequenceNumber StackSamplingProfiler::SamplingThread:: | 366 StaticAtomicSequenceNumber |
| 365 CollectionContext::next_collection_id_; | 367 StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id; |
| 366 | 368 |
| 367 StackSamplingProfiler::SamplingThread::SamplingThread() | 369 StackSamplingProfiler::SamplingThread::SamplingThread() |
| 368 : Thread("StackSamplingProfiler") {} | 370 : Thread("StackSamplingProfiler") {} |
| 369 | 371 |
| 370 StackSamplingProfiler::SamplingThread::~SamplingThread() = default; | 372 StackSamplingProfiler::SamplingThread::~SamplingThread() = default; |
| 371 | 373 |
| 372 StackSamplingProfiler::SamplingThread* | 374 StackSamplingProfiler::SamplingThread* |
| 373 StackSamplingProfiler::SamplingThread::GetInstance() { | 375 StackSamplingProfiler::SamplingThread::GetInstance() { |
| 374 return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get(); | 376 return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get(); |
| 375 } | 377 } |
| 376 | 378 |
| 377 int StackSamplingProfiler::SamplingThread::Add( | 379 int StackSamplingProfiler::SamplingThread::Add( |
| 378 std::unique_ptr<CollectionContext> collection) { | 380 std::unique_ptr<CollectionContext> collection) { |
| 379 // This is not to be run on the sampling thread. | 381 // This is not to be run on the sampling thread. |
| 380 | 382 |
| 381 int id = collection->collection_id; | 383 int id = collection->profiler_id; |
| 382 scoped_refptr<SingleThreadTaskRunner> task_runner = | 384 scoped_refptr<SingleThreadTaskRunner> task_runner = |
| 383 GetOrCreateTaskRunnerForAdd(); | 385 GetOrCreateTaskRunnerForAdd(); |
| 384 | 386 |
| 385 task_runner->PostTask( | 387 task_runner->PostTask( |
| 386 FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this), | 388 FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this), |
| 387 Passed(&collection))); | 389 Passed(&collection))); |
| 388 | 390 |
| 389 return id; | 391 return id; |
| 390 } | 392 } |
| 391 | 393 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 468 | 470 |
| 469 scoped_refptr<SingleThreadTaskRunner> | 471 scoped_refptr<SingleThreadTaskRunner> |
| 470 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { | 472 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { |
| 471 // This should be called only from the sampling thread as it has limited | 473 // This should be called only from the sampling thread as it has limited |
| 472 // accessibility. | 474 // accessibility. |
| 473 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 475 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 474 | 476 |
| 475 return Thread::task_runner(); | 477 return Thread::task_runner(); |
| 476 } | 478 } |
| 477 | 479 |
| 478 void StackSamplingProfiler::SamplingThread::FinishCollection( | 480 Optional<StackSamplingProfiler::SamplingParams> |
| 481 StackSamplingProfiler::SamplingThread::FinishCollection( | |
| 479 CollectionContext* collection) { | 482 CollectionContext* collection) { |
| 480 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 483 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 481 | 484 |
| 482 // 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), |
| 483 // calculate it now. | 486 // calculate it now. |
| 484 if (!collection->profiles.empty() && | 487 if (!collection->profiles.empty() && |
| 485 collection->profiles.back().profile_duration == TimeDelta()) { | 488 collection->profiles.back().profile_duration == TimeDelta()) { |
| 486 collection->profiles.back().profile_duration = | 489 collection->profiles.back().profile_duration = |
| 487 Time::Now() - collection->profile_start_time; | 490 Time::Now() - collection->profile_start_time; |
| 488 } | 491 } |
| 489 | 492 |
| 490 // Extract some information so callback and event-signalling can still be | 493 // Extract some information so callback and event-signalling can still be |
| 491 // 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. |
| 492 // 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 |
| 493 // that collection is fully finished when those things occur. | 496 // that collection is fully finished when those things occur. |
| 494 const CompletedCallback callback = collection->callback; | 497 const CompletedCallback callback = collection->callback; |
| 495 CallStackProfiles profiles = std::move(collection->profiles); | 498 CallStackProfiles profiles = std::move(collection->profiles); |
| 496 WaitableEvent* finished = collection->finished; | 499 WaitableEvent* finished = collection->finished; |
| 497 | 500 |
| 498 // Remove this collection from the map of known ones. The |collection| | |
| 499 // parameter is invalid after this point. | |
| 500 size_t count = active_collections_.erase(collection->collection_id); | |
|
Mike Wittman
2017/07/07 21:01:11
The test code depends on the finished event below
Alexei Svitkine (slow)
2017/07/10 22:05:37
Ah, this wasn't obvious. Change to still do it her
Mike Wittman
2017/07/10 22:31:25
The callback is also used as a synchronization poi
Alexei Svitkine (slow)
2017/07/11 18:27:05
I see. So this required reorganizing things a bit
| |
| 501 DCHECK_EQ(1U, count); | |
| 502 | |
| 503 // Run the associated callback, passing the collected profiles. | 501 // Run the associated callback, passing the collected profiles. |
| 504 callback.Run(std::move(profiles)); | 502 Optional<SamplingParams> new_params = callback.Run(std::move(profiles)); |
| 505 | 503 |
| 506 // Signal that this collection is finished. | 504 // Signal that this collection is finished. |
| 507 finished->Signal(); | 505 finished->Signal(); |
| 506 | |
| 507 return new_params; | |
| 508 } | 508 } |
| 509 | 509 |
| 510 void StackSamplingProfiler::SamplingThread::RecordSample( | 510 void StackSamplingProfiler::SamplingThread::RecordSample( |
| 511 CollectionContext* collection) { | 511 CollectionContext* collection) { |
| 512 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 512 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 513 DCHECK(collection->native_sampler); | 513 DCHECK(collection->native_sampler); |
| 514 | 514 |
| 515 // If this is the first sample of a burst, a new Profile needs to be created | 515 // If this is the first sample of a burst, a new Profile needs to be created |
| 516 // and filled. | 516 // and filled. |
| 517 if (collection->sample == 0) { | 517 if (collection->sample == 0) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 554 GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
| 555 FROM_HERE, | 555 FROM_HERE, |
| 556 BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events), | 556 BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events), |
| 557 TimeDelta::FromSeconds(60)); | 557 TimeDelta::FromSeconds(60)); |
| 558 } | 558 } |
| 559 | 559 |
| 560 void StackSamplingProfiler::SamplingThread::AddCollectionTask( | 560 void StackSamplingProfiler::SamplingThread::AddCollectionTask( |
| 561 std::unique_ptr<CollectionContext> collection) { | 561 std::unique_ptr<CollectionContext> collection) { |
| 562 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 562 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 563 | 563 |
| 564 const int collection_id = collection->collection_id; | 564 const int profiler_id = collection->profiler_id; |
| 565 const TimeDelta initial_delay = collection->params.initial_delay; | 565 const TimeDelta initial_delay = collection->params.initial_delay; |
| 566 | 566 |
| 567 active_collections_.insert( | 567 active_collections_.insert( |
| 568 std::make_pair(collection_id, std::move(collection))); | 568 std::make_pair(profiler_id, std::move(collection))); |
| 569 | 569 |
| 570 GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 570 GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
| 571 FROM_HERE, | 571 FROM_HERE, |
| 572 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), | 572 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), |
| 573 collection_id), | 573 profiler_id), |
| 574 initial_delay); | 574 initial_delay); |
| 575 | 575 |
| 576 // Another increment of "add events" serves to invalidate any pending | 576 // Another increment of "add events" serves to invalidate any pending |
| 577 // shutdown tasks that may have been initiated between the Add() and this | 577 // shutdown tasks that may have been initiated between the Add() and this |
| 578 // task running. | 578 // task running. |
| 579 { | 579 { |
| 580 AutoLock lock(thread_execution_state_lock_); | 580 AutoLock lock(thread_execution_state_lock_); |
| 581 ++thread_execution_state_add_events_; | 581 ++thread_execution_state_add_events_; |
| 582 } | 582 } |
| 583 } | 583 } |
| 584 | 584 |
| 585 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { | 585 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { |
| 586 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 586 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 587 | 587 |
| 588 auto found = active_collections_.find(id); | 588 auto found = active_collections_.find(id); |
| 589 if (found == active_collections_.end()) | 589 if (found == active_collections_.end()) |
| 590 return; | 590 return; |
| 591 | 591 |
| 592 FinishCollection(found->second.get()); | 592 auto* collection = found->second.get(); |
| 593 FinishCollection(collection); | |
| 594 | |
| 595 // Remove this collection from the map of known ones. After this, | |
| 596 // |collection| will be invalid. | |
| 597 size_t count = active_collections_.erase(collection->profiler_id); | |
| 598 DCHECK_EQ(1U, count); | |
| 599 | |
| 593 ScheduleShutdownIfIdle(); | 600 ScheduleShutdownIfIdle(); |
| 594 } | 601 } |
| 595 | 602 |
| 596 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { | 603 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { |
| 597 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 604 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 598 | 605 |
| 599 auto found = active_collections_.find(id); | 606 auto found = active_collections_.find(id); |
| 600 | 607 |
| 601 // The task won't be found if it has been stopped. | 608 // The task won't be found if it has been stopped. |
| 602 if (found == active_collections_.end()) | 609 if (found == active_collections_.end()) |
| 603 return; | 610 return; |
| 604 | 611 |
| 605 CollectionContext* collection = found->second.get(); | 612 CollectionContext* collection = found->second.get(); |
| 606 | 613 |
| 607 // Handle first-run with no "next time". | 614 // Handle first-run with no "next time". |
| 608 if (collection->next_sample_time == Time()) | 615 if (collection->next_sample_time == Time()) |
| 609 collection->next_sample_time = Time::Now(); | 616 collection->next_sample_time = Time::Now(); |
| 610 | 617 |
| 611 // Do the collection of a single sample. | 618 // Do the collection of a single sample. |
| 612 RecordSample(collection); | 619 RecordSample(collection); |
| 613 | 620 |
| 614 // Update the time of the next sample recording. | 621 // Update the time of the next sample recording. |
| 615 if (UpdateNextSampleTime(collection)) { | 622 const bool collection_finished = !UpdateNextSampleTime(collection); |
| 616 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 623 if (collection_finished) { |
| 617 FROM_HERE, | 624 // All capturing has completed so finish the collection. If no new params |
| 618 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), | 625 // are returned, a new collection should not be started. |
| 619 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); | 626 Optional<SamplingParams> new_params = FinishCollection(collection); |
| 620 DCHECK(success); | 627 if (!new_params.has_value()) { |
| 621 } else { | 628 // Remove this collection from the map of known ones. After this, |
| 622 // All capturing has completed so finish the collection. By not re-adding | 629 // |collection| will be invalid. |
| 623 // it to the task queue, the collection will "expire" (i.e. no further work | 630 size_t count = active_collections_.erase(collection->profiler_id); |
| 624 // will be done). The |collection| variable will be invalid after this call. | 631 DCHECK_EQ(1U, count); |
| 625 FinishCollection(collection); | 632 |
| 626 ScheduleShutdownIfIdle(); | 633 // By not adding it to the task queue, the collection will "expire" (i.e. |
| 634 // no further work will be done). | |
| 635 ScheduleShutdownIfIdle(); | |
| 636 return; | |
| 637 } | |
| 638 | |
| 639 // Restart the collection with the new params. Keep the same collection | |
| 640 // id so the Stop() operation continues to work. | |
| 641 auto new_collection = MakeUnique<SamplingThread::CollectionContext>( | |
| 642 collection->profiler_id, collection->target, new_params.value(), | |
| 643 collection->callback, collection->finished, | |
| 644 std::move(collection->native_sampler)); | |
| 645 new_collection->next_sample_time = | |
| 646 Time::Now() + collection->params.initial_delay; | |
| 647 // Replace |collection| in the map by |new_collection|. After this, | |
| 648 // |collection| will be invalid. | |
| 649 found->second = std::move(new_collection); | |
| 627 } | 650 } |
| 651 | |
| 652 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( | |
| 653 FROM_HERE, | |
| 654 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), | |
| 655 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); | |
| 656 DCHECK(success); | |
| 628 } | 657 } |
| 629 | 658 |
| 630 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { | 659 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { |
| 631 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 660 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 632 | 661 |
| 633 // Holding this lock ensures that any attempt to start another job will | 662 // Holding this lock ensures that any attempt to start another job will |
| 634 // get postponed until |thread_execution_state_| is updated, thus eliminating | 663 // get postponed until |thread_execution_state_| is updated, thus eliminating |
| 635 // the race in starting a new thread while the previous one is exiting. | 664 // the race in starting a new thread while the previous one is exiting. |
| 636 AutoLock lock(thread_execution_state_lock_); | 665 AutoLock lock(thread_execution_state_lock_); |
| 637 | 666 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 737 const SamplingParams& params, | 766 const SamplingParams& params, |
| 738 const CompletedCallback& callback, | 767 const CompletedCallback& callback, |
| 739 NativeStackSamplerTestDelegate* test_delegate) | 768 NativeStackSamplerTestDelegate* test_delegate) |
| 740 : thread_id_(thread_id), | 769 : thread_id_(thread_id), |
| 741 params_(params), | 770 params_(params), |
| 742 completed_callback_(callback), | 771 completed_callback_(callback), |
| 743 // The event starts "signaled" so code knows it's safe to start thread | 772 // The event starts "signaled" so code knows it's safe to start thread |
| 744 // and "manual" so that it can be waited in multiple places. | 773 // and "manual" so that it can be waited in multiple places. |
| 745 profiling_inactive_(WaitableEvent::ResetPolicy::MANUAL, | 774 profiling_inactive_(WaitableEvent::ResetPolicy::MANUAL, |
| 746 WaitableEvent::InitialState::SIGNALED), | 775 WaitableEvent::InitialState::SIGNALED), |
| 747 collection_id_(NULL_COLLECTION_ID), | 776 profiler_id_(NULL_PROFILER_ID), |
| 748 test_delegate_(test_delegate) {} | 777 test_delegate_(test_delegate) {} |
| 749 | 778 |
| 750 StackSamplingProfiler::~StackSamplingProfiler() { | 779 StackSamplingProfiler::~StackSamplingProfiler() { |
| 751 // Stop returns immediately but the shutdown runs asynchronously. There is a | 780 // Stop returns immediately but the shutdown runs asynchronously. There is a |
| 752 // non-zero probability that one more sample will be taken after this call | 781 // non-zero probability that one more sample will be taken after this call |
| 753 // returns. | 782 // returns. |
| 754 Stop(); | 783 Stop(); |
| 755 | 784 |
| 756 // The behavior of sampling a thread that has exited is undefined and could | 785 // The behavior of sampling a thread that has exited is undefined and could |
| 757 // cause Bad Things(tm) to occur. The safety model provided by this class is | 786 // cause Bad Things(tm) to occur. The safety model provided by this class is |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 774 NativeStackSampler::Create(thread_id_, &RecordAnnotations, | 803 NativeStackSampler::Create(thread_id_, &RecordAnnotations, |
| 775 test_delegate_); | 804 test_delegate_); |
| 776 | 805 |
| 777 if (!native_sampler) | 806 if (!native_sampler) |
| 778 return; | 807 return; |
| 779 | 808 |
| 780 // Wait for profiling to be "inactive", then reset it for the upcoming run. | 809 // Wait for profiling to be "inactive", then reset it for the upcoming run. |
| 781 profiling_inactive_.Wait(); | 810 profiling_inactive_.Wait(); |
| 782 profiling_inactive_.Reset(); | 811 profiling_inactive_.Reset(); |
| 783 | 812 |
| 784 DCHECK_EQ(NULL_COLLECTION_ID, collection_id_); | 813 DCHECK_EQ(NULL_PROFILER_ID, profiler_id_); |
| 785 collection_id_ = SamplingThread::GetInstance()->Add( | 814 profiler_id_ = SamplingThread::GetInstance()->Add( |
| 786 MakeUnique<SamplingThread::CollectionContext>( | 815 MakeUnique<SamplingThread::CollectionContext>( |
| 816 SamplingThread::CollectionContext::next_profiler_id.GetNext(), | |
| 787 thread_id_, params_, completed_callback_, &profiling_inactive_, | 817 thread_id_, params_, completed_callback_, &profiling_inactive_, |
| 788 std::move(native_sampler))); | 818 std::move(native_sampler))); |
| 789 DCHECK_NE(NULL_COLLECTION_ID, collection_id_); | 819 DCHECK_NE(NULL_PROFILER_ID, profiler_id_); |
| 790 } | 820 } |
| 791 | 821 |
| 792 void StackSamplingProfiler::Stop() { | 822 void StackSamplingProfiler::Stop() { |
| 793 SamplingThread::GetInstance()->Remove(collection_id_); | 823 SamplingThread::GetInstance()->Remove(profiler_id_); |
| 794 collection_id_ = NULL_COLLECTION_ID; | 824 profiler_id_ = NULL_PROFILER_ID; |
| 795 } | 825 } |
| 796 | 826 |
| 797 // static | 827 // static |
| 798 void StackSamplingProfiler::SetProcessMilestone(int milestone) { | 828 void StackSamplingProfiler::SetProcessMilestone(int milestone) { |
| 799 DCHECK_LE(0, milestone); | 829 DCHECK_LE(0, milestone); |
| 800 DCHECK_GT(static_cast<int>(sizeof(process_milestones_) * 8), milestone); | 830 DCHECK_GT(static_cast<int>(sizeof(process_milestones_) * 8), milestone); |
| 801 DCHECK_EQ(0, subtle::NoBarrier_Load(&process_milestones_) & (1 << milestone)); | 831 DCHECK_EQ(0, subtle::NoBarrier_Load(&process_milestones_) & (1 << milestone)); |
| 802 ChangeAtomicFlags(&process_milestones_, 1 << milestone, 0); | 832 ChangeAtomicFlags(&process_milestones_, 1 << milestone, 0); |
| 803 } | 833 } |
| 804 | 834 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 845 } | 875 } |
| 846 | 876 |
| 847 bool operator<(const StackSamplingProfiler::Frame &a, | 877 bool operator<(const StackSamplingProfiler::Frame &a, |
| 848 const StackSamplingProfiler::Frame &b) { | 878 const StackSamplingProfiler::Frame &b) { |
| 849 return (a.module_index < b.module_index) || | 879 return (a.module_index < b.module_index) || |
| 850 (a.module_index == b.module_index && | 880 (a.module_index == b.module_index && |
| 851 a.instruction_pointer < b.instruction_pointer); | 881 a.instruction_pointer < b.instruction_pointer); |
| 852 } | 882 } |
| 853 | 883 |
| 854 } // namespace base | 884 } // namespace base |
| OLD | NEW |