Index: base/profiler/stack_sampling_profiler.cc |
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc |
index 317400b2d4d70422b34f1abe7af1f4975e046522..1c08234fdf39ae05d5ff0d6326e49effb92cab01 100644 |
--- a/base/profiler/stack_sampling_profiler.cc |
+++ b/base/profiler/stack_sampling_profiler.cc |
@@ -15,61 +15,102 @@ |
namespace base { |
-// PendingProfiles ------------------------------------------------------------ |
+// DefaultProfileProcessor ---------------------------------------------------- |
namespace { |
-// Thread-safe singleton class that stores collected call stack profiles waiting |
-// to be processed. |
-class PendingProfiles { |
+// Singleton class responsible for providing the default processing for profiles |
+// (i.e. for profiles generated by profilers without their own completed |
+// callback). |
+class DefaultProfileProcessor { |
public: |
- ~PendingProfiles(); |
+ using CompletedCallback = StackSamplingProfiler::CompletedCallback; |
- static PendingProfiles* GetInstance(); |
+ ~DefaultProfileProcessor(); |
- // Appends |profiles| to |profiles_|. This function may be called on any |
- // thread. |
- void AppendProfiles( |
- const std::vector<StackSamplingProfiler::CallStackProfile>& profiles); |
+ static DefaultProfileProcessor* GetInstance(); |
+ |
+ // Sets the callback to use for processing profiles captured without a |
+ // per-profiler completed callback. Pending completed profiles are stored in |
+ // this object until a non-null callback is provided here. This function is |
+ // thread-safe. |
+ void SetCompletedCallback(CompletedCallback callback); |
+ |
+ // Processes |profiles|. This function is thread safe. |
+ void ProcessProfiles( |
+ const StackSamplingProfiler::CallStackProfiles& profiles); |
+ |
+ private: |
+ friend struct DefaultSingletonTraits<DefaultProfileProcessor>; |
+ |
+ DefaultProfileProcessor(); |
// Copies the pending profiles from |profiles_| into |profiles|, and clears |
// |profiles_|. This function may be called on any thread. |
void GetAndClearPendingProfiles( |
- std::vector<StackSamplingProfiler::CallStackProfile>* profiles); |
+ StackSamplingProfiler::CallStackProfiles* profiles); |
- private: |
- friend struct DefaultSingletonTraits<PendingProfiles>; |
+ // Gets the current completed callback, with proper locking. |
+ CompletedCallback GetCompletedCallback() const; |
- PendingProfiles(); |
+ mutable Lock callback_lock_; |
+ CompletedCallback default_completed_callback_; |
Lock profiles_lock_; |
- std::vector<StackSamplingProfiler::CallStackProfile> profiles_; |
+ StackSamplingProfiler::CallStackProfiles profiles_; |
- DISALLOW_COPY_AND_ASSIGN(PendingProfiles); |
+ DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor); |
}; |
-PendingProfiles::PendingProfiles() {} |
- |
-PendingProfiles::~PendingProfiles() {} |
+DefaultProfileProcessor::~DefaultProfileProcessor() {} |
// static |
-PendingProfiles* PendingProfiles::GetInstance() { |
- return Singleton<PendingProfiles>::get(); |
+DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() { |
+ return Singleton<DefaultProfileProcessor>::get(); |
} |
-void PendingProfiles::AppendProfiles( |
- const std::vector<StackSamplingProfiler::CallStackProfile>& profiles) { |
- AutoLock scoped_lock(profiles_lock_); |
- profiles_.insert(profiles_.end(), profiles.begin(), profiles.end()); |
+void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) { |
+ { |
+ AutoLock scoped_lock(callback_lock_); |
+ default_completed_callback_ = callback; |
+ } |
+ |
+ if (!callback.is_null()) { |
+ // Provide any pending profiles to the callback immediately. |
+ StackSamplingProfiler::CallStackProfiles profiles; |
+ GetAndClearPendingProfiles(&profiles); |
+ if (!profiles.empty()) |
+ callback.Run(profiles); |
+ } |
+} |
+ |
+void DefaultProfileProcessor::ProcessProfiles( |
+ const StackSamplingProfiler::CallStackProfiles& profiles) { |
+ CompletedCallback callback = GetCompletedCallback(); |
+ |
+ // Store pending profiles if we don't have a valid callback. |
+ if (!callback.is_null()) { |
+ callback.Run(profiles); |
+ } else { |
+ AutoLock scoped_lock(profiles_lock_); |
+ profiles_.insert(profiles_.end(), profiles.begin(), profiles.end()); |
+ } |
} |
-void PendingProfiles::GetAndClearPendingProfiles( |
- std::vector<StackSamplingProfiler::CallStackProfile>* profiles) { |
+DefaultProfileProcessor::DefaultProfileProcessor() {} |
+ |
+void DefaultProfileProcessor::GetAndClearPendingProfiles( |
+ StackSamplingProfiler::CallStackProfiles* profiles) { |
profiles->clear(); |
AutoLock scoped_lock(profiles_lock_); |
profiles_.swap(*profiles); |
} |
+DefaultProfileProcessor::CompletedCallback |
+DefaultProfileProcessor::GetCompletedCallback() const { |
+ AutoLock scoped_lock(callback_lock_); |
+ return default_completed_callback_; |
+} |
} // namespace |
@@ -209,7 +250,16 @@ StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id, |
const SamplingParams& params) |
: thread_id_(thread_id), params_(params) {} |
-StackSamplingProfiler::~StackSamplingProfiler() {} |
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id, |
+ const SamplingParams& params, |
+ CompletedCallback callback) |
+ : thread_id_(thread_id), params_(params), completed_callback_(callback) {} |
+ |
+StackSamplingProfiler::~StackSamplingProfiler() { |
+ Stop(); |
+ if (!sampling_thread_handle_.is_null()) |
+ PlatformThread::Join(sampling_thread_handle_); |
+} |
void StackSamplingProfiler::Start() { |
scoped_ptr<NativeStackSampler> native_sampler = |
@@ -217,14 +267,14 @@ void StackSamplingProfiler::Start() { |
if (!native_sampler) |
return; |
+ CompletedCallback callback = |
+ !completed_callback_.is_null() ? completed_callback_ : |
+ Bind(&DefaultProfileProcessor::ProcessProfiles, |
+ Unretained(DefaultProfileProcessor::GetInstance())); |
sampling_thread_.reset( |
- new SamplingThread( |
- native_sampler.Pass(), params_, |
- (custom_completed_callback_.is_null() ? |
- Bind(&PendingProfiles::AppendProfiles, |
- Unretained(PendingProfiles::GetInstance())) : |
- custom_completed_callback_))); |
- if (!PlatformThread::CreateNonJoinable(0, sampling_thread_.get())) |
+ new SamplingThread(native_sampler.Pass(), params_, callback)); |
+ if (!PlatformThread::Create(0, sampling_thread_.get(), |
+ &sampling_thread_handle_)) |
sampling_thread_.reset(); |
} |
@@ -234,8 +284,9 @@ void StackSamplingProfiler::Stop() { |
} |
// static |
-void StackSamplingProfiler::GetPendingProfiles(CallStackProfiles* profiles) { |
- PendingProfiles::GetInstance()->GetAndClearPendingProfiles(profiles); |
+void StackSamplingProfiler::SetDefaultCompletedCallback( |
+ CompletedCallback callback) { |
+ DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback); |
} |
// StackSamplingProfiler::Frame global functions ------------------------------ |