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/path_service.h"
8 #include "base/profiler/stack_sampling_profiler.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/time/time.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 using Frame
= StackSamplingProfiler::Frame
;
18 using Module
= StackSamplingProfiler::Module
;
19 using Sample
= StackSamplingProfiler::Sample
;
20 using CallStackProfile
= StackSamplingProfiler::CallStackProfile
;
24 // A thread to target for profiling, whose stack is guaranteed to contain
25 // SignalAndWaitUntilSignaled() when coordinated with the main thread.
26 class TargetThread
: public PlatformThread::Delegate
{
30 // PlatformThread::Delegate:
31 void ThreadMain() override
;
33 // Waits for the thread to have started and be executing in
34 // SignalAndWaitUntilSignaled().
35 void WaitForThreadStart();
37 // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
39 void SignalThreadToFinish();
41 // This function is guaranteed to be executing between calls to
42 // WaitForThreadStart() and SignalThreadToFinish(). This function is static so
43 // that we can get a straightforward address for it in one of the tests below,
44 // rather than dealing with the complexity of a member function pointer
46 static void SignalAndWaitUntilSignaled(WaitableEvent
* thread_started_event
,
47 WaitableEvent
* finish_event
);
49 PlatformThreadId
id() const { return id_
; }
52 WaitableEvent thread_started_event_
;
53 WaitableEvent finish_event_
;
56 DISALLOW_COPY_AND_ASSIGN(TargetThread
);
59 TargetThread::TargetThread()
60 : thread_started_event_(false, false), finish_event_(false, false),
63 void TargetThread::ThreadMain() {
64 id_
= PlatformThread::CurrentId();
65 SignalAndWaitUntilSignaled(&thread_started_event_
, &finish_event_
);
68 void TargetThread::WaitForThreadStart() {
69 thread_started_event_
.Wait();
72 void TargetThread::SignalThreadToFinish() {
73 finish_event_
.Signal();
77 // Disable inlining for this function so that it gets its own stack frame.
78 NOINLINE
void TargetThread::SignalAndWaitUntilSignaled(
79 WaitableEvent
* thread_started_event
,
80 WaitableEvent
* finish_event
) {
81 thread_started_event
->Signal();
84 x
= 0; // Prevent tail call to WaitableEvent::Wait().
85 ALLOW_UNUSED_LOCAL(x
);
88 // Called on the profiler thread when complete. Collects profiles produced by
89 // the profiler, and signals an event to allow the main thread to know that that
90 // the profiler is done.
91 void SaveProfilesAndSignalEvent(
92 std::vector
<CallStackProfile
>* profiles
,
94 const std::vector
<CallStackProfile
>& pending_profiles
) {
95 *profiles
= pending_profiles
;
99 // Captures call stack profiles as specified by |params| on the TargetThread,
100 // and returns them in |profiles|. Waits up to |profiler_wait_time| for the
101 // profiler to complete.
102 void CaptureProfiles(const StackSamplingProfiler::SamplingParams
& params
,
103 std::vector
<CallStackProfile
>* profiles
,
104 TimeDelta profiler_wait_time
) {
105 TargetThread target_thread
;
106 PlatformThreadHandle target_thread_handle
;
107 EXPECT_TRUE(PlatformThread::Create(0, &target_thread
, &target_thread_handle
));
109 target_thread
.WaitForThreadStart();
111 WaitableEvent
sampling_thread_completed(true, false);
113 StackSamplingProfiler
profiler(target_thread
.id(), params
);
114 profiler
.set_custom_completed_callback(
115 Bind(&SaveProfilesAndSignalEvent
, Unretained(profiles
),
116 Unretained(&sampling_thread_completed
)));
118 sampling_thread_completed
.TimedWait(profiler_wait_time
);
120 sampling_thread_completed
.Wait();
122 target_thread
.SignalThreadToFinish();
124 PlatformThread::Join(target_thread_handle
);
127 // If this executable was linked with /INCREMENTAL (the default for non-official
128 // debug and release builds on Windows), function addresses do not correspond to
129 // function code itself, but instead to instructions in the Incremental Link
130 // Table that jump to the functions. Checks for a jump instruction and if
131 // present does a little decompilation to find the function's actual starting
133 const void* MaybeFixupFunctionAddressForILT(const void* function_address
) {
135 const unsigned char* opcode
=
136 reinterpret_cast<const unsigned char*>(function_address
);
137 if (*opcode
== 0xe9) {
138 // This is a relative jump instruction. Assume we're in the ILT and compute
139 // the function start address from the instruction offset.
140 const int32
* offset
= reinterpret_cast<const int32
*>(opcode
+ 1);
141 const unsigned char* next_instruction
=
142 reinterpret_cast<const unsigned char*>(offset
+ 1);
143 return next_instruction
+ *offset
;
146 return function_address
;
149 // Searches through the frames in |sample|, returning an iterator to the first
150 // frame that has an instruction pointer between |function_address| and
151 // |function_address| + |size|. Returns sample.end() if no such frames are
153 Sample::const_iterator
FindFirstFrameWithinFunction(
154 const Sample
& sample
,
155 const void* function_address
,
157 function_address
= MaybeFixupFunctionAddressForILT(function_address
);
158 for (auto it
= sample
.begin(); it
!= sample
.end(); ++it
) {
159 if ((it
->instruction_pointer
>= function_address
) &&
160 (it
->instruction_pointer
<
161 (static_cast<const unsigned char*>(function_address
) + function_size
)))
167 // Formats a sample into a string that can be output for test diagnostics.
168 std::string
FormatSampleForDiagnosticOutput(
169 const Sample
& sample
,
170 const std::vector
<Module
>& modules
) {
172 for (const Frame
& frame
: sample
) {
173 output
+= StringPrintf(
174 "0x%p %s\n", frame
.instruction_pointer
,
175 modules
[frame
.module_index
].filename
.AsUTF8Unsafe().c_str());
180 // Returns a duration that is longer than the test timeout. We would use
181 // TimeDelta::Max() but https://crbug.com/465948.
182 TimeDelta
AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
187 // The tests below are enabled for Win x64 only, pending implementation of the
188 // tested functionality on other platforms/architectures.
190 // Checks that the basic expected information is present in a sampled call stack
193 #define MAYBE_Basic Basic
195 #define MAYBE_Basic DISABLED_Basic
197 TEST(StackSamplingProfilerTest
, MAYBE_Basic
) {
198 StackSamplingProfiler::SamplingParams params
;
199 params
.sampling_interval
= TimeDelta::FromMilliseconds(0);
200 params
.samples_per_burst
= 1;
202 std::vector
<CallStackProfile
> profiles
;
203 CaptureProfiles(params
, &profiles
, AVeryLongTimeDelta());
205 // Check that the profile and samples sizes are correct, and the module
206 // indices are in range.
207 ASSERT_EQ(1u, profiles
.size());
208 const CallStackProfile
& profile
= profiles
[0];
209 ASSERT_EQ(1u, profile
.samples
.size());
210 EXPECT_EQ(params
.sampling_interval
, profile
.sampling_period
);
211 const Sample
& sample
= profile
.samples
[0];
212 for (const auto& frame
: sample
) {
213 ASSERT_GE(frame
.module_index
, 0u);
214 ASSERT_LT(frame
.module_index
, profile
.modules
.size());
217 // Check that the stack contains a frame for
218 // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
219 // executable's module.
221 // Since we don't have a good way to know the function size, use 100 bytes as
222 // a reasonable window to locate the instruction pointer.
223 Sample::const_iterator loc
= FindFirstFrameWithinFunction(
225 reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled
),
227 ASSERT_TRUE(loc
!= sample
.end())
229 << MaybeFixupFunctionAddressForILT(
230 reinterpret_cast<const void*>(
231 &TargetThread::SignalAndWaitUntilSignaled
))
232 << " was not found in stack:\n"
233 << FormatSampleForDiagnosticOutput(sample
, profile
.modules
);
234 FilePath executable_path
;
235 EXPECT_TRUE(PathService::Get(FILE_EXE
, &executable_path
));
236 EXPECT_EQ(executable_path
, profile
.modules
[loc
->module_index
].filename
);
239 // Checks that the expected number of profiles and samples are present in the
240 // call stack profiles produced.
242 #define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
244 #define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
246 TEST(StackSamplingProfilerTest
, MAYBE_MultipleProfilesAndSamples
) {
247 StackSamplingProfiler::SamplingParams params
;
248 params
.burst_interval
= params
.sampling_interval
=
249 TimeDelta::FromMilliseconds(0);
251 params
.samples_per_burst
= 3;
253 std::vector
<CallStackProfile
> profiles
;
254 CaptureProfiles(params
, &profiles
, AVeryLongTimeDelta());
256 ASSERT_EQ(2u, profiles
.size());
257 EXPECT_EQ(3u, profiles
[0].samples
.size());
258 EXPECT_EQ(3u, profiles
[1].samples
.size());
261 // Checks that no call stack profiles are captured if the profiling is stopped
262 // during the initial delay.
264 #define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
266 #define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
268 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInitialDelay
) {
269 StackSamplingProfiler::SamplingParams params
;
270 params
.initial_delay
= TimeDelta::FromSeconds(60);
272 std::vector
<CallStackProfile
> profiles
;
273 CaptureProfiles(params
, &profiles
, TimeDelta::FromMilliseconds(0));
275 EXPECT_TRUE(profiles
.empty());
278 // Checks that the single completed call stack profile is captured if the
279 // profiling is stopped between bursts.
281 #define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
283 #define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
285 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInterBurstInterval
) {
286 StackSamplingProfiler::SamplingParams params
;
287 params
.sampling_interval
= TimeDelta::FromMilliseconds(0);
288 params
.burst_interval
= TimeDelta::FromSeconds(60);
290 params
.samples_per_burst
= 1;
292 std::vector
<CallStackProfile
> profiles
;
293 CaptureProfiles(params
, &profiles
, TimeDelta::FromMilliseconds(50));
295 ASSERT_EQ(1u, profiles
.size());
296 EXPECT_EQ(1u, profiles
[0].samples
.size());
299 // Checks that only completed call stack profiles are captured.
301 #define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
303 #define MAYBE_StopDuringInterSampleInterval \
304 DISABLED_StopDuringInterSampleInterval
306 TEST(StackSamplingProfilerTest
, MAYBE_StopDuringInterSampleInterval
) {
307 StackSamplingProfiler::SamplingParams params
;
308 params
.sampling_interval
= TimeDelta::FromSeconds(60);
309 params
.samples_per_burst
= 2;
311 std::vector
<CallStackProfile
> profiles
;
312 CaptureProfiles(params
, &profiles
, TimeDelta::FromMilliseconds(50));
314 EXPECT_TRUE(profiles
.empty());