| 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 |