1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/compiler_specific.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/path_service.h"
10 #include "base/profiler/stack_sampling_profiler.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/time/time.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 // STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
19 // below for supported platforms (currently Win x64).
21 #define STACK_SAMPLING_PROFILER_SUPPORTED 1
26 using SamplingParams
= StackSamplingProfiler::SamplingParams
;
27 using Frame
= StackSamplingProfiler::Frame
;
28 using Module
= StackSamplingProfiler::Module
;
29 using Sample
= StackSamplingProfiler::Sample
;
30 using CallStackProfile
= StackSamplingProfiler::CallStackProfile
;
31 using CallStackProfiles
= StackSamplingProfiler::CallStackProfiles
;
35 // A thread to target for profiling, whose stack is guaranteed to contain
36 // SignalAndWaitUntilSignaled() when coordinated with the main thread.
37 class TargetThread
: public PlatformThread::Delegate
{
41 // PlatformThread::Delegate:
42 void ThreadMain() override
;
44 // Waits for the thread to have started and be executing in
45 // SignalAndWaitUntilSignaled().
46 void WaitForThreadStart();
48 // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
50 void SignalThreadToFinish();
52 // This function is guaranteed to be executing between calls to
53 // WaitForThreadStart() and SignalThreadToFinish(). This function is static so
54 // that we can get a straightforward address for it in one of the tests below,
55 // rather than dealing with the complexity of a member function pointer
57 static void SignalAndWaitUntilSignaled(WaitableEvent
* thread_started_event
,
58 WaitableEvent
* finish_event
);
60 PlatformThreadId
id() const { return id_
; }
63 WaitableEvent thread_started_event_
;
64 WaitableEvent finish_event_
;
67 DISALLOW_COPY_AND_ASSIGN(TargetThread
);
70 TargetThread::TargetThread()
71 : thread_started_event_(false, false), finish_event_(false, false),
74 void TargetThread::ThreadMain() {
75 id_
= PlatformThread::CurrentId();
76 SignalAndWaitUntilSignaled(&thread_started_event_
, &finish_event_
);
79 void TargetThread::WaitForThreadStart() {
80 thread_started_event_
.Wait();
83 void TargetThread::SignalThreadToFinish() {
84 finish_event_
.Signal();
88 // Disable inlining for this function so that it gets its own stack frame.
89 NOINLINE
void TargetThread::SignalAndWaitUntilSignaled(
90 WaitableEvent
* thread_started_event
,
91 WaitableEvent
* finish_event
) {
92 thread_started_event
->Signal();
95 x
= 0; // Prevent tail call to WaitableEvent::Wait().
96 ALLOW_UNUSED_LOCAL(x
);
99 // Called on the profiler thread when complete, to collect profiles.
100 void SaveProfiles(CallStackProfiles
* profiles
,
101 const CallStackProfiles
& pending_profiles
) {
102 *profiles
= pending_profiles
;
105 // Called on the profiler thread when complete. Collects profiles produced by
106 // the profiler, and signals an event to allow the main thread to know that that
107 // the profiler is done.
108 void SaveProfilesAndSignalEvent(CallStackProfiles
* profiles
,
109 WaitableEvent
* event
,
110 const CallStackProfiles
& pending_profiles
) {
111 *profiles
= pending_profiles
;
115 // Executes the function with the target thread running and executing within
116 // SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
117 // and shutdown work before and afterward.
118 template <class Function
>
119 void WithTargetThread(Function function
) {
120 TargetThread target_thread
;
121 PlatformThreadHandle target_thread_handle
;
122 EXPECT_TRUE(PlatformThread::Create(0, &target_thread
, &target_thread_handle
));
124 target_thread
.WaitForThreadStart();
126 function(target_thread
.id());
128 target_thread
.SignalThreadToFinish();
130 PlatformThread::Join(target_thread_handle
);
133 // Captures profiles as specified by |params| on the TargetThread, and returns
134 // them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
136 void CaptureProfiles(const SamplingParams
& params
, TimeDelta profiler_wait_time
,
137 CallStackProfiles
* profiles
) {
140 WithTargetThread([¶ms
, profiles
, profiler_wait_time
](
141 PlatformThreadId target_thread_id
) {
142 WaitableEvent
sampling_thread_completed(true, false);
143 const StackSamplingProfiler::CompletedCallback callback
=
144 Bind(&SaveProfilesAndSignalEvent
, Unretained(profiles
),
145 Unretained(&sampling_thread_completed
));
146 StackSamplingProfiler
profiler(target_thread_id
, params
, callback
);
148 sampling_thread_completed
.TimedWait(profiler_wait_time
);
150 sampling_thread_completed
.Wait();
154 // If this executable was linked with /INCREMENTAL (the default for non-official
155 // debug and release builds on Windows), function addresses do not correspond to
156 // function code itself, but instead to instructions in the Incremental Link
157 // Table that jump to the functions. Checks for a jump instruction and if
158 // present does a little decompilation to find the function's actual starting
160 const void* MaybeFixupFunctionAddressForILT(const void* function_address
) {
162 const unsigned char* opcode
=
163 reinterpret_cast<const unsigned char*>(function_address
);
164 if (*opcode
== 0xe9) {
165 // This is a relative jump instruction. Assume we're in the ILT and compute
166 // the function start address from the instruction offset.
167 const int32
* offset
= reinterpret_cast<const int32
*>(opcode
+ 1);
168 const unsigned char* next_instruction
=
169 reinterpret_cast<const unsigned char*>(offset
+ 1);
170 return next_instruction
+ *offset
;
173 return function_address
;
176 // Searches through the frames in |sample|, returning an iterator to the first
177 // frame that has an instruction pointer between |function_address| and
178 // |function_address| + |size|. Returns sample.end() if no such frames are
180 Sample::const_iterator
FindFirstFrameWithinFunction(
181 const Sample
& sample
,
182 const void* function_address
,
184 function_address
= MaybeFixupFunctionAddressForILT(function_address
);
185 for (auto it
= sample
.begin(); it
!= sample
.end(); ++it
) {
186 if ((it
->instruction_pointer
>= function_address
) &&
187 (it
->instruction_pointer
<
188 (static_cast<const unsigned char*>(function_address
) + function_size
)))
194 // Formats a sample into a string that can be output for test diagnostics.
195 std::string
FormatSampleForDiagnosticOutput(
196 const Sample
& sample
,
197 const std::vector
<Module
>& modules
) {
199 for (const Frame
& frame
: sample
) {
200 output
+= StringPrintf(
201 "0x%p %s\n", frame
.instruction_pointer
,
202 modules
[frame
.module_index
].filename
.AsUTF8Unsafe().c_str());
207 // Returns a duration that is longer than the test timeout. We would use
208 // TimeDelta::Max() but https://crbug.com/465948.
209 TimeDelta
AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
213 // Checks that the basic expected information is present in a sampled call stack
215 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
216 #define MAYBE_Basic Basic
218 #define MAYBE_Basic DISABLED_Basic
220 TEST(StackSamplingProfilerTest
, MAYBE_Basic
) {
221 SamplingParams params
;
222 params
.sampling_interval
= TimeDelta::FromMilliseconds(0);
223 params
.samples_per_burst
= 1;
225 std::vector
<CallStackProfile
> profiles
;
226 CaptureProfiles(params
, AVeryLongTimeDelta(), &profiles
);
228 // Check that the profile and samples sizes are correct, and the module
229 // indices are in range.
230 ASSERT_EQ(1u, profiles
.size());
231 const CallStackProfile
& profile
= profiles
[0];
232 ASSERT_EQ(1u, profile
.samples
.size());
233 EXPECT_EQ(params
.sampling_interval
, profile
.sampling_period
);
234 const Sample
& sample
= profile
.samples
[0];
235 for (const auto& frame
: sample
) {
236 ASSERT_GE(frame
.module_index
, 0u);
237 ASSERT_LT(frame
.module_index
, profile
.modules
.size());
240 // Check that the stack contains a frame for
241 // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
242 // executable's module.
244 // Since we don't have a good way to know the function size, use 100 bytes as
245 // a reasonable window to locate the instruction pointer.
246 Sample::const_iterator loc
= FindFirstFrameWithinFunction(
248 reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled
),
250 ASSERT_TRUE(loc
!= sample
.end())
252 << MaybeFixupFunctionAddressForILT(
253 reinterpret_cast<const void*>(
254 &TargetThread::SignalAndWaitUntilSignaled
))
255 << " was not found in stack:\n"
256 << FormatSampleForDiagnosticOutput(sample
, profile
.modules
);
257 FilePath executable_path
;
258 EXPECT_TRUE(PathService::Get(FILE_EXE
, &executable_path
));
259 EXPECT_EQ(executable_path
, profile
.modules
[loc
->module_index
].filename
);
262 // Checks that the fire-and-forget interface works.
263 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
264 #define MAYBE_StartAndRunAsync StartAndRunAsync
266 #define MAYBE_StartAndRunAsync DISABLED_StartAndRunAsync
268 TEST(StackSamplingProfilerTest
, MAYBE_StartAndRunAsync
) {
269 // StartAndRunAsync requires the caller to have a message loop.
270 MessageLoop message_loop
;
272 SamplingParams params
;
273 params
.samples_per_burst
= 1;
275 CallStackProfiles profiles
;
276 WithTargetThread([¶ms
, &profiles
](PlatformThreadId target_thread_id
) {
277 WaitableEvent
sampling_thread_completed(false, false);
278 const StackSamplingProfiler::CompletedCallback callback
=
279 Bind(&SaveProfilesAndSignalEvent
, Unretained(&profiles
),
280 Unretained(&sampling_thread_completed
));
281 StackSamplingProfiler::StartAndRunAsync(target_thread_id
, params
, callback
);
282 RunLoop().RunUntilIdle();
283 sampling_thread_completed
.Wait();
286 ASSERT_EQ(1u, profiles
.size());
289 // Checks that the expected number of profiles and samples are present in the
290 // call stack profiles produced.
291 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
292 #define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
294 #define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
296 TEST(StackSamplingProfilerTest
, MAYBE_MultipleProfilesAndSamples
) {
297 SamplingParams params
;
298 params
.burst_interval
= params
.sampling_interval
=
299 TimeDelta::FromMilliseconds(0);
301 params
.samples_per_burst
= 3;
303 std::vector
<CallStackProfile
> profiles
;
304 CaptureProfiles(params
, AVeryLongTimeDelta(), &profiles
);
306 ASSERT_EQ(2u, profiles
.size());
307 EXPECT_EQ(3u, profiles
[0].samples
.size());
308 EXPECT_EQ(3u, profiles
[1].samples
.size());
311 // Checks that no call stack profiles are captured if the profiling is stopped
312 // during the initial delay.
313 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
314 #define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
316 #define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
318 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInitialDelay
) {
319 SamplingParams params
;
320 params
.initial_delay
= TimeDelta::FromSeconds(60);
322 std::vector
<CallStackProfile
> profiles
;
323 CaptureProfiles(params
, TimeDelta::FromMilliseconds(0), &profiles
);
325 EXPECT_TRUE(profiles
.empty());
328 // Checks that the single completed call stack profile is captured if the
329 // profiling is stopped between bursts.
330 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
331 #define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
333 #define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
335 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInterBurstInterval
) {
336 SamplingParams params
;
337 params
.sampling_interval
= TimeDelta::FromMilliseconds(0);
338 params
.burst_interval
= TimeDelta::FromSeconds(60);
340 params
.samples_per_burst
= 1;
342 std::vector
<CallStackProfile
> profiles
;
343 CaptureProfiles(params
, TimeDelta::FromMilliseconds(50), &profiles
);
345 ASSERT_EQ(1u, profiles
.size());
346 EXPECT_EQ(1u, profiles
[0].samples
.size());
349 // Checks that only completed call stack profiles are captured.
350 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
351 #define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
353 #define MAYBE_StopDuringInterSampleInterval \
354 DISABLED_StopDuringInterSampleInterval
356 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInterSampleInterval
) {
357 SamplingParams params
;
358 params
.sampling_interval
= TimeDelta::FromSeconds(60);
359 params
.samples_per_burst
= 2;
361 std::vector
<CallStackProfile
> profiles
;
362 CaptureProfiles(params
, TimeDelta::FromMilliseconds(50), &profiles
);
364 EXPECT_TRUE(profiles
.empty());
367 // Checks that we can destroy the profiler while profiling.
368 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
369 #define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
371 #define MAYBE_DestroyProfilerWhileProfiling \
372 DISABLED_DestroyProfilerWhileProfiling
374 TEST(StackSamplingProfilerTest
, MAYBE_DestroyProfilerWhileProfiling
) {
375 SamplingParams params
;
376 params
.sampling_interval
= TimeDelta::FromMilliseconds(10);
378 CallStackProfiles profiles
;
379 WithTargetThread([¶ms
, &profiles
](PlatformThreadId target_thread_id
) {
380 scoped_ptr
<StackSamplingProfiler
> profiler
;
381 profiler
.reset(new StackSamplingProfiler(
382 target_thread_id
, params
, Bind(&SaveProfiles
, Unretained(&profiles
))));
386 // Wait longer than a sample interval to catch any use-after-free actions by
387 // the profiler thread.
388 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
392 // Checks that the same profiler may be run multiple times.
393 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
394 #define MAYBE_CanRunMultipleTimes CanRunMultipleTimes
396 #define MAYBE_CanRunMultipleTimes DISABLED_CanRunMultipleTimes
398 TEST(StackSamplingProfilerTest
, MAYBE_CanRunMultipleTimes
) {
399 SamplingParams params
;
400 params
.sampling_interval
= TimeDelta::FromMilliseconds(0);
401 params
.samples_per_burst
= 1;
403 std::vector
<CallStackProfile
> profiles
;
404 CaptureProfiles(params
, AVeryLongTimeDelta(), &profiles
);
405 ASSERT_EQ(1u, profiles
.size());
408 CaptureProfiles(params
, AVeryLongTimeDelta(), &profiles
);
409 ASSERT_EQ(1u, profiles
.size());
412 // Checks that requests to start profiling while another profile is taking place
414 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
415 #define MAYBE_ConcurrentProfiling ConcurrentProfiling
417 #define MAYBE_ConcurrentProfiling DISABLED_ConcurrentProfiling
419 TEST(StackSamplingProfilerTest
, MAYBE_ConcurrentProfiling
) {
420 WithTargetThread([](PlatformThreadId target_thread_id
) {
421 SamplingParams params
[2];
422 params
[0].initial_delay
= TimeDelta::FromMilliseconds(10);
423 params
[0].sampling_interval
= TimeDelta::FromMilliseconds(0);
424 params
[0].samples_per_burst
= 1;
426 params
[1].sampling_interval
= TimeDelta::FromMilliseconds(0);
427 params
[1].samples_per_burst
= 1;
429 CallStackProfiles profiles
[2];
430 ScopedVector
<WaitableEvent
> sampling_completed
;
431 ScopedVector
<StackSamplingProfiler
> profiler
;
432 for (int i
= 0; i
< 2; ++i
) {
433 sampling_completed
.push_back(new WaitableEvent(false, false));
434 const StackSamplingProfiler::CompletedCallback callback
=
435 Bind(&SaveProfilesAndSignalEvent
, Unretained(&profiles
[i
]),
436 Unretained(sampling_completed
[i
]));
438 new StackSamplingProfiler(target_thread_id
, params
[i
], callback
));
441 profiler
[0]->Start();
442 profiler
[1]->Start();
444 // Wait for the first profiler to finish.
445 sampling_completed
[0]->Wait();
446 EXPECT_EQ(1u, profiles
[0].size());
448 // Give the second profiler a chance to run and observe that it hasn't.
450 sampling_completed
[1]->TimedWait(TimeDelta::FromMilliseconds(25)));
452 // Start the second profiler again and it should run.
453 profiler
[1]->Start();
454 sampling_completed
[1]->Wait();
455 EXPECT_EQ(1u, profiles
[1].size());