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. The |
| 234 // |collection| should already have been removed from |active_collections_| |
| 235 // by the caller, as this is needed to avoid flakyness in unit tests. |
| 236 Optional<SamplingParams> FinishCollection(CollectionContext* collection); |
233 | 237 |
234 // Records a single sample of a collection. | 238 // Records a single sample of a collection. |
235 void RecordSample(CollectionContext* collection); | 239 void RecordSample(CollectionContext* collection); |
236 | 240 |
237 // Check if the sampling thread is idle and begin a shutdown if it is. | 241 // Check if the sampling thread is idle and begin a shutdown if it is. |
238 void ScheduleShutdownIfIdle(); | 242 void ScheduleShutdownIfIdle(); |
239 | 243 |
240 // These methods are tasks that get posted to the internal message queue. | 244 // These methods are tasks that get posted to the internal message queue. |
241 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); | 245 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); |
242 void RemoveCollectionTask(int id); | 246 void RemoveCollectionTask(int id); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 | 358 |
355 // static | 359 // static |
356 void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent( | 360 void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent( |
357 SamplingThread* sampler, | 361 SamplingThread* sampler, |
358 int add_events, | 362 int add_events, |
359 WaitableEvent* event) { | 363 WaitableEvent* event) { |
360 sampler->ShutdownTask(add_events); | 364 sampler->ShutdownTask(add_events); |
361 event->Signal(); | 365 event->Signal(); |
362 } | 366 } |
363 | 367 |
364 StaticAtomicSequenceNumber StackSamplingProfiler::SamplingThread:: | 368 StaticAtomicSequenceNumber |
365 CollectionContext::next_collection_id_; | 369 StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id; |
366 | 370 |
367 StackSamplingProfiler::SamplingThread::SamplingThread() | 371 StackSamplingProfiler::SamplingThread::SamplingThread() |
368 : Thread("StackSamplingProfiler") {} | 372 : Thread("StackSamplingProfiler") {} |
369 | 373 |
370 StackSamplingProfiler::SamplingThread::~SamplingThread() = default; | 374 StackSamplingProfiler::SamplingThread::~SamplingThread() = default; |
371 | 375 |
372 StackSamplingProfiler::SamplingThread* | 376 StackSamplingProfiler::SamplingThread* |
373 StackSamplingProfiler::SamplingThread::GetInstance() { | 377 StackSamplingProfiler::SamplingThread::GetInstance() { |
374 return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get(); | 378 return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get(); |
375 } | 379 } |
376 | 380 |
377 int StackSamplingProfiler::SamplingThread::Add( | 381 int StackSamplingProfiler::SamplingThread::Add( |
378 std::unique_ptr<CollectionContext> collection) { | 382 std::unique_ptr<CollectionContext> collection) { |
379 // This is not to be run on the sampling thread. | 383 // This is not to be run on the sampling thread. |
380 | 384 |
381 int id = collection->collection_id; | 385 int id = collection->profiler_id; |
382 scoped_refptr<SingleThreadTaskRunner> task_runner = | 386 scoped_refptr<SingleThreadTaskRunner> task_runner = |
383 GetOrCreateTaskRunnerForAdd(); | 387 GetOrCreateTaskRunnerForAdd(); |
384 | 388 |
385 task_runner->PostTask( | 389 task_runner->PostTask( |
386 FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this), | 390 FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this), |
387 Passed(&collection))); | 391 Passed(&collection))); |
388 | 392 |
389 return id; | 393 return id; |
390 } | 394 } |
391 | 395 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 | 472 |
469 scoped_refptr<SingleThreadTaskRunner> | 473 scoped_refptr<SingleThreadTaskRunner> |
470 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { | 474 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { |
471 // This should be called only from the sampling thread as it has limited | 475 // This should be called only from the sampling thread as it has limited |
472 // accessibility. | 476 // accessibility. |
473 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 477 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
474 | 478 |
475 return Thread::task_runner(); | 479 return Thread::task_runner(); |
476 } | 480 } |
477 | 481 |
478 void StackSamplingProfiler::SamplingThread::FinishCollection( | 482 Optional<StackSamplingProfiler::SamplingParams> |
| 483 StackSamplingProfiler::SamplingThread::FinishCollection( |
479 CollectionContext* collection) { | 484 CollectionContext* collection) { |
480 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 485 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
| 486 DCHECK_EQ(0u, active_collections_.count(collection->profiler_id)); |
481 | 487 |
482 // If there is no duration for the final profile (because it was stopped), | 488 // If there is no duration for the final profile (because it was stopped), |
483 // calculate it now. | 489 // calculate it now. |
484 if (!collection->profiles.empty() && | 490 if (!collection->profiles.empty() && |
485 collection->profiles.back().profile_duration == TimeDelta()) { | 491 collection->profiles.back().profile_duration == TimeDelta()) { |
486 collection->profiles.back().profile_duration = | 492 collection->profiles.back().profile_duration = |
487 Time::Now() - collection->profile_start_time; | 493 Time::Now() - collection->profile_start_time + |
| 494 collection->params.sampling_interval; |
488 } | 495 } |
489 | 496 |
490 // Extract some information so callback and event-signalling can still be | 497 // 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. | 498 // 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 | 499 // This allows the the controlling object (and tests using it) to be confident |
493 // that collection is fully finished when those things occur. | 500 // that collection is fully finished when those things occur. |
494 const CompletedCallback callback = collection->callback; | 501 const CompletedCallback callback = collection->callback; |
495 CallStackProfiles profiles = std::move(collection->profiles); | 502 CallStackProfiles profiles = std::move(collection->profiles); |
496 WaitableEvent* finished = collection->finished; | 503 WaitableEvent* finished = collection->finished; |
497 | 504 |
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); | |
501 DCHECK_EQ(1U, count); | |
502 | |
503 // Run the associated callback, passing the collected profiles. | 505 // Run the associated callback, passing the collected profiles. |
504 callback.Run(std::move(profiles)); | 506 Optional<SamplingParams> new_params = callback.Run(std::move(profiles)); |
505 | 507 |
506 // Signal that this collection is finished. | 508 // Signal that this collection is finished. |
507 finished->Signal(); | 509 finished->Signal(); |
| 510 |
| 511 return new_params; |
508 } | 512 } |
509 | 513 |
510 void StackSamplingProfiler::SamplingThread::RecordSample( | 514 void StackSamplingProfiler::SamplingThread::RecordSample( |
511 CollectionContext* collection) { | 515 CollectionContext* collection) { |
512 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 516 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
513 DCHECK(collection->native_sampler); | 517 DCHECK(collection->native_sampler); |
514 | 518 |
515 // If this is the first sample of a burst, a new Profile needs to be created | 519 // If this is the first sample of a burst, a new Profile needs to be created |
516 // and filled. | 520 // and filled. |
517 if (collection->sample == 0) { | 521 if (collection->sample == 0) { |
518 collection->profiles.push_back(CallStackProfile()); | 522 collection->profiles.push_back(CallStackProfile()); |
519 CallStackProfile& profile = collection->profiles.back(); | 523 CallStackProfile& profile = collection->profiles.back(); |
520 profile.sampling_period = collection->params.sampling_interval; | 524 profile.sampling_period = collection->params.sampling_interval; |
521 collection->profile_start_time = Time::Now(); | 525 collection->profile_start_time = Time::Now(); |
522 collection->native_sampler->ProfileRecordingStarting(&profile.modules); | 526 collection->native_sampler->ProfileRecordingStarting(&profile.modules); |
523 } | 527 } |
524 | 528 |
525 // The currently active profile being captured. | 529 // The currently active profile being captured. |
526 CallStackProfile& profile = collection->profiles.back(); | 530 CallStackProfile& profile = collection->profiles.back(); |
527 | 531 |
528 // Record a single sample. | 532 // Record a single sample. |
529 profile.samples.push_back(Sample()); | 533 profile.samples.push_back(Sample()); |
530 collection->native_sampler->RecordStackSample(stack_buffer_.get(), | 534 collection->native_sampler->RecordStackSample(stack_buffer_.get(), |
531 &profile.samples.back()); | 535 &profile.samples.back()); |
532 | 536 |
533 // If this is the last sample of a burst, record the total time. | 537 // If this is the last sample of a burst, record the total time. |
534 if (collection->sample == collection->params.samples_per_burst - 1) { | 538 if (collection->sample == collection->params.samples_per_burst - 1) { |
535 profile.profile_duration = Time::Now() - collection->profile_start_time; | 539 profile.profile_duration = Time::Now() - collection->profile_start_time + |
| 540 collection->params.sampling_interval; |
536 collection->native_sampler->ProfileRecordingStopped(stack_buffer_.get()); | 541 collection->native_sampler->ProfileRecordingStopped(stack_buffer_.get()); |
537 } | 542 } |
538 } | 543 } |
539 | 544 |
540 void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() { | 545 void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() { |
541 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 546 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
542 | 547 |
543 if (!active_collections_.empty()) | 548 if (!active_collections_.empty()) |
544 return; | 549 return; |
545 | 550 |
546 int add_events; | 551 int add_events; |
547 { | 552 { |
548 AutoLock lock(thread_execution_state_lock_); | 553 AutoLock lock(thread_execution_state_lock_); |
549 if (thread_execution_state_disable_idle_shutdown_for_testing_) | 554 if (thread_execution_state_disable_idle_shutdown_for_testing_) |
550 return; | 555 return; |
551 add_events = thread_execution_state_add_events_; | 556 add_events = thread_execution_state_add_events_; |
552 } | 557 } |
553 | 558 |
554 GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 559 GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
555 FROM_HERE, | 560 FROM_HERE, |
556 BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events), | 561 BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events), |
557 TimeDelta::FromSeconds(60)); | 562 TimeDelta::FromSeconds(60)); |
558 } | 563 } |
559 | 564 |
560 void StackSamplingProfiler::SamplingThread::AddCollectionTask( | 565 void StackSamplingProfiler::SamplingThread::AddCollectionTask( |
561 std::unique_ptr<CollectionContext> collection) { | 566 std::unique_ptr<CollectionContext> collection) { |
562 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 567 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
563 | 568 |
564 const int collection_id = collection->collection_id; | 569 const int profiler_id = collection->profiler_id; |
565 const TimeDelta initial_delay = collection->params.initial_delay; | 570 const TimeDelta initial_delay = collection->params.initial_delay; |
566 | 571 |
567 active_collections_.insert( | 572 active_collections_.insert( |
568 std::make_pair(collection_id, std::move(collection))); | 573 std::make_pair(profiler_id, std::move(collection))); |
569 | 574 |
570 GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 575 GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
571 FROM_HERE, | 576 FROM_HERE, |
572 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), | 577 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), |
573 collection_id), | 578 profiler_id), |
574 initial_delay); | 579 initial_delay); |
575 | 580 |
576 // Another increment of "add events" serves to invalidate any pending | 581 // Another increment of "add events" serves to invalidate any pending |
577 // shutdown tasks that may have been initiated between the Add() and this | 582 // shutdown tasks that may have been initiated between the Add() and this |
578 // task running. | 583 // task running. |
579 { | 584 { |
580 AutoLock lock(thread_execution_state_lock_); | 585 AutoLock lock(thread_execution_state_lock_); |
581 ++thread_execution_state_add_events_; | 586 ++thread_execution_state_add_events_; |
582 } | 587 } |
583 } | 588 } |
584 | 589 |
585 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { | 590 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { |
586 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 591 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
587 | 592 |
588 auto found = active_collections_.find(id); | 593 auto found = active_collections_.find(id); |
589 if (found == active_collections_.end()) | 594 if (found == active_collections_.end()) |
590 return; | 595 return; |
591 | 596 |
592 FinishCollection(found->second.get()); | 597 // Remove |collection| from |active_collections_|. |
| 598 std::unique_ptr<CollectionContext> collection = std::move(found->second); |
| 599 size_t count = active_collections_.erase(id); |
| 600 DCHECK_EQ(1U, count); |
| 601 |
| 602 FinishCollection(collection.get()); |
593 ScheduleShutdownIfIdle(); | 603 ScheduleShutdownIfIdle(); |
594 } | 604 } |
595 | 605 |
596 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { | 606 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { |
597 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 607 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
598 | 608 |
599 auto found = active_collections_.find(id); | 609 auto found = active_collections_.find(id); |
600 | 610 |
601 // The task won't be found if it has been stopped. | 611 // The task won't be found if it has been stopped. |
602 if (found == active_collections_.end()) | 612 if (found == active_collections_.end()) |
603 return; | 613 return; |
604 | 614 |
605 CollectionContext* collection = found->second.get(); | 615 CollectionContext* collection = found->second.get(); |
606 | 616 |
607 // Handle first-run with no "next time". | 617 // Handle first-run with no "next time". |
608 if (collection->next_sample_time == Time()) | 618 if (collection->next_sample_time == Time()) |
609 collection->next_sample_time = Time::Now(); | 619 collection->next_sample_time = Time::Now(); |
610 | 620 |
611 // Do the collection of a single sample. | 621 // Do the collection of a single sample. |
612 RecordSample(collection); | 622 RecordSample(collection); |
613 | 623 |
614 // Update the time of the next sample recording. | 624 // Update the time of the next sample recording. |
615 if (UpdateNextSampleTime(collection)) { | 625 const bool collection_finished = !UpdateNextSampleTime(collection); |
| 626 if (!collection_finished) { |
616 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( | 627 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( |
617 FROM_HERE, | 628 FROM_HERE, |
618 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), | 629 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), |
619 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); | 630 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); |
620 DCHECK(success); | 631 DCHECK(success); |
621 } else { | 632 return; |
622 // All capturing has completed so finish the collection. By not re-adding | 633 } |
623 // it to the task queue, the collection will "expire" (i.e. no further work | 634 |
624 // will be done). The |collection| variable will be invalid after this call. | 635 // Take ownership of |collection| and remove it from the map. If collection is |
625 FinishCollection(collection); | 636 // to be restarted, a new collection task will be added below. |
| 637 std::unique_ptr<CollectionContext> owned_collection = |
| 638 std::move(found->second); |
| 639 size_t count = active_collections_.erase(id); |
| 640 DCHECK_EQ(1U, count); |
| 641 |
| 642 // All capturing has completed so finish the collection. If no new params |
| 643 // are returned, a new collection should not be started. |
| 644 Optional<SamplingParams> new_params = FinishCollection(collection); |
| 645 if (!new_params.has_value()) { |
| 646 // By not adding it to the task queue, the collection will "expire" (i.e. |
| 647 // no further work will be done). |
626 ScheduleShutdownIfIdle(); | 648 ScheduleShutdownIfIdle(); |
| 649 return; |
627 } | 650 } |
| 651 |
| 652 // Restart the collection with the new params. Keep the same id so the |
| 653 // Stop() operation continues to work. |
| 654 auto new_collection = MakeUnique<SamplingThread::CollectionContext>( |
| 655 id, collection->target, new_params.value(), collection->callback, |
| 656 collection->finished, std::move(collection->native_sampler)); |
| 657 AddCollectionTask(std::move(new_collection)); |
628 } | 658 } |
629 | 659 |
630 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { | 660 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { |
631 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); | 661 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); |
632 | 662 |
633 // Holding this lock ensures that any attempt to start another job will | 663 // Holding this lock ensures that any attempt to start another job will |
634 // get postponed until |thread_execution_state_| is updated, thus eliminating | 664 // get postponed until |thread_execution_state_| is updated, thus eliminating |
635 // the race in starting a new thread while the previous one is exiting. | 665 // the race in starting a new thread while the previous one is exiting. |
636 AutoLock lock(thread_execution_state_lock_); | 666 AutoLock lock(thread_execution_state_lock_); |
637 | 667 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 const SamplingParams& params, | 767 const SamplingParams& params, |
738 const CompletedCallback& callback, | 768 const CompletedCallback& callback, |
739 NativeStackSamplerTestDelegate* test_delegate) | 769 NativeStackSamplerTestDelegate* test_delegate) |
740 : thread_id_(thread_id), | 770 : thread_id_(thread_id), |
741 params_(params), | 771 params_(params), |
742 completed_callback_(callback), | 772 completed_callback_(callback), |
743 // The event starts "signaled" so code knows it's safe to start thread | 773 // 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. | 774 // and "manual" so that it can be waited in multiple places. |
745 profiling_inactive_(WaitableEvent::ResetPolicy::MANUAL, | 775 profiling_inactive_(WaitableEvent::ResetPolicy::MANUAL, |
746 WaitableEvent::InitialState::SIGNALED), | 776 WaitableEvent::InitialState::SIGNALED), |
747 collection_id_(NULL_COLLECTION_ID), | 777 profiler_id_(NULL_PROFILER_ID), |
748 test_delegate_(test_delegate) {} | 778 test_delegate_(test_delegate) {} |
749 | 779 |
750 StackSamplingProfiler::~StackSamplingProfiler() { | 780 StackSamplingProfiler::~StackSamplingProfiler() { |
751 // Stop returns immediately but the shutdown runs asynchronously. There is a | 781 // 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 | 782 // non-zero probability that one more sample will be taken after this call |
753 // returns. | 783 // returns. |
754 Stop(); | 784 Stop(); |
755 | 785 |
756 // The behavior of sampling a thread that has exited is undefined and could | 786 // 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 | 787 // 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, | 804 NativeStackSampler::Create(thread_id_, &RecordAnnotations, |
775 test_delegate_); | 805 test_delegate_); |
776 | 806 |
777 if (!native_sampler) | 807 if (!native_sampler) |
778 return; | 808 return; |
779 | 809 |
780 // Wait for profiling to be "inactive", then reset it for the upcoming run. | 810 // Wait for profiling to be "inactive", then reset it for the upcoming run. |
781 profiling_inactive_.Wait(); | 811 profiling_inactive_.Wait(); |
782 profiling_inactive_.Reset(); | 812 profiling_inactive_.Reset(); |
783 | 813 |
784 DCHECK_EQ(NULL_COLLECTION_ID, collection_id_); | 814 DCHECK_EQ(NULL_PROFILER_ID, profiler_id_); |
785 collection_id_ = SamplingThread::GetInstance()->Add( | 815 profiler_id_ = SamplingThread::GetInstance()->Add( |
786 MakeUnique<SamplingThread::CollectionContext>( | 816 MakeUnique<SamplingThread::CollectionContext>( |
| 817 SamplingThread::CollectionContext::next_profiler_id.GetNext(), |
787 thread_id_, params_, completed_callback_, &profiling_inactive_, | 818 thread_id_, params_, completed_callback_, &profiling_inactive_, |
788 std::move(native_sampler))); | 819 std::move(native_sampler))); |
789 DCHECK_NE(NULL_COLLECTION_ID, collection_id_); | 820 DCHECK_NE(NULL_PROFILER_ID, profiler_id_); |
790 } | 821 } |
791 | 822 |
792 void StackSamplingProfiler::Stop() { | 823 void StackSamplingProfiler::Stop() { |
793 SamplingThread::GetInstance()->Remove(collection_id_); | 824 SamplingThread::GetInstance()->Remove(profiler_id_); |
794 collection_id_ = NULL_COLLECTION_ID; | 825 profiler_id_ = NULL_PROFILER_ID; |
795 } | 826 } |
796 | 827 |
797 // static | 828 // static |
798 void StackSamplingProfiler::SetProcessMilestone(int milestone) { | 829 void StackSamplingProfiler::SetProcessMilestone(int milestone) { |
799 DCHECK_LE(0, milestone); | 830 DCHECK_LE(0, milestone); |
800 DCHECK_GT(static_cast<int>(sizeof(process_milestones_) * 8), milestone); | 831 DCHECK_GT(static_cast<int>(sizeof(process_milestones_) * 8), milestone); |
801 DCHECK_EQ(0, subtle::NoBarrier_Load(&process_milestones_) & (1 << milestone)); | 832 DCHECK_EQ(0, subtle::NoBarrier_Load(&process_milestones_) & (1 << milestone)); |
802 ChangeAtomicFlags(&process_milestones_, 1 << milestone, 0); | 833 ChangeAtomicFlags(&process_milestones_, 1 << milestone, 0); |
803 } | 834 } |
804 | 835 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 } | 876 } |
846 | 877 |
847 bool operator<(const StackSamplingProfiler::Frame &a, | 878 bool operator<(const StackSamplingProfiler::Frame &a, |
848 const StackSamplingProfiler::Frame &b) { | 879 const StackSamplingProfiler::Frame &b) { |
849 return (a.module_index < b.module_index) || | 880 return (a.module_index < b.module_index) || |
850 (a.module_index == b.module_index && | 881 (a.module_index == b.module_index && |
851 a.instruction_pointer < b.instruction_pointer); | 882 a.instruction_pointer < b.instruction_pointer); |
852 } | 883 } |
853 | 884 |
854 } // namespace base | 885 } // namespace base |
OLD | NEW |