Index: base/profiler/stack_sampling_profiler.cc |
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc |
index 57b7b355a080923b2acc4b2201d4e58d7bb666ab..bb0abf27d6b52d203531fce3929f6c946b18f520 100644 |
--- a/base/profiler/stack_sampling_profiler.cc |
+++ b/base/profiler/stack_sampling_profiler.cc |
@@ -9,31 +9,36 @@ |
#include "base/bind.h" |
#include "base/callback.h" |
#include "base/memory/singleton.h" |
+#include "base/profiler/native_stack_sampler.h" |
#include "base/synchronization/lock.h" |
-#include "base/synchronization/waitable_event.h" |
#include "base/timer/elapsed_timer.h" |
-template <typename T> struct DefaultSingletonTraits; |
- |
namespace base { |
+// PendingProfiles ------------------------------------------------------------ |
+ |
namespace { |
// Thread-safe singleton class that stores collected profiles waiting to be |
// processed. |
class PendingProfiles { |
public: |
- PendingProfiles(); |
~PendingProfiles(); |
static PendingProfiles* GetInstance(); |
- // Appends |profiles|. This function is thread safe. |
- void PutProfiles(const std::vector<StackSamplingProfiler::Profile>& profiles); |
- // Gets the pending profiles into *|profiles|. This function is thread safe. |
- void GetProfiles(std::vector<StackSamplingProfiler::Profile>* profiles); |
+ // Appends |profiles| to |profiles_|. This function is thread safe. |
+ void AppendProfiles( |
+ const std::vector<StackSamplingProfiler::Profile>& profiles); |
+ |
+ // Moves the pending profiles from |profiles_| into *|profiles|. This function |
+ // is thread safe. |
+ void MoveProfiles(std::vector<StackSamplingProfiler::Profile>* profiles); |
Peter Kasting
2015/03/30 23:07:34
FWIW, I don't love using "Move" in the function na
Mike Wittman
2015/03/31 01:06:36
Used GetAndClearPendingProfiles().
|
private: |
+ PendingProfiles(); |
+ friend struct DefaultSingletonTraits<PendingProfiles>; |
Peter Kasting
2015/03/30 23:07:34
Nit: The Google style guide is unclear here, but c
Mike Wittman
2015/03/31 01:06:36
Done.
|
+ |
Lock profiles_lock_; |
std::vector<StackSamplingProfiler::Profile> profiles_; |
@@ -49,74 +54,49 @@ PendingProfiles* PendingProfiles::GetInstance() { |
return Singleton<PendingProfiles>::get(); |
} |
-void PendingProfiles::PutProfiles( |
+void PendingProfiles::AppendProfiles( |
const std::vector<StackSamplingProfiler::Profile>& profiles) { |
AutoLock scoped_lock(profiles_lock_); |
profiles_.insert(profiles_.end(), profiles.begin(), profiles.end()); |
} |
-void PendingProfiles::GetProfiles( |
+void PendingProfiles::MoveProfiles( |
std::vector<StackSamplingProfiler::Profile>* profiles) { |
profiles->clear(); |
AutoLock scoped_lock(profiles_lock_); |
profiles_.swap(*profiles); |
} |
+ |
} // namespace |
+// StackSamplingProfiler::Module ---------------------------------------------- |
+ |
StackSamplingProfiler::Module::Module() : base_address(nullptr) {} |
StackSamplingProfiler::Module::~Module() {} |
-StackSamplingProfiler::Frame::Frame() |
- : instruction_pointer(nullptr), |
- module_index(-1) {} |
+// StackSamplingProfiler::Frame ----------------------------------------------- |
+ |
+StackSamplingProfiler::Frame::Frame(const void* instruction_pointer, |
+ size_t module_index) |
+ : instruction_pointer(instruction_pointer), |
+ module_index(module_index) {} |
StackSamplingProfiler::Frame::~Frame() {} |
+// StackSamplingProfiler::Profile --------------------------------------------- |
+ |
StackSamplingProfiler::Profile::Profile() : preserve_sample_ordering(false) {} |
StackSamplingProfiler::Profile::~Profile() {} |
-class StackSamplingProfiler::SamplingThread : public PlatformThread::Delegate { |
- public: |
- // Samples stacks using |native_sampler|. When complete, invokes |
- // |profiles_callback| with the collected profiles. |profiles_callback| must |
- // be thread-safe and may consume the contents of the vector. |
- SamplingThread( |
- scoped_ptr<NativeStackSampler> native_sampler, |
- const SamplingParams& params, |
- Callback<void(const std::vector<Profile>&)> completed_callback); |
- ~SamplingThread() override; |
- |
- // Implementation of PlatformThread::Delegate: |
- void ThreadMain() override; |
- |
- void Stop(); |
- |
- private: |
- // Collects a profile from a single burst. Returns true if the profile was |
- // collected, or false if collection was stopped before it completed. |
- bool CollectProfile(Profile* profile, TimeDelta* elapsed_time); |
- // Collects profiles from all bursts, or until the sampling is stopped. If |
- // stopped before complete, |profiles| will contains only full bursts. |
- void CollectProfiles(std::vector<Profile>* profiles); |
- |
- scoped_ptr<NativeStackSampler> native_sampler_; |
- |
- const SamplingParams params_; |
- |
- WaitableEvent stop_event_; |
- |
- Callback<void(const std::vector<Profile>&)> completed_callback_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SamplingThread); |
-}; |
+// StackSamplingProfiler::SamplingThread -------------------------------------- |
StackSamplingProfiler::SamplingThread::SamplingThread( |
scoped_ptr<NativeStackSampler> native_sampler, |
const SamplingParams& params, |
- Callback<void(const std::vector<Profile>&)> completed_callback) |
+ CompletedCallback completed_callback) |
: native_sampler_(native_sampler.Pass()), |
params_(params), |
stop_event_(false, false), |
@@ -133,6 +113,13 @@ void StackSamplingProfiler::SamplingThread::ThreadMain() { |
completed_callback_.Run(profiles); |
} |
+// Depending on how long the sampling takes and the length of the sampling |
+// interval, a burst of samples could take arbitrarily longer than |
+// samples_per_burst * sampling_interval. In this case, we (somewhat |
+// arbitrarily) honor the number of samples requested rather than strictly |
+// adhereing to the sampling intervals. Once we have established users for the |
Peter Kasting
2015/03/30 23:07:34
Nit: adhering
Mike Wittman
2015/03/31 01:06:36
Done.
|
+// StackSamplingProfiler and the collected data to judge, we may go the other |
+// way or make this behavior configurable. |
bool StackSamplingProfiler::SamplingThread::CollectProfile( |
Profile* profile, |
TimeDelta* elapsed_time) { |
@@ -140,49 +127,59 @@ bool StackSamplingProfiler::SamplingThread::CollectProfile( |
Profile current_profile; |
native_sampler_->ProfileRecordingStarting(¤t_profile); |
current_profile.sampling_period = params_.sampling_interval; |
- bool stopped_early = false; |
+ bool burst_completed = true; |
+ TimeDelta previous_elapsed_sample_time; |
for (int i = 0; i < params_.samples_per_burst; ++i) { |
- ElapsedTimer sample_timer; |
- current_profile.samples.push_back(Sample()); |
- native_sampler_->RecordStackSample(¤t_profile.samples.back()); |
- TimeDelta elapsed_sample_time = sample_timer.Elapsed(); |
- if (i != params_.samples_per_burst - 1) { |
+ if (i != 0) { |
+ // Always wait, even if for 0 seconds, so we can observe a signal on |
+ // stop_event_. |
if (stop_event_.TimedWait( |
- std::max(params_.sampling_interval - elapsed_sample_time, |
+ std::max(params_.sampling_interval - previous_elapsed_sample_time, |
TimeDelta()))) { |
- stopped_early = true; |
+ burst_completed = false; |
break; |
} |
} |
+ ElapsedTimer sample_timer; |
+ current_profile.samples.push_back(Sample()); |
+ native_sampler_->RecordStackSample(¤t_profile.samples.back()); |
+ previous_elapsed_sample_time = sample_timer.Elapsed(); |
} |
*elapsed_time = profile_timer.Elapsed(); |
current_profile.profile_duration = *elapsed_time; |
native_sampler_->ProfileRecordingStopped(); |
- if (!stopped_early) |
+ if (burst_completed) |
*profile = current_profile; |
- return !stopped_early; |
+ return burst_completed; |
} |
+// In an analogous manner to CollectProfiles and samples exceeding the expected |
Peter Kasting
2015/03/30 23:07:34
Nit: CollectProfile()?
Mike Wittman
2015/03/31 01:06:36
Done.
|
+// total sampling time, bursts may also exceed the burst_interval. We adopt the |
+// same wait-and-see approach here. |
void StackSamplingProfiler::SamplingThread::CollectProfiles( |
std::vector<Profile>* profiles) { |
if (stop_event_.TimedWait(params_.initial_delay)) |
return; |
+ TimeDelta previous_elapsed_profile_time; |
for (int i = 0; i < params_.bursts; ++i) { |
+ if (i != 0) { |
+ // Always wait, even if for 0 seconds, so we can observe a signal on |
+ // stop_event_. |
+ if (stop_event_.TimedWait( |
+ std::max(params_.burst_interval - previous_elapsed_profile_time, |
+ TimeDelta()))) |
+ return; |
+ } |
+ |
Profile profile; |
TimeDelta elapsed_profile_time; |
Peter Kasting
2015/03/30 23:07:34
This variable is dead.
Mike Wittman
2015/03/31 01:06:36
Removed.
|
- if (CollectProfile(&profile, &elapsed_profile_time)) |
- profiles->push_back(profile); |
- else |
- return; |
- |
- if (stop_event_.TimedWait( |
- std::max(params_.burst_interval - elapsed_profile_time, |
- TimeDelta()))) |
+ if (!CollectProfile(&profile, &previous_elapsed_profile_time)) |
return; |
+ profiles->push_back(profile); |
} |
} |
@@ -190,14 +187,7 @@ void StackSamplingProfiler::SamplingThread::Stop() { |
stop_event_.Signal(); |
} |
-void StackSamplingProfiler::SamplingThreadDeleter::operator()( |
- SamplingThread* thread) const { |
- delete thread; |
-} |
- |
-StackSamplingProfiler::NativeStackSampler::NativeStackSampler() {} |
- |
-StackSamplingProfiler::NativeStackSampler::~NativeStackSampler() {} |
+// StackSamplingProfiler ------------------------------------------------------ |
StackSamplingProfiler::SamplingParams::SamplingParams() |
: initial_delay(TimeDelta::FromMilliseconds(0)), |
@@ -215,19 +205,20 @@ StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id, |
StackSamplingProfiler::~StackSamplingProfiler() {} |
void StackSamplingProfiler::Start() { |
- native_sampler_ = NativeStackSampler::Create(thread_id_); |
- if (!native_sampler_) |
+ scoped_ptr<NativeStackSampler> native_sampler = |
+ NativeStackSampler::Create(thread_id_); |
+ if (!native_sampler) |
return; |
sampling_thread_.reset( |
new SamplingThread( |
- native_sampler_.Pass(), params_, |
+ native_sampler.Pass(), params_, |
(custom_completed_callback_.is_null() ? |
- Bind(&PendingProfiles::PutProfiles, |
+ Bind(&PendingProfiles::AppendProfiles, |
Unretained(PendingProfiles::GetInstance())) : |
custom_completed_callback_))); |
if (!PlatformThread::CreateNonJoinable(0, sampling_thread_.get())) |
- LOG(ERROR) << "failed to create thread"; |
+ sampling_thread_.reset(); |
} |
void StackSamplingProfiler::Stop() { |
@@ -237,13 +228,10 @@ void StackSamplingProfiler::Stop() { |
// static |
void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) { |
- PendingProfiles::GetInstance()->GetProfiles(profiles); |
+ PendingProfiles::GetInstance()->MoveProfiles(profiles); |
} |
-void StackSamplingProfiler::SetCustomCompletedCallback( |
- Callback<void(const std::vector<Profile>&)> callback) { |
- custom_completed_callback_ = callback; |
-} |
+// StackSamplingProfiler::Frame global functions ------------------------------ |
bool operator==(const StackSamplingProfiler::Frame &a, |
const StackSamplingProfiler::Frame &b) { |
@@ -259,3 +247,4 @@ bool operator<(const StackSamplingProfiler::Frame &a, |
} |
} // namespace base |
+ |