summaryrefslogtreecommitdiffstats
path: root/base/profiler
diff options
context:
space:
mode:
authorwittman <wittman@chromium.org>2015-04-07 19:20:35 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-08 02:21:04 +0000
commitae2a08ac68bcb4000d1ddf391dbf19aa285cc48f (patch)
tree4b16d638ad7c12e54f025d78d7c544a8c7a0b705 /base/profiler
parentc438c1843041746877c9dc83d9ce63a3c43bb6bb (diff)
downloadchromium_src-ae2a08ac68bcb4000d1ddf391dbf19aa285cc48f.zip
chromium_src-ae2a08ac68bcb4000d1ddf391dbf19aa285cc48f.tar.gz
chromium_src-ae2a08ac68bcb4000d1ddf391dbf19aa285cc48f.tar.bz2
Enable startup profiling by Win x64 stack sampling profiler
Collects stack samples at 10 Hz for 30 seconds at startup. Uploading of samples to UMA is controlled by a Finch experiment. This change moves to a callback-based mechanism for communicating completed profiles to the metrics provider to avoid profiles lingering in memory when reporting is disabled. BUG=464929 Review URL: https://codereview.chromium.org/1029653002 Cr-Commit-Position: refs/heads/master@{#324175}
Diffstat (limited to 'base/profiler')
-rw-r--r--base/profiler/stack_sampling_profiler.cc125
-rw-r--r--base/profiler/stack_sampling_profiler.h51
-rw-r--r--base/profiler/stack_sampling_profiler_unittest.cc184
3 files changed, 269 insertions, 91 deletions
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index 317400b..1c08234 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 ------------------------------
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
index bea266d..73dbec7 100644
--- a/base/profiler/stack_sampling_profiler.h
+++ b/base/profiler/stack_sampling_profiler.h
@@ -34,11 +34,12 @@ class NativeStackSampler;
// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
// params);
//
-// // To process the call stack profiles within Chrome rather than via UMA,
-// // set a custom completed callback:
+// // Or, to process the profiles within Chrome rather than via UMA, use a
+// // custom completed callback:
// base::StackStackSamplingProfiler::CompletedCallback
// thread_safe_callback = ...;
-// profiler.SetCustomCompletedCallback(thread_safe_callback);
+// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+// params, thread_safe_callback);
//
// profiler.Start();
// // ... work being done on the target thread here ...
@@ -49,13 +50,13 @@ class NativeStackSampler;
// altered as desired.
//
// When all call stack profiles are complete or the profiler is stopped, if the
-// custom completed callback was set it is called from the profiler thread with
-// the completed profiles. A profile is considered complete if all requested
-// samples were recorded for the profile (i.e. it was not stopped
-// prematurely). If no callback was set, the completed profiles are stored
-// internally and retrieved for UMA through GetPendingProfiles().
-// GetPendingProfiles() should never be called by other code; to retrieve
-// profiles for in-process processing, set a completed callback.
+// custom completed callback was set it is called from a thread created by the
+// profiler with the completed profiles. A profile is considered complete if all
+// requested samples were recorded for the profile (i.e. it was not stopped
+// prematurely). If no callback was set, the default completed callback will be
+// called with the profiles. It is expected that the the default completed
+// callback is set by the metrics system to allow profiles to be provided via
+// UMA.
//
// The results of the profiling are passed to the completed callback and consist
// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
@@ -164,8 +165,14 @@ class BASE_EXPORT StackSamplingProfiler {
// thread-safe callback implementation.
using CompletedCallback = Callback<void(const CallStackProfiles&)>;
+ // Creates a profiler that sends completed profiles to the default completed
+ // callback.
StackSamplingProfiler(PlatformThreadId thread_id,
const SamplingParams& params);
+ // Creates a profiler that sends completed profiles to |completed_callback|.
+ StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params,
+ CompletedCallback callback);
~StackSamplingProfiler();
// Initializes the profiler and starts sampling.
@@ -176,19 +183,14 @@ class BASE_EXPORT StackSamplingProfiler {
// specified in the SamplingParams are completed.
void Stop();
- // Moves all pending call stack profiles from internal storage to
- // |profiles|. This function is thread safe.
+ // Sets a callback to process profiles collected by profiler instances without
+ // a completed callback. Profiles are queued internally until a non-null
+ // callback is provided to this function,
//
- // ***This is intended for use only by UMA.*** Callers who want to process the
- // collected profiles should use SetCustomCompletedCallback.
- static void GetPendingProfiles(CallStackProfiles* call_stack_profiles);
-
- // By default, collected call stack profiles are stored internally and can be
- // retrieved by GetPendingProfiles. If a callback is provided via this
- // function, however, it is called with the collected profiles instead.
- void set_custom_completed_callback(CompletedCallback callback) {
- custom_completed_callback_ = callback;
- }
+ // The callback is typically called on a thread created by the profiler. If
+ // completed profiles are queued when set, however, it will also be called
+ // immediately on the calling thread.
+ static void SetDefaultCompletedCallback(CompletedCallback callback);
private:
// SamplingThread is a separate thread used to suspend and sample stacks from
@@ -226,7 +228,7 @@ class BASE_EXPORT StackSamplingProfiler {
// terminate before all the samples specified in |params_| are collected.
WaitableEvent stop_event_;
- CompletedCallback completed_callback_;
+ const CompletedCallback completed_callback_;
DISALLOW_COPY_AND_ASSIGN(SamplingThread);
};
@@ -237,8 +239,9 @@ class BASE_EXPORT StackSamplingProfiler {
const SamplingParams params_;
scoped_ptr<SamplingThread> sampling_thread_;
+ PlatformThreadHandle sampling_thread_handle_;
- CompletedCallback custom_completed_callback_;
+ const CompletedCallback completed_callback_;
DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
};
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index 5bfc2d4..e48c89b 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -14,10 +14,12 @@
namespace base {
+using SamplingParams = StackSamplingProfiler::SamplingParams;
using Frame = StackSamplingProfiler::Frame;
using Module = StackSamplingProfiler::Module;
using Sample = StackSamplingProfiler::Sample;
using CallStackProfile = StackSamplingProfiler::CallStackProfile;
+using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
namespace {
@@ -85,45 +87,99 @@ NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
ALLOW_UNUSED_LOCAL(x);
}
+// Called on the profiler thread when complete, to collect profiles.
+void SaveProfiles(CallStackProfiles* profiles,
+ const CallStackProfiles& pending_profiles) {
+ *profiles = pending_profiles;
+}
+
// Called on the profiler thread when complete. Collects profiles produced by
// the profiler, and signals an event to allow the main thread to know that that
// the profiler is done.
-void SaveProfilesAndSignalEvent(
- std::vector<CallStackProfile>* profiles,
- WaitableEvent* event,
- const std::vector<CallStackProfile>& pending_profiles) {
+void SaveProfilesAndSignalEvent(CallStackProfiles* profiles,
+ WaitableEvent* event,
+ const CallStackProfiles& pending_profiles) {
*profiles = pending_profiles;
event->Signal();
}
-// Captures call stack profiles as specified by |params| on the TargetThread,
-// and returns them in |profiles|. Waits up to |profiler_wait_time| for the
-// profiler to complete.
-void CaptureProfiles(const StackSamplingProfiler::SamplingParams& params,
- std::vector<CallStackProfile>* profiles,
- TimeDelta profiler_wait_time) {
+// Executes the function with the target thread running and executing within
+// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
+// and shutdown work before and afterward.
+template <class Function>
+void WithTargetThread(Function function) {
TargetThread target_thread;
PlatformThreadHandle target_thread_handle;
EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
target_thread.WaitForThreadStart();
- WaitableEvent sampling_thread_completed(true, false);
- profiles->clear();
- StackSamplingProfiler profiler(target_thread.id(), params);
- profiler.set_custom_completed_callback(
- Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
- Unretained(&sampling_thread_completed)));
- profiler.Start();
- sampling_thread_completed.TimedWait(profiler_wait_time);
- profiler.Stop();
- sampling_thread_completed.Wait();
+ function(target_thread.id());
target_thread.SignalThreadToFinish();
PlatformThread::Join(target_thread_handle);
}
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
+// complete.
+void CaptureProfilesWithObjectCallback(const SamplingParams& params,
+ CallStackProfiles* profiles,
+ TimeDelta profiler_wait_time) {
+ profiles->clear();
+
+ WithTargetThread([&params, profiles, profiler_wait_time](
+ PlatformThreadId target_thread_id) {
+ WaitableEvent sampling_thread_completed(true, false);
+ const StackSamplingProfiler::CompletedCallback callback =
+ Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+ Unretained(&sampling_thread_completed));
+ StackSamplingProfiler profiler(target_thread_id, params, callback);
+ profiler.Start();
+ sampling_thread_completed.TimedWait(profiler_wait_time);
+ profiler.Stop();
+ sampling_thread_completed.Wait();
+ });
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Uses the default callback rather than a per-object
+// callback.
+void CaptureProfilesWithDefaultCallback(const SamplingParams& params,
+ CallStackProfiles* profiles) {
+ profiles->clear();
+
+ WithTargetThread([&params, profiles](PlatformThreadId target_thread_id) {
+ WaitableEvent sampling_thread_completed(false, false);
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+ Unretained(&sampling_thread_completed)));
+
+ StackSamplingProfiler profiler(target_thread_id, params);
+ profiler.Start();
+ sampling_thread_completed.Wait();
+
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ StackSamplingProfiler::CompletedCallback());
+ });
+}
+
+// Runs the profiler with |params| on the TargetThread, with no default or
+// per-object callback.
+void RunProfilerWithNoCallback(const SamplingParams& params,
+ TimeDelta profiler_wait_time) {
+ WithTargetThread(
+ [&params, profiler_wait_time](PlatformThreadId target_thread_id) {
+ StackSamplingProfiler profiler(target_thread_id, params);
+ profiler.Start();
+ // Since we don't specify a callback, we don't have a synchronization
+ // mechanism with the sampling thread. Just sleep instead.
+ PlatformThread::Sleep(profiler_wait_time);
+ profiler.Stop();
+ });
+}
+
// If this executable was linked with /INCREMENTAL (the default for non-official
// debug and release builds on Windows), function addresses do not correspond to
// function code itself, but instead to instructions in the Incremental Link
@@ -195,12 +251,12 @@ TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
#define MAYBE_Basic DISABLED_Basic
#endif
TEST(StackSamplingProfilerTest, MAYBE_Basic) {
- StackSamplingProfiler::SamplingParams params;
+ SamplingParams params;
params.sampling_interval = TimeDelta::FromMilliseconds(0);
params.samples_per_burst = 1;
std::vector<CallStackProfile> profiles;
- CaptureProfiles(params, &profiles, AVeryLongTimeDelta());
+ CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
// Check that the profile and samples sizes are correct, and the module
// indices are in range.
@@ -244,14 +300,14 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) {
#define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
#endif
TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
- StackSamplingProfiler::SamplingParams params;
+ SamplingParams params;
params.burst_interval = params.sampling_interval =
TimeDelta::FromMilliseconds(0);
params.bursts = 2;
params.samples_per_burst = 3;
std::vector<CallStackProfile> profiles;
- CaptureProfiles(params, &profiles, AVeryLongTimeDelta());
+ CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
ASSERT_EQ(2u, profiles.size());
EXPECT_EQ(3u, profiles[0].samples.size());
@@ -266,11 +322,12 @@ TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
#define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
#endif
TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
- StackSamplingProfiler::SamplingParams params;
+ SamplingParams params;
params.initial_delay = TimeDelta::FromSeconds(60);
std::vector<CallStackProfile> profiles;
- CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(0));
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(0));
EXPECT_TRUE(profiles.empty());
}
@@ -283,14 +340,15 @@ TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
#define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
#endif
TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
- StackSamplingProfiler::SamplingParams params;
+ SamplingParams params;
params.sampling_interval = TimeDelta::FromMilliseconds(0);
params.burst_interval = TimeDelta::FromSeconds(60);
params.bursts = 2;
params.samples_per_burst = 1;
std::vector<CallStackProfile> profiles;
- CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50));
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(50));
ASSERT_EQ(1u, profiles.size());
EXPECT_EQ(1u, profiles[0].samples.size());
@@ -304,14 +362,80 @@ TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
DISABLED_StopDuringInterSampleInterval
#endif
TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) {
- StackSamplingProfiler::SamplingParams params;
+ SamplingParams params;
params.sampling_interval = TimeDelta::FromSeconds(60);
params.samples_per_burst = 2;
std::vector<CallStackProfile> profiles;
- CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50));
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(50));
EXPECT_TRUE(profiles.empty());
}
+// Checks that profiles are captured via the default completed callback.
+#if defined(_WIN64)
+#define MAYBE_DefaultCallback DefaultCallback
+#else
+#define MAYBE_DefaultCallback DISABLED_DefaultCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DefaultCallback) {
+ SamplingParams params;
+ params.samples_per_burst = 1;
+
+ CallStackProfiles profiles;
+ CaptureProfilesWithDefaultCallback(params, &profiles);
+
+ EXPECT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that profiles are queued until a default callback is set, then
+// delivered.
+#if defined(_WIN64)
+#define MAYBE_ProfilesQueuedWithNoCallback ProfilesQueuedWithNoCallback
+#else
+#define MAYBE_ProfilesQueuedWithNoCallback DISABLED_ProfilesQueuedWithNoCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_ProfilesQueuedWithNoCallback) {
+ SamplingParams params;
+ params.samples_per_burst = 1;
+
+ RunProfilerWithNoCallback(params, TimeDelta::FromMilliseconds(50));
+
+ CallStackProfiles profiles;
+ // This should immediately call SaveProfiles on this thread.
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ Bind(&SaveProfiles, Unretained(&profiles)));
+ EXPECT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ StackSamplingProfiler::CompletedCallback());
+}
+
+// Checks that we can destroy the profiler while profiling.
+#if defined(_WIN64)
+#define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
+#else
+#define MAYBE_DestroyProfilerWhileProfiling \
+ DISABLED_DestroyProfilerWhileProfiling
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DestroyProfilerWhileProfiling) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(10);
+
+ CallStackProfiles profiles;
+ WithTargetThread([&params, &profiles](PlatformThreadId target_thread_id) {
+ scoped_ptr<StackSamplingProfiler> profiler;
+ profiler.reset(new StackSamplingProfiler(
+ target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles))));
+ profiler->Start();
+ profiler.reset();
+
+ // Wait longer than a sample interval to catch any use-after-free actions by
+ // the profiler thread.
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+ });
+}
+
} // namespace base