| Index: base/profiler/stack_sampling_profiler.cc
|
| diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
|
| index f7605079953769e162aa7463ebc54c6ea772485a..317400b2d4d70422b34f1abe7af1f4975e046522 100644
|
| --- a/base/profiler/stack_sampling_profiler.cc
|
| +++ b/base/profiler/stack_sampling_profiler.cc
|
| @@ -9,33 +9,41 @@
|
| #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.
|
| +// Thread-safe singleton class that stores collected call stack 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 may be called on any
|
| + // thread.
|
| + void AppendProfiles(
|
| + const std::vector<StackSamplingProfiler::CallStackProfile>& profiles);
|
| +
|
| + // 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);
|
|
|
| private:
|
| + friend struct DefaultSingletonTraits<PendingProfiles>;
|
| +
|
| + PendingProfiles();
|
| +
|
| Lock profiles_lock_;
|
| - std::vector<StackSamplingProfiler::Profile> profiles_;
|
| + std::vector<StackSamplingProfiler::CallStackProfile> profiles_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
|
| };
|
| @@ -49,21 +57,24 @@ PendingProfiles* PendingProfiles::GetInstance() {
|
| return Singleton<PendingProfiles>::get();
|
| }
|
|
|
| -void PendingProfiles::PutProfiles(
|
| - const std::vector<StackSamplingProfiler::Profile>& profiles) {
|
| +void PendingProfiles::AppendProfiles(
|
| + const std::vector<StackSamplingProfiler::CallStackProfile>& profiles) {
|
| AutoLock scoped_lock(profiles_lock_);
|
| profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
|
| }
|
|
|
| -void PendingProfiles::GetProfiles(
|
| - std::vector<StackSamplingProfiler::Profile>* profiles) {
|
| +void PendingProfiles::GetAndClearPendingProfiles(
|
| + std::vector<StackSamplingProfiler::CallStackProfile>* profiles) {
|
| profiles->clear();
|
|
|
| AutoLock scoped_lock(profiles_lock_);
|
| profiles_.swap(*profiles);
|
| }
|
| +
|
| } // namespace
|
|
|
| +// StackSamplingProfiler::Module ----------------------------------------------
|
| +
|
| StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
|
| StackSamplingProfiler::Module::Module(const void* base_address,
|
| const std::string& id,
|
| @@ -72,60 +83,28 @@ StackSamplingProfiler::Module::Module(const void* base_address,
|
|
|
| StackSamplingProfiler::Module::~Module() {}
|
|
|
| -StackSamplingProfiler::Frame::Frame()
|
| - : instruction_pointer(nullptr),
|
| - module_index(-1) {}
|
| +// StackSamplingProfiler::Frame -----------------------------------------------
|
|
|
| StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
|
| - int module_index)
|
| + size_t module_index)
|
| : instruction_pointer(instruction_pointer),
|
| module_index(module_index) {}
|
|
|
| StackSamplingProfiler::Frame::~Frame() {}
|
|
|
| -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_;
|
| +// StackSamplingProfiler::CallStackProfile ------------------------------------
|
|
|
| - WaitableEvent stop_event_;
|
| +StackSamplingProfiler::CallStackProfile::CallStackProfile()
|
| + : preserve_sample_ordering(false) {}
|
|
|
| - Callback<void(const std::vector<Profile>&)> completed_callback_;
|
| +StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
|
|
|
| - 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),
|
| @@ -137,61 +116,77 @@ StackSamplingProfiler::SamplingThread::~SamplingThread() {}
|
| void StackSamplingProfiler::SamplingThread::ThreadMain() {
|
| PlatformThread::SetName("Chrome_SamplingProfilerThread");
|
|
|
| - std::vector<Profile> profiles;
|
| + CallStackProfiles profiles;
|
| CollectProfiles(&profiles);
|
| 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
|
| +// adhering to the sampling intervals. Once we have established users for the
|
| +// StackSamplingProfiler and the collected data to judge, we may go the other
|
| +// way or make this behavior configurable.
|
| bool StackSamplingProfiler::SamplingThread::CollectProfile(
|
| - Profile* profile,
|
| + CallStackProfile* profile,
|
| TimeDelta* elapsed_time) {
|
| ElapsedTimer profile_timer;
|
| - Profile current_profile;
|
| - native_sampler_->ProfileRecordingStarting(¤t_profile);
|
| + CallStackProfile current_profile;
|
| + native_sampler_->ProfileRecordingStarting(¤t_profile.modules);
|
| 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 CollectProfile() and samples exceeding the expected
|
| +// 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) {
|
| + CallStackProfiles* profiles) {
|
| if (stop_event_.TimedWait(params_.initial_delay))
|
| return;
|
|
|
| + TimeDelta previous_elapsed_profile_time;
|
| for (int i = 0; i < params_.bursts; ++i) {
|
| - Profile profile;
|
| - TimeDelta elapsed_profile_time;
|
| - if (CollectProfile(&profile, &elapsed_profile_time))
|
| - profiles->push_back(profile);
|
| - else
|
| - return;
|
| + 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;
|
| + }
|
|
|
| - if (stop_event_.TimedWait(
|
| - std::max(params_.burst_interval - elapsed_profile_time,
|
| - TimeDelta())))
|
| + CallStackProfile profile;
|
| + if (!CollectProfile(&profile, &previous_elapsed_profile_time))
|
| return;
|
| + profiles->push_back(profile);
|
| }
|
| }
|
|
|
| @@ -199,14 +194,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)),
|
| @@ -224,19 +212,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() {
|
| @@ -245,14 +234,11 @@ void StackSamplingProfiler::Stop() {
|
| }
|
|
|
| // static
|
| -void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) {
|
| - PendingProfiles::GetInstance()->GetProfiles(profiles);
|
| +void StackSamplingProfiler::GetPendingProfiles(CallStackProfiles* profiles) {
|
| + PendingProfiles::GetInstance()->GetAndClearPendingProfiles(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) {
|
|
|