| Index: base/profiler/stack_sampling_profiler.cc
|
| diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
|
| index 39d665cb24f77064097330137c0818142ed4004c..6145c5b9132a023b03645b448d3aaccb81a3be44 100644
|
| --- a/base/profiler/stack_sampling_profiler.cc
|
| +++ b/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 StaticAtomicSequenceNumber 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. If there
|
| + // are new params, |collection| will be erased from |active_collections_| map
|
| + // and thus made invalid.
|
| + Optional<SamplingParams> FinishCollection(CollectionContext* collection);
|
|
|
| // Records a single sample of a collection.
|
| void RecordSample(CollectionContext* collection);
|
| @@ -361,8 +365,8 @@ void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent(
|
| event->Signal();
|
| }
|
|
|
| -StaticAtomicSequenceNumber StackSamplingProfiler::SamplingThread::
|
| - CollectionContext::next_collection_id_;
|
| +StaticAtomicSequenceNumber
|
| + StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id;
|
|
|
| StackSamplingProfiler::SamplingThread::SamplingThread()
|
| : Thread("StackSamplingProfiler") {}
|
| @@ -378,7 +382,7 @@ 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();
|
|
|
| @@ -475,7 +479,8 @@ StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() {
|
| return Thread::task_runner();
|
| }
|
|
|
| -void StackSamplingProfiler::SamplingThread::FinishCollection(
|
| +Optional<StackSamplingProfiler::SamplingParams>
|
| +StackSamplingProfiler::SamplingThread::FinishCollection(
|
| CollectionContext* collection) {
|
| DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
|
|
|
| @@ -495,16 +500,20 @@ 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));
|
| + if (!new_params.has_value()) {
|
| + // Since there are no params for a new collection, remove |collection| from
|
| + // the map of known ones, after which it will be invalid. Note: This must be
|
| + // done before Signal() in order for tests to not be flaky.
|
| + size_t count = active_collections_.erase(collection->profiler_id);
|
| + DCHECK_EQ(1U, count);
|
| + }
|
|
|
| // Signal that this collection is finished.
|
| finished->Signal();
|
| +
|
| + return new_params;
|
| }
|
|
|
| void StackSamplingProfiler::SamplingThread::RecordSample(
|
| @@ -561,16 +570,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,
|
| BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this),
|
| - collection_id),
|
| + profiler_id),
|
| initial_delay);
|
|
|
| // Another increment of "add events" serves to invalidate any pending
|
| @@ -589,7 +598,15 @@ void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) {
|
| if (found == active_collections_.end())
|
| return;
|
|
|
| - FinishCollection(found->second.get());
|
| + auto* collection = found->second.get();
|
| + auto new_params = FinishCollection(collection);
|
| + if (new_params.has_value()) {
|
| + // If there's new params, FinishCollection() did not erase |collection|, so
|
| + // do it here. After this, |collection| will be invalid.
|
| + size_t count = active_collections_.erase(collection->profiler_id);
|
| + DCHECK_EQ(1U, count);
|
| + }
|
| +
|
| ScheduleShutdownIfIdle();
|
| }
|
|
|
| @@ -612,19 +629,37 @@ void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) {
|
| RecordSample(collection);
|
|
|
| // Update the time of the next sample recording.
|
| - if (UpdateNextSampleTime(collection)) {
|
| - bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
|
| - FROM_HERE,
|
| - 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);
|
| - ScheduleShutdownIfIdle();
|
| + const bool collection_finished = !UpdateNextSampleTime(collection);
|
| + if (collection_finished) {
|
| + // 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). Note: |collection| has already been
|
| + // erased by FinishCollection() in this case.
|
| + ScheduleShutdownIfIdle();
|
| + return;
|
| + }
|
| +
|
| + // Restart the collection with the new params. Keep the same collection
|
| + // id so the Stop() operation continues to work.
|
| + auto new_collection = MakeUnique<SamplingThread::CollectionContext>(
|
| + collection->profiler_id, collection->target, new_params.value(),
|
| + collection->callback, collection->finished,
|
| + std::move(collection->native_sampler));
|
| + new_collection->next_sample_time =
|
| + Time::Now() + collection->params.initial_delay;
|
| + // Replace |collection| in the map by |new_collection|. After this,
|
| + // |collection| will be invalid.
|
| + found->second = std::move(new_collection);
|
| }
|
| +
|
| + bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
|
| + FROM_HERE,
|
| + BindOnce(&SamplingThread::PerformCollectionTask, Unretained(this), id),
|
| + std::max(collection->next_sample_time - Time::Now(), TimeDelta()));
|
| + DCHECK(success);
|
| }
|
|
|
| void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) {
|
| @@ -744,7 +779,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() {
|
| @@ -781,17 +816,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
|
|
|