Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: base/profiler/stack_sampling_profiler.cc

Issue 2927593002: Make stack sampling profiler sample beyond startup. (Closed)
Patch Set: Address comments. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 collection_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 : collection_id(collection_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 this collection, used to uniquely identify it to
156 // outside interests. 157 // outside interests.
157 const int collection_id; 158 const int collection_id;
Mike Wittman 2017/07/06 17:25:52 We probably should rename this to something like "
Alexei Svitkine (slow) 2017/07/06 19:36:26 Done.
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 static StaticAtomicSequenceNumber next_collection_id_; 181 static StaticAtomicSequenceNumber next_collection_id_;
Mike Wittman 2017/07/06 17:25:53 nit: drop trailing underscore
Alexei Svitkine (slow) 2017/07/06 19:36:26 Done.
182 }; 182 };
183 183
184 // Gets the single instance of this class. 184 // Gets the single instance of this class.
185 static SamplingThread* GetInstance(); 185 static SamplingThread* GetInstance();
186 186
187 // Adds a new CollectionContext to the thread. This can be called externally 187 // 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 188 // from any thread. This returns an ID that can later be used to stop
189 // the sampling. 189 // the sampling.
190 int Add(std::unique_ptr<CollectionContext> collection); 190 int Add(std::unique_ptr<CollectionContext> collection);
191 191
(...skipping 29 matching lines...) Expand all
221 ~SamplingThread() override; 221 ~SamplingThread() override;
222 222
223 // Get task runner that is usable from the outside. 223 // Get task runner that is usable from the outside.
224 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd(); 224 scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd();
225 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner( 225 scoped_refptr<SingleThreadTaskRunner> GetTaskRunner(
226 ThreadExecutionState* out_state); 226 ThreadExecutionState* out_state);
227 227
228 // Get task runner that is usable from the sampling thread itself. 228 // Get task runner that is usable from the sampling thread itself.
229 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); 229 scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread();
230 230
231 // Finishes a collection and reports collected data via callback. 231 // Finishes a collection and reports collected data via callback. Returns
232 void FinishCollection(CollectionContext* collection); 232 // the new collection params, if a new collection should be started.
233 Optional<SamplingParams> FinishCollection(CollectionContext* collection);
233 234
234 // Records a single sample of a collection. 235 // Records a single sample of a collection.
235 void RecordSample(CollectionContext* collection); 236 void RecordSample(CollectionContext* collection);
236 237
237 // Check if the sampling thread is idle and begin a shutdown if it is. 238 // Check if the sampling thread is idle and begin a shutdown if it is.
238 void ScheduleShutdownIfIdle(); 239 void ScheduleShutdownIfIdle();
239 240
240 // These methods are tasks that get posted to the internal message queue. 241 // These methods are tasks that get posted to the internal message queue.
241 void AddCollectionTask(std::unique_ptr<CollectionContext> collection); 242 void AddCollectionTask(std::unique_ptr<CollectionContext> collection);
242 void RemoveCollectionTask(int id); 243 void RemoveCollectionTask(int id);
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 469
469 scoped_refptr<SingleThreadTaskRunner> 470 scoped_refptr<SingleThreadTaskRunner>
470 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { 471 StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() {
471 // This should be called only from the sampling thread as it has limited 472 // This should be called only from the sampling thread as it has limited
472 // accessibility. 473 // accessibility.
473 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 474 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
474 475
475 return Thread::task_runner(); 476 return Thread::task_runner();
476 } 477 }
477 478
478 void StackSamplingProfiler::SamplingThread::FinishCollection( 479 Optional<StackSamplingProfiler::SamplingParams>
480 StackSamplingProfiler::SamplingThread::FinishCollection(
479 CollectionContext* collection) { 481 CollectionContext* collection) {
480 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 482 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
481 483
482 // If there is no duration for the final profile (because it was stopped), 484 // If there is no duration for the final profile (because it was stopped),
483 // calculate it now. 485 // calculate it now.
484 if (!collection->profiles.empty() && 486 if (!collection->profiles.empty() &&
485 collection->profiles.back().profile_duration == TimeDelta()) { 487 collection->profiles.back().profile_duration == TimeDelta()) {
486 collection->profiles.back().profile_duration = 488 collection->profiles.back().profile_duration =
487 Time::Now() - collection->profile_start_time; 489 Time::Now() - collection->profile_start_time;
488 } 490 }
489 491
490 // Extract some information so callback and event-signalling can still be 492 // 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. 493 // 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 494 // This allows the the controlling object (and tests using it) to be confident
493 // that collection is fully finished when those things occur. 495 // that collection is fully finished when those things occur.
494 const CompletedCallback callback = collection->callback; 496 const CompletedCallback callback = collection->callback;
495 CallStackProfiles profiles = std::move(collection->profiles); 497 CallStackProfiles profiles = std::move(collection->profiles);
496 WaitableEvent* finished = collection->finished; 498 WaitableEvent* finished = collection->finished;
497 499
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. 500 // Run the associated callback, passing the collected profiles.
504 callback.Run(std::move(profiles)); 501 Optional<SamplingParams> new_params = callback.Run(std::move(profiles));
505 502
506 // Signal that this collection is finished. 503 // Signal that this collection is finished.
507 finished->Signal(); 504 finished->Signal();
505
506 return new_params;
508 } 507 }
509 508
510 void StackSamplingProfiler::SamplingThread::RecordSample( 509 void StackSamplingProfiler::SamplingThread::RecordSample(
511 CollectionContext* collection) { 510 CollectionContext* collection) {
512 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 511 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
513 DCHECK(collection->native_sampler); 512 DCHECK(collection->native_sampler);
514 513
515 // If this is the first sample of a burst, a new Profile needs to be created 514 // If this is the first sample of a burst, a new Profile needs to be created
516 // and filled. 515 // and filled.
517 if (collection->sample == 0) { 516 if (collection->sample == 0) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 } 581 }
583 } 582 }
584 583
585 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { 584 void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) {
586 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 585 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
587 586
588 auto found = active_collections_.find(id); 587 auto found = active_collections_.find(id);
589 if (found == active_collections_.end()) 588 if (found == active_collections_.end())
590 return; 589 return;
591 590
592 FinishCollection(found->second.get()); 591 auto* collection = found->second.get();
592 FinishCollection(collection);
593
594 // Remove this collection from the map of known ones. After this,
595 // |collection| will be invalid.
596 size_t count = active_collections_.erase(collection->collection_id);
597 DCHECK_EQ(1U, count);
598
593 ScheduleShutdownIfIdle(); 599 ScheduleShutdownIfIdle();
594 } 600 }
595 601
596 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { 602 void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) {
597 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 603 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
598 604
599 auto found = active_collections_.find(id); 605 auto found = active_collections_.find(id);
600 606
601 // The task won't be found if it has been stopped. 607 // The task won't be found if it has been stopped.
602 if (found == active_collections_.end()) 608 if (found == active_collections_.end())
603 return; 609 return;
604 610
605 CollectionContext* collection = found->second.get(); 611 CollectionContext* collection = found->second.get();
606 612
607 // Handle first-run with no "next time". 613 // Handle first-run with no "next time".
608 if (collection->next_sample_time == Time()) 614 if (collection->next_sample_time == Time())
609 collection->next_sample_time = Time::Now(); 615 collection->next_sample_time = Time::Now();
610 616
611 // Do the collection of a single sample. 617 // Do the collection of a single sample.
612 RecordSample(collection); 618 RecordSample(collection);
613 619
614 // Update the time of the next sample recording. 620 // Update the time of the next sample recording.
615 if (UpdateNextSampleTime(collection)) { 621 const bool collection_finished = !UpdateNextSampleTime(collection);
616 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( 622 if (collection_finished) {
617 FROM_HERE, 623 // All capturing has completed so finish the collection. If no new params
618 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), 624 // are returned, a new collection should not be started.
619 std::max(collection->next_sample_time - Time::Now(), TimeDelta())); 625 Optional<SamplingParams> new_params = FinishCollection(collection);
620 DCHECK(success); 626 if (!new_params.has_value()) {
621 } else { 627 // Remove this collection from the map of known ones. After this,
622 // All capturing has completed so finish the collection. By not re-adding 628 // |collection| will be invalid.
623 // it to the task queue, the collection will "expire" (i.e. no further work 629 size_t count = active_collections_.erase(collection->collection_id);
624 // will be done). The |collection| variable will be invalid after this call. 630 DCHECK_EQ(1U, count);
625 FinishCollection(collection); 631
626 ScheduleShutdownIfIdle(); 632 // By not adding it to the task queue, the collection will "expire" (i.e.
633 // no further work will be done).
634 ScheduleShutdownIfIdle();
635 return;
636 }
637
638 // Restart the collection with the new params. Keep the same collection
639 // id so the Stop() operation continues to work.
640 auto new_collection = MakeUnique<SamplingThread::CollectionContext>(
641 collection->collection_id, collection->target, new_params.value(),
642 collection->callback, collection->finished,
643 std::move(collection->native_sampler));
644 new_collection->next_sample_time =
Mike Wittman 2017/07/06 17:25:52 Can we reuse the logic in AddCollectionTask for re
Alexei Svitkine (slow) 2017/07/06 19:36:25 The way it's structured right now, it re-uses the
Mike Wittman 2017/07/06 22:14:01 I was thinking that we could remove the old collec
645 Time::Now() + collection->params.initial_delay;
646 // Replace |collection| in the map by |new_collection|. After this,
647 // |collection| will be invalid.
648 found->second = std::move(new_collection);
627 } 649 }
650
651 bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
652 FROM_HERE,
653 BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id),
654 std::max(collection->next_sample_time - Time::Now(), TimeDelta()));
655 DCHECK(success);
628 } 656 }
629 657
630 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { 658 void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) {
631 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); 659 DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
632 660
633 // Holding this lock ensures that any attempt to start another job will 661 // Holding this lock ensures that any attempt to start another job will
634 // get postponed until |thread_execution_state_| is updated, thus eliminating 662 // get postponed until |thread_execution_state_| is updated, thus eliminating
635 // the race in starting a new thread while the previous one is exiting. 663 // the race in starting a new thread while the previous one is exiting.
636 AutoLock lock(thread_execution_state_lock_); 664 AutoLock lock(thread_execution_state_lock_);
637 665
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
777 if (!native_sampler) 805 if (!native_sampler)
778 return; 806 return;
779 807
780 // Wait for profiling to be "inactive", then reset it for the upcoming run. 808 // Wait for profiling to be "inactive", then reset it for the upcoming run.
781 profiling_inactive_.Wait(); 809 profiling_inactive_.Wait();
782 profiling_inactive_.Reset(); 810 profiling_inactive_.Reset();
783 811
784 DCHECK_EQ(NULL_COLLECTION_ID, collection_id_); 812 DCHECK_EQ(NULL_COLLECTION_ID, collection_id_);
785 collection_id_ = SamplingThread::GetInstance()->Add( 813 collection_id_ = SamplingThread::GetInstance()->Add(
786 MakeUnique<SamplingThread::CollectionContext>( 814 MakeUnique<SamplingThread::CollectionContext>(
815 SamplingThread::CollectionContext::next_collection_id_.GetNext(),
787 thread_id_, params_, completed_callback_, &profiling_inactive_, 816 thread_id_, params_, completed_callback_, &profiling_inactive_,
788 std::move(native_sampler))); 817 std::move(native_sampler)));
789 DCHECK_NE(NULL_COLLECTION_ID, collection_id_); 818 DCHECK_NE(NULL_COLLECTION_ID, collection_id_);
790 } 819 }
791 820
792 void StackSamplingProfiler::Stop() { 821 void StackSamplingProfiler::Stop() {
793 SamplingThread::GetInstance()->Remove(collection_id_); 822 SamplingThread::GetInstance()->Remove(collection_id_);
794 collection_id_ = NULL_COLLECTION_ID; 823 collection_id_ = NULL_COLLECTION_ID;
795 } 824 }
796 825
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 } 874 }
846 875
847 bool operator<(const StackSamplingProfiler::Frame &a, 876 bool operator<(const StackSamplingProfiler::Frame &a,
848 const StackSamplingProfiler::Frame &b) { 877 const StackSamplingProfiler::Frame &b) {
849 return (a.module_index < b.module_index) || 878 return (a.module_index < b.module_index) ||
850 (a.module_index == b.module_index && 879 (a.module_index == b.module_index &&
851 a.instruction_pointer < b.instruction_pointer); 880 a.instruction_pointer < b.instruction_pointer);
852 } 881 }
853 882
854 } // namespace base 883 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698