diff options
Diffstat (limited to 'chromium/base/profiler/stack_sampling_profiler.cc')
-rw-r--r-- | chromium/base/profiler/stack_sampling_profiler.cc | 129 |
1 files changed, 81 insertions, 48 deletions
diff --git a/chromium/base/profiler/stack_sampling_profiler.cc b/chromium/base/profiler/stack_sampling_profiler.cc index 76ad81df9e8..6e8370e92c9 100644 --- a/chromium/base/profiler/stack_sampling_profiler.cc +++ b/chromium/base/profiler/stack_sampling_profiler.cc @@ -31,7 +31,7 @@ namespace { // This value is used when there is no collection in progress and thus no ID // for referencing the active collection to the SamplingThread. -const int NULL_COLLECTION_ID = -1; +const int NULL_PROFILER_ID = -1; void ChangeAtomicFlags(subtle::Atomic32* flags, subtle::Atomic32 set, @@ -139,12 +139,13 @@ class StackSamplingProfiler::SamplingThread : public Thread { }; struct CollectionContext { - CollectionContext(PlatformThreadId target, + CollectionContext(int profiler_id, + PlatformThreadId target, const SamplingParams& params, const CompletedCallback& callback, WaitableEvent* finished, std::unique_ptr<NativeStackSampler> sampler) - : collection_id(next_collection_id_.GetNext()), + : profiler_id(profiler_id), target(target), params(params), callback(callback), @@ -152,9 +153,9 @@ class StackSamplingProfiler::SamplingThread : public Thread { native_sampler(std::move(sampler)) {} ~CollectionContext() {} - // An identifier for this collection, used to uniquely identify it to - // outside interests. - const int collection_id; + // An identifier for the profiler associated with this collection, used to + // uniquely identify the collection to outside interests. + const int profiler_id; const PlatformThreadId target; // ID of The thread being sampled. const SamplingParams params; // Information about how to sample. @@ -177,8 +178,8 @@ class StackSamplingProfiler::SamplingThread : public Thread { // The collected stack samples. The active profile is always at the back(). CallStackProfiles profiles; - private: - static StaticAtomicSequenceNumber next_collection_id_; + // Sequence number for generating new profiler ids. + static AtomicSequenceNumber next_profiler_id; }; // Gets the single instance of this class. @@ -228,8 +229,11 @@ class StackSamplingProfiler::SamplingThread : public Thread { // Get task runner that is usable from the sampling thread itself. scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread(); - // Finishes a collection and reports collected data via callback. - void FinishCollection(CollectionContext* collection); + // Finishes a collection and reports collected data via callback. Returns + // the new collection params, if a new collection should be started. The + // |collection| should already have been removed from |active_collections_| + // by the caller, as this is needed to avoid flakyness in unit tests. + Optional<SamplingParams> FinishCollection(CollectionContext* collection); // Records a single sample of a collection. void RecordSample(CollectionContext* collection); @@ -346,9 +350,9 @@ void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownAssumingIdle( WaitableEvent::InitialState::NOT_SIGNALED); // PostTaskAndReply won't work because thread and associated message-loop may // be shut down. - task_runner->PostTask(FROM_HERE, - Bind(&ShutdownTaskAndSignalEvent, Unretained(sampler), - add_events, Unretained(&executed))); + task_runner->PostTask( + FROM_HERE, BindOnce(&ShutdownTaskAndSignalEvent, Unretained(sampler), + add_events, Unretained(&executed))); executed.Wait(); } @@ -361,8 +365,8 @@ void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent( event->Signal(); } -StaticAtomicSequenceNumber StackSamplingProfiler::SamplingThread:: - CollectionContext::next_collection_id_; +AtomicSequenceNumber + StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id; StackSamplingProfiler::SamplingThread::SamplingThread() : Thread("StackSamplingProfiler") {} @@ -378,12 +382,13 @@ int StackSamplingProfiler::SamplingThread::Add( std::unique_ptr<CollectionContext> collection) { // This is not to be run on the sampling thread. - int id = collection->collection_id; + int id = collection->profiler_id; scoped_refptr<SingleThreadTaskRunner> task_runner = GetOrCreateTaskRunnerForAdd(); - task_runner->PostTask(FROM_HERE, Bind(&SamplingThread::AddCollectionTask, - Unretained(this), Passed(&collection))); + task_runner->PostTask( + FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this), + Passed(&collection))); return id; } @@ -400,8 +405,9 @@ void StackSamplingProfiler::SamplingThread::Remove(int id) { // This can fail if the thread were to exit between acquisition of the task // runner above and the call below. In that case, however, everything has // stopped so there's no need to try to stop it. - task_runner->PostTask(FROM_HERE, Bind(&SamplingThread::RemoveCollectionTask, - Unretained(this), id)); + task_runner->PostTask( + FROM_HERE, + BindOnce(&SamplingThread::RemoveCollectionTask, Unretained(this), id)); } scoped_refptr<SingleThreadTaskRunner> @@ -473,16 +479,19 @@ StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() { return Thread::task_runner(); } -void StackSamplingProfiler::SamplingThread::FinishCollection( +Optional<StackSamplingProfiler::SamplingParams> +StackSamplingProfiler::SamplingThread::FinishCollection( CollectionContext* collection) { DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); + DCHECK_EQ(0u, active_collections_.count(collection->profiler_id)); // If there is no duration for the final profile (because it was stopped), // calculate it now. if (!collection->profiles.empty() && collection->profiles.back().profile_duration == TimeDelta()) { collection->profiles.back().profile_duration = - Time::Now() - collection->profile_start_time; + Time::Now() - collection->profile_start_time + + collection->params.sampling_interval; } // Extract some information so callback and event-signalling can still be @@ -493,16 +502,13 @@ void StackSamplingProfiler::SamplingThread::FinishCollection( CallStackProfiles profiles = std::move(collection->profiles); WaitableEvent* finished = collection->finished; - // Remove this collection from the map of known ones. The |collection| - // parameter is invalid after this point. - size_t count = active_collections_.erase(collection->collection_id); - DCHECK_EQ(1U, count); - // Run the associated callback, passing the collected profiles. - callback.Run(std::move(profiles)); + Optional<SamplingParams> new_params = callback.Run(std::move(profiles)); // Signal that this collection is finished. finished->Signal(); + + return new_params; } void StackSamplingProfiler::SamplingThread::RecordSample( @@ -530,7 +536,8 @@ void StackSamplingProfiler::SamplingThread::RecordSample( // If this is the last sample of a burst, record the total time. if (collection->sample == collection->params.samples_per_burst - 1) { - profile.profile_duration = Time::Now() - collection->profile_start_time; + profile.profile_duration = Time::Now() - collection->profile_start_time + + collection->params.sampling_interval; collection->native_sampler->ProfileRecordingStopped(stack_buffer_.get()); } } @@ -551,7 +558,7 @@ void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() { GetTaskRunnerOnSamplingThread()->PostDelayedTask( FROM_HERE, - Bind(&SamplingThread::ShutdownTask, Unretained(this), add_events), + BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events), TimeDelta::FromSeconds(60)); } @@ -559,16 +566,16 @@ void StackSamplingProfiler::SamplingThread::AddCollectionTask( std::unique_ptr<CollectionContext> collection) { DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId()); - const int collection_id = collection->collection_id; + const int profiler_id = collection->profiler_id; const TimeDelta initial_delay = collection->params.initial_delay; active_collections_.insert( - std::make_pair(collection_id, std::move(collection))); + std::make_pair(profiler_id, std::move(collection))); GetTaskRunnerOnSamplingThread()->PostDelayedTask( FROM_HERE, - Bind(&SamplingThread::PerformCollectionTask, Unretained(this), - collection_id), + BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), + profiler_id), initial_delay); // Another increment of "add events" serves to invalidate any pending @@ -587,7 +594,12 @@ void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) { if (found == active_collections_.end()) return; - FinishCollection(found->second.get()); + // Remove |collection| from |active_collections_|. + std::unique_ptr<CollectionContext> collection = std::move(found->second); + size_t count = active_collections_.erase(id); + DCHECK_EQ(1U, count); + + FinishCollection(collection.get()); ScheduleShutdownIfIdle(); } @@ -610,19 +622,39 @@ void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) { RecordSample(collection); // Update the time of the next sample recording. - if (UpdateNextSampleTime(collection)) { + const bool collection_finished = !UpdateNextSampleTime(collection); + if (!collection_finished) { bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask( FROM_HERE, - Bind(&SamplingThread::PerformCollectionTask, Unretained(this), id), + BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id), std::max(collection->next_sample_time - Time::Now(), TimeDelta())); DCHECK(success); - } else { - // All capturing has completed so finish the collection. By not re-adding - // it to the task queue, the collection will "expire" (i.e. no further work - // will be done). The |collection| variable will be invalid after this call. - FinishCollection(collection); + return; + } + + // Take ownership of |collection| and remove it from the map. If collection is + // to be restarted, a new collection task will be added below. + std::unique_ptr<CollectionContext> owned_collection = + std::move(found->second); + size_t count = active_collections_.erase(id); + DCHECK_EQ(1U, count); + + // All capturing has completed so finish the collection. If no new params + // are returned, a new collection should not be started. + Optional<SamplingParams> new_params = FinishCollection(collection); + if (!new_params.has_value()) { + // By not adding it to the task queue, the collection will "expire" (i.e. + // no further work will be done). ScheduleShutdownIfIdle(); + return; } + + // Restart the collection with the new params. Keep the same id so the + // Stop() operation continues to work. + auto new_collection = MakeUnique<SamplingThread::CollectionContext>( + id, collection->target, new_params.value(), collection->callback, + collection->finished, std::move(collection->native_sampler)); + AddCollectionTask(std::move(new_collection)); } void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) { @@ -742,7 +774,7 @@ StackSamplingProfiler::StackSamplingProfiler( // and "manual" so that it can be waited in multiple places. profiling_inactive_(WaitableEvent::ResetPolicy::MANUAL, WaitableEvent::InitialState::SIGNALED), - collection_id_(NULL_COLLECTION_ID), + profiler_id_(NULL_PROFILER_ID), test_delegate_(test_delegate) {} StackSamplingProfiler::~StackSamplingProfiler() { @@ -779,17 +811,18 @@ void StackSamplingProfiler::Start() { profiling_inactive_.Wait(); profiling_inactive_.Reset(); - DCHECK_EQ(NULL_COLLECTION_ID, collection_id_); - collection_id_ = SamplingThread::GetInstance()->Add( + DCHECK_EQ(NULL_PROFILER_ID, profiler_id_); + profiler_id_ = SamplingThread::GetInstance()->Add( MakeUnique<SamplingThread::CollectionContext>( + SamplingThread::CollectionContext::next_profiler_id.GetNext(), thread_id_, params_, completed_callback_, &profiling_inactive_, std::move(native_sampler))); - DCHECK_NE(NULL_COLLECTION_ID, collection_id_); + DCHECK_NE(NULL_PROFILER_ID, profiler_id_); } void StackSamplingProfiler::Stop() { - SamplingThread::GetInstance()->Remove(collection_id_); - collection_id_ = NULL_COLLECTION_ID; + SamplingThread::GetInstance()->Remove(profiler_id_); + profiler_id_ = NULL_PROFILER_ID; } // static |