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

Unified Diff: base/profiler/stack_sampling_profiler.cc

Issue 1124763003: Update from https://crrev.com/327068 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: update nacl, buildtools, fix display_change_notifier_unittest Created 5 years, 7 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..9da662859fd9535cb4037d1d1302401b2566f5b3 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -9,114 +9,144 @@
#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 {
+// DefaultProfileProcessor ----------------------------------------------------
+
namespace {
-// Thread-safe singleton class that stores collected 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();
- ~PendingProfiles();
+ using CompletedCallback = StackSamplingProfiler::CompletedCallback;
+
+ ~DefaultProfileProcessor();
+
+ static DefaultProfileProcessor* GetInstance();
- static PendingProfiles* 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);
- // 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);
+ // 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(
+ StackSamplingProfiler::CallStackProfiles* profiles);
+
+ // Gets the current completed callback, with proper locking.
+ CompletedCallback GetCompletedCallback() const;
+
+ mutable Lock callback_lock_;
+ CompletedCallback default_completed_callback_;
+
Lock profiles_lock_;
- std::vector<StackSamplingProfiler::Profile> 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::PutProfiles(
- const std::vector<StackSamplingProfiler::Profile>& 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 PendingProfiles::GetProfiles(
- std::vector<StackSamplingProfiler::Profile>* profiles) {
- profiles->clear();
+void DefaultProfileProcessor::ProcessProfiles(
+ const StackSamplingProfiler::CallStackProfiles& profiles) {
+ CompletedCallback callback = GetCompletedCallback();
- AutoLock scoped_lock(profiles_lock_);
- profiles_.swap(*profiles);
+ // 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());
+ }
}
-} // namespace
-StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+DefaultProfileProcessor::DefaultProfileProcessor() {}
-StackSamplingProfiler::Module::~Module() {}
+void DefaultProfileProcessor::GetAndClearPendingProfiles(
+ StackSamplingProfiler::CallStackProfiles* profiles) {
+ profiles->clear();
-StackSamplingProfiler::Frame::Frame()
- : instruction_pointer(nullptr),
- module_index(-1) {}
+ AutoLock scoped_lock(profiles_lock_);
+ profiles_.swap(*profiles);
+}
-StackSamplingProfiler::Frame::~Frame() {}
+DefaultProfileProcessor::CompletedCallback
+DefaultProfileProcessor::GetCompletedCallback() const {
+ AutoLock scoped_lock(callback_lock_);
+ return default_completed_callback_;
+}
-StackSamplingProfiler::Profile::Profile() : preserve_sample_ordering(false) {}
+} // namespace
-StackSamplingProfiler::Profile::~Profile() {}
+// StackSamplingProfiler::Module ----------------------------------------------
-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;
+StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+StackSamplingProfiler::Module::Module(const void* base_address,
+ const std::string& id,
+ const FilePath& filename)
+ : base_address(base_address), id(id), filename(filename) {}
- // Implementation of PlatformThread::Delegate:
- void ThreadMain() override;
+StackSamplingProfiler::Module::~Module() {}
- 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), user_data(0) {}
- 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 +158,79 @@ 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(&current_profile);
+ CallStackProfile current_profile;
+ native_sampler_->ProfileRecordingStarting(&current_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(&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;
+ current_profile.preserve_sample_ordering = params_.preserve_sample_ordering;
+ current_profile.user_data = params_.user_data;
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);
}
}
@@ -190,14 +238,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)),
@@ -205,29 +246,40 @@ StackSamplingProfiler::SamplingParams::SamplingParams()
burst_interval(TimeDelta::FromMilliseconds(10000)),
samples_per_burst(300),
sampling_interval(TimeDelta::FromMilliseconds(100)),
- preserve_sample_ordering(false) {
+ preserve_sample_ordering(false),
+ user_data(0) {
}
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() {
- native_sampler_ = NativeStackSampler::Create(thread_id_);
- if (!native_sampler_)
+ scoped_ptr<NativeStackSampler> native_sampler =
+ NativeStackSampler::Create(thread_id_);
+ 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::PutProfiles,
- Unretained(PendingProfiles::GetInstance())) :
- custom_completed_callback_)));
- if (!PlatformThread::CreateNonJoinable(0, sampling_thread_.get()))
- LOG(ERROR) << "failed to create thread";
+ new SamplingThread(native_sampler.Pass(), params_, callback));
+ if (!PlatformThread::Create(0, sampling_thread_.get(),
+ &sampling_thread_handle_))
+ sampling_thread_.reset();
}
void StackSamplingProfiler::Stop() {
@@ -236,14 +288,12 @@ void StackSamplingProfiler::Stop() {
}
// static
-void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) {
- PendingProfiles::GetInstance()->GetProfiles(profiles);
+void StackSamplingProfiler::SetDefaultCompletedCallback(
+ CompletedCallback callback) {
+ DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
}
-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