OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/profiler/native_stack_sampler.h" | 5 #include "base/profiler/native_stack_sampler.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <libkern/OSByteOrder.h> | 8 #include <libkern/OSByteOrder.h> |
9 #include <libunwind.h> | 9 #include <libunwind.h> |
10 #include <mach-o/swap.h> | 10 #include <mach-o/swap.h> |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 class NativeStackSamplerMac : public NativeStackSampler { | 316 class NativeStackSamplerMac : public NativeStackSampler { |
317 public: | 317 public: |
318 NativeStackSamplerMac(mach_port_t thread_port, | 318 NativeStackSamplerMac(mach_port_t thread_port, |
319 AnnotateCallback annotator, | 319 AnnotateCallback annotator, |
320 NativeStackSamplerTestDelegate* test_delegate); | 320 NativeStackSamplerTestDelegate* test_delegate); |
321 ~NativeStackSamplerMac() override; | 321 ~NativeStackSamplerMac() override; |
322 | 322 |
323 // StackSamplingProfiler::NativeStackSampler: | 323 // StackSamplingProfiler::NativeStackSampler: |
324 void ProfileRecordingStarting( | 324 void ProfileRecordingStarting( |
325 std::vector<StackSamplingProfiler::Module>* modules) override; | 325 std::vector<StackSamplingProfiler::Module>* modules) override; |
326 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; | 326 void RecordStackSample(StackBuffer* stackbuffer, |
327 void ProfileRecordingStopped() override; | 327 StackSamplingProfiler::Sample* sample) override; |
| 328 void ProfileRecordingStopped(StackBuffer* stackbuffer) override; |
328 | 329 |
329 private: | 330 private: |
330 // Suspends the thread with |thread_port_|, copies its stack and resumes the | 331 // Suspends the thread with |thread_port_|, copies its stack and resumes the |
331 // thread, then records the stack frames and associated modules into |sample|. | 332 // thread, then records the stack frames and associated modules into |sample|. |
332 void SuspendThreadAndRecordStack(StackSamplingProfiler::Sample* sample); | 333 void SuspendThreadAndRecordStack(StackBuffer* stackbuffer, |
| 334 StackSamplingProfiler::Sample* sample); |
333 | 335 |
334 // Weak reference: Mach port for thread being profiled. | 336 // Weak reference: Mach port for thread being profiled. |
335 mach_port_t thread_port_; | 337 mach_port_t thread_port_; |
336 | 338 |
337 const AnnotateCallback annotator_; | 339 const AnnotateCallback annotator_; |
338 | 340 |
339 NativeStackSamplerTestDelegate* const test_delegate_; | 341 NativeStackSamplerTestDelegate* const test_delegate_; |
340 | 342 |
341 // The stack base address corresponding to |thread_handle_|. | 343 // The stack base address corresponding to |thread_handle_|. |
342 const void* const thread_stack_base_address_; | 344 const void* const thread_stack_base_address_; |
343 | 345 |
344 // The size of the |stack_copy_buffer_|. | |
345 const size_t stack_copy_buffer_size_; | |
346 | |
347 // Buffer to use for copies of the stack. We use the same buffer for all the | |
348 // samples to avoid the overhead of multiple allocations and frees. | |
349 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; | |
350 | |
351 // Weak. Points to the modules associated with the profile being recorded | 346 // Weak. Points to the modules associated with the profile being recorded |
352 // between ProfileRecordingStarting() and ProfileRecordingStopped(). | 347 // between ProfileRecordingStarting() and ProfileRecordingStopped(). |
353 std::vector<StackSamplingProfiler::Module>* current_modules_ = nullptr; | 348 std::vector<StackSamplingProfiler::Module>* current_modules_ = nullptr; |
354 | 349 |
355 // Maps a module's base address to the corresponding Module's index within | 350 // Maps a module's base address to the corresponding Module's index within |
356 // current_modules_. | 351 // current_modules_. |
357 std::map<const void*, size_t> profile_module_index_; | 352 std::map<const void*, size_t> profile_module_index_; |
358 | 353 |
359 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerMac); | 354 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerMac); |
360 }; | 355 }; |
361 | 356 |
362 NativeStackSamplerMac::NativeStackSamplerMac( | 357 NativeStackSamplerMac::NativeStackSamplerMac( |
363 mach_port_t thread_port, | 358 mach_port_t thread_port, |
364 AnnotateCallback annotator, | 359 AnnotateCallback annotator, |
365 NativeStackSamplerTestDelegate* test_delegate) | 360 NativeStackSamplerTestDelegate* test_delegate) |
366 : thread_port_(thread_port), | 361 : thread_port_(thread_port), |
367 annotator_(annotator), | 362 annotator_(annotator), |
368 test_delegate_(test_delegate), | 363 test_delegate_(test_delegate), |
369 thread_stack_base_address_( | 364 thread_stack_base_address_( |
370 pthread_get_stackaddr_np(pthread_from_mach_thread_np(thread_port))), | 365 pthread_get_stackaddr_np(pthread_from_mach_thread_np(thread_port))) { |
371 stack_copy_buffer_size_(StackCopyBufferSize()), | |
372 stack_copy_buffer_(new unsigned char[stack_copy_buffer_size_]) { | |
373 DCHECK(annotator_); | 366 DCHECK(annotator_); |
374 | 367 |
375 // This class suspends threads, and those threads might be suspended in dyld. | 368 // This class suspends threads, and those threads might be suspended in dyld. |
376 // Therefore, for all the system functions that might be linked in dynamically | 369 // Therefore, for all the system functions that might be linked in dynamically |
377 // that are used while threads are suspended, make calls to them to make sure | 370 // that are used while threads are suspended, make calls to them to make sure |
378 // that they are linked up. | 371 // that they are linked up. |
379 x86_thread_state64_t thread_state; | 372 x86_thread_state64_t thread_state; |
380 GetThreadState(thread_port_, &thread_state); | 373 GetThreadState(thread_port_, &thread_state); |
381 } | 374 } |
382 | 375 |
383 NativeStackSamplerMac::~NativeStackSamplerMac() {} | 376 NativeStackSamplerMac::~NativeStackSamplerMac() {} |
384 | 377 |
385 void NativeStackSamplerMac::ProfileRecordingStarting( | 378 void NativeStackSamplerMac::ProfileRecordingStarting( |
386 std::vector<StackSamplingProfiler::Module>* modules) { | 379 std::vector<StackSamplingProfiler::Module>* modules) { |
387 current_modules_ = modules; | 380 current_modules_ = modules; |
388 profile_module_index_.clear(); | 381 profile_module_index_.clear(); |
389 } | 382 } |
390 | 383 |
391 void NativeStackSamplerMac::RecordStackSample( | 384 void NativeStackSamplerMac::RecordStackSample( |
| 385 StackBuffer* stackbuffer, |
392 StackSamplingProfiler::Sample* sample) { | 386 StackSamplingProfiler::Sample* sample) { |
393 DCHECK(current_modules_); | 387 DCHECK(current_modules_); |
394 | 388 |
395 SuspendThreadAndRecordStack(sample); | 389 SuspendThreadAndRecordStack(stackbuffer, sample); |
396 } | 390 } |
397 | 391 |
398 void NativeStackSamplerMac::ProfileRecordingStopped() { | 392 void NativeStackSamplerMac::ProfileRecordingStopped(StackBuffer* stackbuffer) { |
399 current_modules_ = nullptr; | 393 current_modules_ = nullptr; |
400 } | 394 } |
401 | 395 |
402 void NativeStackSamplerMac::SuspendThreadAndRecordStack( | 396 void NativeStackSamplerMac::SuspendThreadAndRecordStack( |
| 397 StackBuffer* stackbuffer, |
403 StackSamplingProfiler::Sample* sample) { | 398 StackSamplingProfiler::Sample* sample) { |
404 x86_thread_state64_t thread_state; | 399 x86_thread_state64_t thread_state; |
405 | 400 |
406 // Copy the stack. | 401 // Copy the stack. |
407 | 402 |
408 uintptr_t new_stack_top = 0; | 403 uintptr_t new_stack_top = 0; |
409 { | 404 { |
410 // IMPORTANT NOTE: Do not do ANYTHING in this in this scope that might | 405 // IMPORTANT NOTE: Do not do ANYTHING in this in this scope that might |
411 // allocate memory, including indirectly via use of DCHECK/CHECK or other | 406 // allocate memory, including indirectly via use of DCHECK/CHECK or other |
412 // logging statements. Otherwise this code can deadlock on heap locks in the | 407 // logging statements. Otherwise this code can deadlock on heap locks in the |
413 // default heap acquired by the target thread before it was suspended. | 408 // default heap acquired by the target thread before it was suspended. |
414 ScopedSuspendThread suspend_thread(thread_port_); | 409 ScopedSuspendThread suspend_thread(thread_port_); |
415 if (!suspend_thread.was_successful()) | 410 if (!suspend_thread.was_successful()) |
416 return; | 411 return; |
417 | 412 |
418 if (!GetThreadState(thread_port_, &thread_state)) | 413 if (!GetThreadState(thread_port_, &thread_state)) |
419 return; | 414 return; |
420 uintptr_t stack_top = | 415 uintptr_t stack_top = |
421 reinterpret_cast<uintptr_t>(thread_stack_base_address_); | 416 reinterpret_cast<uintptr_t>(thread_stack_base_address_); |
422 uintptr_t stack_bottom = thread_state.__rsp; | 417 uintptr_t stack_bottom = thread_state.__rsp; |
423 if (stack_bottom >= stack_top) | 418 if (stack_bottom >= stack_top) |
424 return; | 419 return; |
425 uintptr_t stack_size = stack_top - stack_bottom; | 420 uintptr_t stack_size = stack_top - stack_bottom; |
426 | 421 |
427 if (stack_size > stack_copy_buffer_size_) | 422 if (stack_size > stackbuffer->size()) |
428 return; | 423 return; |
429 | 424 |
430 (*annotator_)(sample); | 425 (*annotator_)(sample); |
431 | 426 |
432 CopyStackAndRewritePointers( | 427 CopyStackAndRewritePointers( |
433 reinterpret_cast<uintptr_t*>(stack_copy_buffer_.get()), | 428 reinterpret_cast<uintptr_t*>(stackbuffer->buffer()), |
434 reinterpret_cast<uintptr_t*>(stack_bottom), | 429 reinterpret_cast<uintptr_t*>(stack_bottom), |
435 reinterpret_cast<uintptr_t*>(stack_top), &thread_state); | 430 reinterpret_cast<uintptr_t*>(stack_top), &thread_state); |
436 | 431 |
437 new_stack_top = | 432 new_stack_top = |
438 reinterpret_cast<uintptr_t>(stack_copy_buffer_.get()) + stack_size; | 433 reinterpret_cast<uintptr_t>(stackbuffer->buffer()) + stack_size; |
439 } // ScopedSuspendThread | 434 } // ScopedSuspendThread |
440 | 435 |
441 if (test_delegate_) | 436 if (test_delegate_) |
442 test_delegate_->OnPreStackWalk(); | 437 test_delegate_->OnPreStackWalk(); |
443 | 438 |
444 // Walk the stack and record it. | 439 // Walk the stack and record it. |
445 | 440 |
446 // Reserve enough memory for most stacks, to avoid repeated allocations. | 441 // Reserve enough memory for most stacks, to avoid repeated allocations. |
447 // Approximately 99.9% of recorded stacks are 128 frames or fewer. | 442 // Approximately 99.9% of recorded stacks are 128 frames or fewer. |
448 sample->frames.reserve(128); | 443 sample->frames.reserve(128); |
(...skipping 12 matching lines...) Expand all Loading... |
461 } // namespace | 456 } // namespace |
462 | 457 |
463 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( | 458 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( |
464 PlatformThreadId thread_id, | 459 PlatformThreadId thread_id, |
465 AnnotateCallback annotator, | 460 AnnotateCallback annotator, |
466 NativeStackSamplerTestDelegate* test_delegate) { | 461 NativeStackSamplerTestDelegate* test_delegate) { |
467 return base::MakeUnique<NativeStackSamplerMac>(thread_id, annotator, | 462 return base::MakeUnique<NativeStackSamplerMac>(thread_id, annotator, |
468 test_delegate); | 463 test_delegate); |
469 } | 464 } |
470 | 465 |
| 466 std::unique_ptr<NativeStackSampler::StackBuffer> |
| 467 NativeStackSampler::CreateStackBuffer() { |
| 468 return MakeUnique<StackBuffer>(StackCopyBufferSize()); |
| 469 } |
| 470 |
471 } // namespace base | 471 } // namespace base |
OLD | NEW |