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..2284a25dcec953121ea2d90a7e187fd9105bd29f 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. 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); |
@@ -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,16 +479,20 @@ 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)); |
+ LOG(ERROR) << "FinishCollection call"; |
// 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 |
@@ -495,16 +503,15 @@ 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)); |
+ LOG(ERROR) << "FinishCollection before signal, with new_params=" |
+ << new_params.has_value(); |
// Signal that this collection is finished. |
finished->Signal(); |
+ |
+ return new_params; |
} |
void StackSamplingProfiler::SamplingThread::RecordSample( |
@@ -532,7 +539,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()); |
} |
} |
@@ -561,16 +569,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 +597,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(); |
} |
@@ -612,19 +625,41 @@ 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, |
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; |
+ } |
+ LOG(ERROR) << "Collection finished"; |
+ |
+ // 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; |
} |
+ LOG(ERROR) << "Scheduling new collection"; |
+ |
+ // 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) { |
@@ -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 |