OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/compiler_specific.h" | 6 #include "base/compiler_specific.h" |
7 #include "base/path_service.h" | 7 #include "base/path_service.h" |
8 #include "base/profiler/stack_sampling_profiler.h" | 8 #include "base/profiler/stack_sampling_profiler.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" |
11 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
14 | 14 |
15 namespace base { | 15 namespace base { |
16 | 16 |
| 17 using SamplingParams = StackSamplingProfiler::SamplingParams; |
17 using Frame = StackSamplingProfiler::Frame; | 18 using Frame = StackSamplingProfiler::Frame; |
18 using Module = StackSamplingProfiler::Module; | 19 using Module = StackSamplingProfiler::Module; |
19 using Sample = StackSamplingProfiler::Sample; | 20 using Sample = StackSamplingProfiler::Sample; |
20 using CallStackProfile = StackSamplingProfiler::CallStackProfile; | 21 using CallStackProfile = StackSamplingProfiler::CallStackProfile; |
| 22 using CallStackProfiles = StackSamplingProfiler::CallStackProfiles; |
21 | 23 |
22 namespace { | 24 namespace { |
23 | 25 |
24 // A thread to target for profiling, whose stack is guaranteed to contain | 26 // A thread to target for profiling, whose stack is guaranteed to contain |
25 // SignalAndWaitUntilSignaled() when coordinated with the main thread. | 27 // SignalAndWaitUntilSignaled() when coordinated with the main thread. |
26 class TargetThread : public PlatformThread::Delegate { | 28 class TargetThread : public PlatformThread::Delegate { |
27 public: | 29 public: |
28 TargetThread(); | 30 TargetThread(); |
29 | 31 |
30 // PlatformThread::Delegate: | 32 // PlatformThread::Delegate: |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 NOINLINE void TargetThread::SignalAndWaitUntilSignaled( | 80 NOINLINE void TargetThread::SignalAndWaitUntilSignaled( |
79 WaitableEvent* thread_started_event, | 81 WaitableEvent* thread_started_event, |
80 WaitableEvent* finish_event) { | 82 WaitableEvent* finish_event) { |
81 thread_started_event->Signal(); | 83 thread_started_event->Signal(); |
82 volatile int x = 1; | 84 volatile int x = 1; |
83 finish_event->Wait(); | 85 finish_event->Wait(); |
84 x = 0; // Prevent tail call to WaitableEvent::Wait(). | 86 x = 0; // Prevent tail call to WaitableEvent::Wait(). |
85 ALLOW_UNUSED_LOCAL(x); | 87 ALLOW_UNUSED_LOCAL(x); |
86 } | 88 } |
87 | 89 |
| 90 // Called on the profiler thread when complete, to collect profiles. |
| 91 void SaveProfiles(CallStackProfiles* profiles, |
| 92 const CallStackProfiles& pending_profiles) { |
| 93 *profiles = pending_profiles; |
| 94 } |
| 95 |
88 // Called on the profiler thread when complete. Collects profiles produced by | 96 // 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 | 97 // the profiler, and signals an event to allow the main thread to know that that |
90 // the profiler is done. | 98 // the profiler is done. |
91 void SaveProfilesAndSignalEvent( | 99 void SaveProfilesAndSignalEvent(CallStackProfiles* profiles, |
92 std::vector<CallStackProfile>* profiles, | 100 WaitableEvent* event, |
93 WaitableEvent* event, | 101 const CallStackProfiles& pending_profiles) { |
94 const std::vector<CallStackProfile>& pending_profiles) { | |
95 *profiles = pending_profiles; | 102 *profiles = pending_profiles; |
96 event->Signal(); | 103 event->Signal(); |
97 } | 104 } |
98 | 105 |
99 // Captures call stack profiles as specified by |params| on the TargetThread, | 106 // Executes the function with the target thread running and executing within |
100 // and returns them in |profiles|. Waits up to |profiler_wait_time| for the | 107 // SignalAndWaitUntilSignaled(). Performs all necessary target thread startup |
101 // profiler to complete. | 108 // and shutdown work before and afterward. |
102 void CaptureProfiles(const StackSamplingProfiler::SamplingParams& params, | 109 template <class Function> |
103 std::vector<CallStackProfile>* profiles, | 110 void WithTargetThread(Function function) { |
104 TimeDelta profiler_wait_time) { | |
105 TargetThread target_thread; | 111 TargetThread target_thread; |
106 PlatformThreadHandle target_thread_handle; | 112 PlatformThreadHandle target_thread_handle; |
107 EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle)); | 113 EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle)); |
108 | 114 |
109 target_thread.WaitForThreadStart(); | 115 target_thread.WaitForThreadStart(); |
110 | 116 |
111 WaitableEvent sampling_thread_completed(true, false); | 117 function(target_thread.id()); |
112 profiles->clear(); | |
113 StackSamplingProfiler profiler(target_thread.id(), params); | |
114 profiler.set_custom_completed_callback( | |
115 Bind(&SaveProfilesAndSignalEvent, Unretained(profiles), | |
116 Unretained(&sampling_thread_completed))); | |
117 profiler.Start(); | |
118 sampling_thread_completed.TimedWait(profiler_wait_time); | |
119 profiler.Stop(); | |
120 sampling_thread_completed.Wait(); | |
121 | 118 |
122 target_thread.SignalThreadToFinish(); | 119 target_thread.SignalThreadToFinish(); |
123 | 120 |
124 PlatformThread::Join(target_thread_handle); | 121 PlatformThread::Join(target_thread_handle); |
125 } | 122 } |
126 | 123 |
| 124 // Captures profiles as specified by |params| on the TargetThread, and returns |
| 125 // them in |profiles|. Waits up to |profiler_wait_time| for the profiler to |
| 126 // complete. |
| 127 void CaptureProfilesWithObjectCallback(const SamplingParams& params, |
| 128 CallStackProfiles* profiles, |
| 129 TimeDelta profiler_wait_time) { |
| 130 profiles->clear(); |
| 131 |
| 132 WithTargetThread([¶ms, profiles, profiler_wait_time]( |
| 133 PlatformThreadId target_thread_id) { |
| 134 WaitableEvent sampling_thread_completed(true, false); |
| 135 const StackSamplingProfiler::CompletedCallback callback = |
| 136 Bind(&SaveProfilesAndSignalEvent, Unretained(profiles), |
| 137 Unretained(&sampling_thread_completed)); |
| 138 StackSamplingProfiler profiler(target_thread_id, params, callback); |
| 139 profiler.Start(); |
| 140 sampling_thread_completed.TimedWait(profiler_wait_time); |
| 141 profiler.Stop(); |
| 142 sampling_thread_completed.Wait(); |
| 143 }); |
| 144 } |
| 145 |
| 146 // Captures profiles as specified by |params| on the TargetThread, and returns |
| 147 // them in |profiles|. Uses the default callback rather than a per-object |
| 148 // callback. |
| 149 void CaptureProfilesWithDefaultCallback(const SamplingParams& params, |
| 150 CallStackProfiles* profiles) { |
| 151 profiles->clear(); |
| 152 |
| 153 WithTargetThread([¶ms, profiles](PlatformThreadId target_thread_id) { |
| 154 WaitableEvent sampling_thread_completed(false, false); |
| 155 StackSamplingProfiler::SetDefaultCompletedCallback( |
| 156 Bind(&SaveProfilesAndSignalEvent, Unretained(profiles), |
| 157 Unretained(&sampling_thread_completed))); |
| 158 |
| 159 StackSamplingProfiler profiler(target_thread_id, params); |
| 160 profiler.Start(); |
| 161 sampling_thread_completed.Wait(); |
| 162 |
| 163 StackSamplingProfiler::SetDefaultCompletedCallback( |
| 164 StackSamplingProfiler::CompletedCallback()); |
| 165 }); |
| 166 } |
| 167 |
| 168 // Runs the profiler with |params| on the TargetThread, with no default or |
| 169 // per-object callback. |
| 170 void RunProfilerWithNoCallback(const SamplingParams& params, |
| 171 TimeDelta profiler_wait_time) { |
| 172 WithTargetThread( |
| 173 [¶ms, profiler_wait_time](PlatformThreadId target_thread_id) { |
| 174 StackSamplingProfiler profiler(target_thread_id, params); |
| 175 profiler.Start(); |
| 176 // Since we don't specify a callback, we don't have a synchronization |
| 177 // mechanism with the sampling thread. Just sleep instead. |
| 178 PlatformThread::Sleep(profiler_wait_time); |
| 179 profiler.Stop(); |
| 180 }); |
| 181 } |
| 182 |
127 // If this executable was linked with /INCREMENTAL (the default for non-official | 183 // 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 | 184 // debug and release builds on Windows), function addresses do not correspond to |
129 // function code itself, but instead to instructions in the Incremental Link | 185 // 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 | 186 // 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 | 187 // present does a little decompilation to find the function's actual starting |
132 // address. | 188 // address. |
133 const void* MaybeFixupFunctionAddressForILT(const void* function_address) { | 189 const void* MaybeFixupFunctionAddressForILT(const void* function_address) { |
134 #if defined(_WIN64) | 190 #if defined(_WIN64) |
135 const unsigned char* opcode = | 191 const unsigned char* opcode = |
136 reinterpret_cast<const unsigned char*>(function_address); | 192 reinterpret_cast<const unsigned char*>(function_address); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 // tested functionality on other platforms/architectures. | 244 // tested functionality on other platforms/architectures. |
189 | 245 |
190 // Checks that the basic expected information is present in a sampled call stack | 246 // Checks that the basic expected information is present in a sampled call stack |
191 // profile. | 247 // profile. |
192 #if defined(_WIN64) | 248 #if defined(_WIN64) |
193 #define MAYBE_Basic Basic | 249 #define MAYBE_Basic Basic |
194 #else | 250 #else |
195 #define MAYBE_Basic DISABLED_Basic | 251 #define MAYBE_Basic DISABLED_Basic |
196 #endif | 252 #endif |
197 TEST(StackSamplingProfilerTest, MAYBE_Basic) { | 253 TEST(StackSamplingProfilerTest, MAYBE_Basic) { |
198 StackSamplingProfiler::SamplingParams params; | 254 SamplingParams params; |
199 params.sampling_interval = TimeDelta::FromMilliseconds(0); | 255 params.sampling_interval = TimeDelta::FromMilliseconds(0); |
200 params.samples_per_burst = 1; | 256 params.samples_per_burst = 1; |
201 | 257 |
202 std::vector<CallStackProfile> profiles; | 258 std::vector<CallStackProfile> profiles; |
203 CaptureProfiles(params, &profiles, AVeryLongTimeDelta()); | 259 CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta()); |
204 | 260 |
205 // Check that the profile and samples sizes are correct, and the module | 261 // Check that the profile and samples sizes are correct, and the module |
206 // indices are in range. | 262 // indices are in range. |
207 ASSERT_EQ(1u, profiles.size()); | 263 ASSERT_EQ(1u, profiles.size()); |
208 const CallStackProfile& profile = profiles[0]; | 264 const CallStackProfile& profile = profiles[0]; |
209 ASSERT_EQ(1u, profile.samples.size()); | 265 ASSERT_EQ(1u, profile.samples.size()); |
210 EXPECT_EQ(params.sampling_interval, profile.sampling_period); | 266 EXPECT_EQ(params.sampling_interval, profile.sampling_period); |
211 const Sample& sample = profile.samples[0]; | 267 const Sample& sample = profile.samples[0]; |
212 for (const auto& frame : sample) { | 268 for (const auto& frame : sample) { |
213 ASSERT_GE(frame.module_index, 0u); | 269 ASSERT_GE(frame.module_index, 0u); |
(...skipping 23 matching lines...) Expand all Loading... |
237 } | 293 } |
238 | 294 |
239 // Checks that the expected number of profiles and samples are present in the | 295 // Checks that the expected number of profiles and samples are present in the |
240 // call stack profiles produced. | 296 // call stack profiles produced. |
241 #if defined(_WIN64) | 297 #if defined(_WIN64) |
242 #define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples | 298 #define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples |
243 #else | 299 #else |
244 #define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples | 300 #define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples |
245 #endif | 301 #endif |
246 TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) { | 302 TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) { |
247 StackSamplingProfiler::SamplingParams params; | 303 SamplingParams params; |
248 params.burst_interval = params.sampling_interval = | 304 params.burst_interval = params.sampling_interval = |
249 TimeDelta::FromMilliseconds(0); | 305 TimeDelta::FromMilliseconds(0); |
250 params.bursts = 2; | 306 params.bursts = 2; |
251 params.samples_per_burst = 3; | 307 params.samples_per_burst = 3; |
252 | 308 |
253 std::vector<CallStackProfile> profiles; | 309 std::vector<CallStackProfile> profiles; |
254 CaptureProfiles(params, &profiles, AVeryLongTimeDelta()); | 310 CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta()); |
255 | 311 |
256 ASSERT_EQ(2u, profiles.size()); | 312 ASSERT_EQ(2u, profiles.size()); |
257 EXPECT_EQ(3u, profiles[0].samples.size()); | 313 EXPECT_EQ(3u, profiles[0].samples.size()); |
258 EXPECT_EQ(3u, profiles[1].samples.size()); | 314 EXPECT_EQ(3u, profiles[1].samples.size()); |
259 } | 315 } |
260 | 316 |
261 // Checks that no call stack profiles are captured if the profiling is stopped | 317 // Checks that no call stack profiles are captured if the profiling is stopped |
262 // during the initial delay. | 318 // during the initial delay. |
263 #if defined(_WIN64) | 319 #if defined(_WIN64) |
264 #define MAYBE_StopDuringInitialDelay StopDuringInitialDelay | 320 #define MAYBE_StopDuringInitialDelay StopDuringInitialDelay |
265 #else | 321 #else |
266 #define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay | 322 #define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay |
267 #endif | 323 #endif |
268 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) { | 324 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) { |
269 StackSamplingProfiler::SamplingParams params; | 325 SamplingParams params; |
270 params.initial_delay = TimeDelta::FromSeconds(60); | 326 params.initial_delay = TimeDelta::FromSeconds(60); |
271 | 327 |
272 std::vector<CallStackProfile> profiles; | 328 std::vector<CallStackProfile> profiles; |
273 CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(0)); | 329 CaptureProfilesWithObjectCallback(params, &profiles, |
| 330 TimeDelta::FromMilliseconds(0)); |
274 | 331 |
275 EXPECT_TRUE(profiles.empty()); | 332 EXPECT_TRUE(profiles.empty()); |
276 } | 333 } |
277 | 334 |
278 // Checks that the single completed call stack profile is captured if the | 335 // Checks that the single completed call stack profile is captured if the |
279 // profiling is stopped between bursts. | 336 // profiling is stopped between bursts. |
280 #if defined(_WIN64) | 337 #if defined(_WIN64) |
281 #define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval | 338 #define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval |
282 #else | 339 #else |
283 #define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval | 340 #define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval |
284 #endif | 341 #endif |
285 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) { | 342 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) { |
286 StackSamplingProfiler::SamplingParams params; | 343 SamplingParams params; |
287 params.sampling_interval = TimeDelta::FromMilliseconds(0); | 344 params.sampling_interval = TimeDelta::FromMilliseconds(0); |
288 params.burst_interval = TimeDelta::FromSeconds(60); | 345 params.burst_interval = TimeDelta::FromSeconds(60); |
289 params.bursts = 2; | 346 params.bursts = 2; |
290 params.samples_per_burst = 1; | 347 params.samples_per_burst = 1; |
291 | 348 |
292 std::vector<CallStackProfile> profiles; | 349 std::vector<CallStackProfile> profiles; |
293 CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50)); | 350 CaptureProfilesWithObjectCallback(params, &profiles, |
| 351 TimeDelta::FromMilliseconds(50)); |
294 | 352 |
295 ASSERT_EQ(1u, profiles.size()); | 353 ASSERT_EQ(1u, profiles.size()); |
296 EXPECT_EQ(1u, profiles[0].samples.size()); | 354 EXPECT_EQ(1u, profiles[0].samples.size()); |
297 } | 355 } |
298 | 356 |
299 // Checks that only completed call stack profiles are captured. | 357 // Checks that only completed call stack profiles are captured. |
300 #if defined(_WIN64) | 358 #if defined(_WIN64) |
301 #define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval | 359 #define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval |
302 #else | 360 #else |
303 #define MAYBE_StopDuringInterSampleInterval \ | 361 #define MAYBE_StopDuringInterSampleInterval \ |
304 DISABLED_StopDuringInterSampleInterval | 362 DISABLED_StopDuringInterSampleInterval |
305 #endif | 363 #endif |
306 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) { | 364 TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) { |
307 StackSamplingProfiler::SamplingParams params; | 365 SamplingParams params; |
308 params.sampling_interval = TimeDelta::FromSeconds(60); | 366 params.sampling_interval = TimeDelta::FromSeconds(60); |
309 params.samples_per_burst = 2; | 367 params.samples_per_burst = 2; |
310 | 368 |
311 std::vector<CallStackProfile> profiles; | 369 std::vector<CallStackProfile> profiles; |
312 CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50)); | 370 CaptureProfilesWithObjectCallback(params, &profiles, |
| 371 TimeDelta::FromMilliseconds(50)); |
313 | 372 |
314 EXPECT_TRUE(profiles.empty()); | 373 EXPECT_TRUE(profiles.empty()); |
315 } | 374 } |
316 | 375 |
| 376 // Checks that profiles are captured via the default completed callback. |
| 377 #if defined(_WIN64) |
| 378 #define MAYBE_DefaultCallback DefaultCallback |
| 379 #else |
| 380 #define MAYBE_DefaultCallback DISABLED_DefaultCallback |
| 381 #endif |
| 382 TEST(StackSamplingProfilerTest, MAYBE_DefaultCallback) { |
| 383 SamplingParams params; |
| 384 params.samples_per_burst = 1; |
| 385 |
| 386 CallStackProfiles profiles; |
| 387 CaptureProfilesWithDefaultCallback(params, &profiles); |
| 388 |
| 389 EXPECT_EQ(1u, profiles.size()); |
| 390 EXPECT_EQ(1u, profiles[0].samples.size()); |
| 391 } |
| 392 |
| 393 // Checks that profiles are queued until a default callback is set, then |
| 394 // delivered. |
| 395 #if defined(_WIN64) |
| 396 #define MAYBE_ProfilesQueuedWithNoCallback ProfilesQueuedWithNoCallback |
| 397 #else |
| 398 #define MAYBE_ProfilesQueuedWithNoCallback DISABLED_ProfilesQueuedWithNoCallback |
| 399 #endif |
| 400 TEST(StackSamplingProfilerTest, MAYBE_ProfilesQueuedWithNoCallback) { |
| 401 SamplingParams params; |
| 402 params.samples_per_burst = 1; |
| 403 |
| 404 RunProfilerWithNoCallback(params, TimeDelta::FromMilliseconds(50)); |
| 405 |
| 406 CallStackProfiles profiles; |
| 407 // This should immediately call SaveProfiles on this thread. |
| 408 StackSamplingProfiler::SetDefaultCompletedCallback( |
| 409 Bind(&SaveProfiles, Unretained(&profiles))); |
| 410 EXPECT_EQ(1u, profiles.size()); |
| 411 EXPECT_EQ(1u, profiles[0].samples.size()); |
| 412 StackSamplingProfiler::SetDefaultCompletedCallback( |
| 413 StackSamplingProfiler::CompletedCallback()); |
| 414 } |
| 415 |
| 416 // Checks that we can destroy the profiler while profiling. |
| 417 #if defined(_WIN64) |
| 418 #define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling |
| 419 #else |
| 420 #define MAYBE_DestroyProfilerWhileProfiling \ |
| 421 DISABLED_DestroyProfilerWhileProfiling |
| 422 #endif |
| 423 TEST(StackSamplingProfilerTest, MAYBE_DestroyProfilerWhileProfiling) { |
| 424 SamplingParams params; |
| 425 params.sampling_interval = TimeDelta::FromMilliseconds(10); |
| 426 |
| 427 CallStackProfiles profiles; |
| 428 WithTargetThread([¶ms, &profiles](PlatformThreadId target_thread_id) { |
| 429 scoped_ptr<StackSamplingProfiler> profiler; |
| 430 profiler.reset(new StackSamplingProfiler( |
| 431 target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles)))); |
| 432 profiler->Start(); |
| 433 profiler.reset(); |
| 434 |
| 435 // Wait longer than a sample interval to catch any use-after-free actions by |
| 436 // the profiler thread. |
| 437 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); |
| 438 }); |
| 439 } |
| 440 |
317 } // namespace base | 441 } // namespace base |
OLD | NEW |