Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3396)

Unified Diff: base/profiler/stack_sampling_profiler.cc

Issue 1030923002: StackSamplingProfiler clean up (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: address comments Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..710212b2c6f8e5b8603546f78a4f0959b1338474 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -9,33 +9,39 @@
#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 is thread safe.
+ void AppendProfiles(
+ const std::vector<StackSamplingProfiler::CallStackProfile>& profiles);
+
+ // Copies the pending profiles from |profiles_| into |profiles|, and clears
+ // |profiles_|. This function is thread safe.
Peter Kasting 2015/03/31 01:51:25 Nit: Again, I think "This function may be called o
Mike Wittman 2015/03/31 19:29:41 Done.
+ void GetAndClearPendingProfiles(
+ std::vector<StackSamplingProfiler::CallStackProfile>* profiles);
private:
+ friend struct DefaultSingletonTraits<PendingProfiles>;
+ PendingProfiles();
Peter Kasting 2015/03/31 01:51:25 Nit: I'd put a blank line above this
Mike Wittman 2015/03/31 19:29:41 Done.
+
Lock profiles_lock_;
- std::vector<StackSamplingProfiler::Profile> profiles_;
+ std::vector<StackSamplingProfiler::CallStackProfile> profiles_;
DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
};
@@ -49,74 +55,50 @@ 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() {}
-StackSamplingProfiler::Frame::Frame()
- : instruction_pointer(nullptr),
- module_index(-1) {}
-
-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();
+// StackSamplingProfiler::Frame -----------------------------------------------
- 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);
+StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
+ size_t module_index)
+ : instruction_pointer(instruction_pointer),
+ module_index(module_index) {}
- scoped_ptr<NativeStackSampler> native_sampler_;
+StackSamplingProfiler::Frame::~Frame() {}
- 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),
@@ -128,61 +110,77 @@ StackSamplingProfiler::SamplingThread::~SamplingThread() {}
void StackSamplingProfiler::SamplingThread::ThreadMain() {
PlatformThread::SetName("Chrome_SamplingProfilerThread");
- std::vector<Profile> profiles;
+ std::vector<CallStackProfile> 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;
+ CallStackProfile current_profile;
native_sampler_->ProfileRecordingStarting(&current_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(&current_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(&current_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) {
+ std::vector<CallStackProfile>* 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);
}
}
@@ -190,14 +188,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 +206,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() {
@@ -236,14 +228,12 @@ void StackSamplingProfiler::Stop() {
}
// static
-void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) {
- PendingProfiles::GetInstance()->GetProfiles(profiles);
+void StackSamplingProfiler::GetPendingProfiles(
+ std::vector<CallStackProfile>* 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) {

Powered by Google App Engine
This is Rietveld 408576698