| 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/profiler/native_stack_sampler.h" | 5 #include "base/profiler/native_stack_sampler.h" |
| 6 | 6 |
| 7 #include <objbase.h> | 7 #include <objbase.h> |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <winternl.h> | 10 #include <winternl.h> |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 // IMPORTANT NOTE: No allocations from the default heap may occur in the | 325 // IMPORTANT NOTE: No allocations from the default heap may occur in the |
| 326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or | 326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or |
| 327 // other logging statements. Otherwise this code can deadlock on heap locks in | 327 // other logging statements. Otherwise this code can deadlock on heap locks in |
| 328 // the default heap acquired by the target thread before it was suspended. | 328 // the default heap acquired by the target thread before it was suspended. |
| 329 void SuspendThreadAndRecordStack( | 329 void SuspendThreadAndRecordStack( |
| 330 HANDLE thread_handle, | 330 HANDLE thread_handle, |
| 331 const void* base_address, | 331 const void* base_address, |
| 332 void* stack_copy_buffer, | 332 void* stack_copy_buffer, |
| 333 size_t stack_copy_buffer_size, | 333 size_t stack_copy_buffer_size, |
| 334 std::vector<RecordedFrame>* stack, | 334 std::vector<RecordedFrame>* stack, |
| 335 NativeStackSampler::AnnotateCallback annotator, |
| 336 StackSamplingProfiler::Sample* sample, |
| 335 NativeStackSamplerTestDelegate* test_delegate) { | 337 NativeStackSamplerTestDelegate* test_delegate) { |
| 336 DCHECK(stack->empty()); | 338 DCHECK(stack->empty()); |
| 337 | 339 |
| 338 CONTEXT thread_context = {0}; | 340 CONTEXT thread_context = {0}; |
| 339 thread_context.ContextFlags = CONTEXT_FULL; | 341 thread_context.ContextFlags = CONTEXT_FULL; |
| 340 // The stack bounds are saved to uintptr_ts for use outside | 342 // The stack bounds are saved to uintptr_ts for use outside |
| 341 // ScopedSuspendThread, as the thread's memory is not safe to dereference | 343 // ScopedSuspendThread, as the thread's memory is not safe to dereference |
| 342 // beyond that point. | 344 // beyond that point. |
| 343 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); | 345 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); |
| 344 uintptr_t bottom = 0u; | 346 uintptr_t bottom = 0u; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 359 | 361 |
| 360 if ((top - bottom) > stack_copy_buffer_size) | 362 if ((top - bottom) > stack_copy_buffer_size) |
| 361 return; | 363 return; |
| 362 | 364 |
| 363 // Dereferencing a pointer in the guard page in a thread that doesn't own | 365 // Dereferencing a pointer in the guard page in a thread that doesn't own |
| 364 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. | 366 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. |
| 365 // This occurs very rarely, but reliably over the population. | 367 // This occurs very rarely, but reliably over the population. |
| 366 if (PointsToGuardPage(bottom)) | 368 if (PointsToGuardPage(bottom)) |
| 367 return; | 369 return; |
| 368 | 370 |
| 371 (*annotator)(sample); |
| 372 |
| 369 CopyMemoryFromStack(stack_copy_buffer, | 373 CopyMemoryFromStack(stack_copy_buffer, |
| 370 reinterpret_cast<const void*>(bottom), top - bottom); | 374 reinterpret_cast<const void*>(bottom), top - bottom); |
| 371 } | 375 } |
| 372 | 376 |
| 373 if (test_delegate) | 377 if (test_delegate) |
| 374 test_delegate->OnPreStackWalk(); | 378 test_delegate->OnPreStackWalk(); |
| 375 | 379 |
| 376 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); | 380 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); |
| 377 | 381 |
| 378 RecordStack(&thread_context, stack); | 382 RecordStack(&thread_context, stack); |
| 379 } | 383 } |
| 380 | 384 |
| 381 // NativeStackSamplerWin ------------------------------------------------------ | 385 // NativeStackSamplerWin ------------------------------------------------------ |
| 382 | 386 |
| 383 class NativeStackSamplerWin : public NativeStackSampler { | 387 class NativeStackSamplerWin : public NativeStackSampler { |
| 384 public: | 388 public: |
| 385 NativeStackSamplerWin(win::ScopedHandle thread_handle, | 389 NativeStackSamplerWin(win::ScopedHandle thread_handle, |
| 390 AnnotateCallback annotator, |
| 386 NativeStackSamplerTestDelegate* test_delegate); | 391 NativeStackSamplerTestDelegate* test_delegate); |
| 387 ~NativeStackSamplerWin() override; | 392 ~NativeStackSamplerWin() override; |
| 388 | 393 |
| 389 // StackSamplingProfiler::NativeStackSampler: | 394 // StackSamplingProfiler::NativeStackSampler: |
| 390 void ProfileRecordingStarting( | 395 void ProfileRecordingStarting( |
| 391 std::vector<StackSamplingProfiler::Module>* modules) override; | 396 std::vector<StackSamplingProfiler::Module>* modules) override; |
| 392 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; | 397 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; |
| 393 void ProfileRecordingStopped() override; | 398 void ProfileRecordingStopped() override; |
| 394 | 399 |
| 395 private: | 400 private: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 414 size_t GetModuleIndex(HMODULE module_handle, | 419 size_t GetModuleIndex(HMODULE module_handle, |
| 415 std::vector<StackSamplingProfiler::Module>* modules); | 420 std::vector<StackSamplingProfiler::Module>* modules); |
| 416 | 421 |
| 417 // Copies the information represented by |stack| into |sample| and |modules|. | 422 // Copies the information represented by |stack| into |sample| and |modules|. |
| 418 void CopyToSample(const std::vector<RecordedFrame>& stack, | 423 void CopyToSample(const std::vector<RecordedFrame>& stack, |
| 419 StackSamplingProfiler::Sample* sample, | 424 StackSamplingProfiler::Sample* sample, |
| 420 std::vector<StackSamplingProfiler::Module>* modules); | 425 std::vector<StackSamplingProfiler::Module>* modules); |
| 421 | 426 |
| 422 win::ScopedHandle thread_handle_; | 427 win::ScopedHandle thread_handle_; |
| 423 | 428 |
| 429 const AnnotateCallback annotator_; |
| 430 |
| 424 NativeStackSamplerTestDelegate* const test_delegate_; | 431 NativeStackSamplerTestDelegate* const test_delegate_; |
| 425 | 432 |
| 426 // The stack base address corresponding to |thread_handle_|. | 433 // The stack base address corresponding to |thread_handle_|. |
| 427 const void* const thread_stack_base_address_; | 434 const void* const thread_stack_base_address_; |
| 428 | 435 |
| 429 // Buffer to use for copies of the stack. We use the same buffer for all the | 436 // Buffer to use for copies of the stack. We use the same buffer for all the |
| 430 // samples to avoid the overhead of multiple allocations and frees. | 437 // samples to avoid the overhead of multiple allocations and frees. |
| 431 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; | 438 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; |
| 432 | 439 |
| 433 // Weak. Points to the modules associated with the profile being recorded | 440 // Weak. Points to the modules associated with the profile being recorded |
| 434 // between ProfileRecordingStarting() and ProfileRecordingStopped(). | 441 // between ProfileRecordingStarting() and ProfileRecordingStopped(). |
| 435 std::vector<StackSamplingProfiler::Module>* current_modules_; | 442 std::vector<StackSamplingProfiler::Module>* current_modules_; |
| 436 | 443 |
| 437 // Maps a module handle to the corresponding Module's index within | 444 // Maps a module handle to the corresponding Module's index within |
| 438 // current_modules_. | 445 // current_modules_. |
| 439 std::map<HMODULE, size_t> profile_module_index_; | 446 std::map<HMODULE, size_t> profile_module_index_; |
| 440 | 447 |
| 441 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); | 448 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); |
| 442 }; | 449 }; |
| 443 | 450 |
| 444 NativeStackSamplerWin::NativeStackSamplerWin( | 451 NativeStackSamplerWin::NativeStackSamplerWin( |
| 445 win::ScopedHandle thread_handle, | 452 win::ScopedHandle thread_handle, |
| 453 AnnotateCallback annotator, |
| 446 NativeStackSamplerTestDelegate* test_delegate) | 454 NativeStackSamplerTestDelegate* test_delegate) |
| 447 : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate), | 455 : thread_handle_(thread_handle.Take()), |
| 456 annotator_(annotator), |
| 457 test_delegate_(test_delegate), |
| 448 thread_stack_base_address_( | 458 thread_stack_base_address_( |
| 449 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), | 459 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), |
| 450 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { | 460 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { |
| 461 DCHECK(annotator_); |
| 451 } | 462 } |
| 452 | 463 |
| 453 NativeStackSamplerWin::~NativeStackSamplerWin() { | 464 NativeStackSamplerWin::~NativeStackSamplerWin() { |
| 454 } | 465 } |
| 455 | 466 |
| 456 void NativeStackSamplerWin::ProfileRecordingStarting( | 467 void NativeStackSamplerWin::ProfileRecordingStarting( |
| 457 std::vector<StackSamplingProfiler::Module>* modules) { | 468 std::vector<StackSamplingProfiler::Module>* modules) { |
| 458 current_modules_ = modules; | 469 current_modules_ = modules; |
| 459 profile_module_index_.clear(); | 470 profile_module_index_.clear(); |
| 460 } | 471 } |
| 461 | 472 |
| 462 void NativeStackSamplerWin::RecordStackSample( | 473 void NativeStackSamplerWin::RecordStackSample( |
| 463 StackSamplingProfiler::Sample* sample) { | 474 StackSamplingProfiler::Sample* sample) { |
| 464 DCHECK(current_modules_); | 475 DCHECK(current_modules_); |
| 465 | 476 |
| 466 if (!stack_copy_buffer_) | 477 if (!stack_copy_buffer_) |
| 467 return; | 478 return; |
| 468 | 479 |
| 469 std::vector<RecordedFrame> stack; | 480 std::vector<RecordedFrame> stack; |
| 470 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, | 481 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, |
| 471 stack_copy_buffer_.get(), kStackCopyBufferSize, | 482 stack_copy_buffer_.get(), kStackCopyBufferSize, |
| 472 &stack, test_delegate_); | 483 &stack, annotator_, sample, test_delegate_); |
| 473 CopyToSample(stack, sample, current_modules_); | 484 CopyToSample(stack, sample, current_modules_); |
| 474 } | 485 } |
| 475 | 486 |
| 476 void NativeStackSamplerWin::ProfileRecordingStopped() { | 487 void NativeStackSamplerWin::ProfileRecordingStopped() { |
| 477 current_modules_ = nullptr; | 488 current_modules_ = nullptr; |
| 478 } | 489 } |
| 479 | 490 |
| 480 // static | 491 // static |
| 481 bool NativeStackSamplerWin::GetModuleForHandle( | 492 bool NativeStackSamplerWin::GetModuleForHandle( |
| 482 HMODULE module_handle, | 493 HMODULE module_handle, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 module_handle, modules->size() - 1)).first; | 525 module_handle, modules->size() - 1)).first; |
| 515 } | 526 } |
| 516 | 527 |
| 517 return loc->second; | 528 return loc->second; |
| 518 } | 529 } |
| 519 | 530 |
| 520 void NativeStackSamplerWin::CopyToSample( | 531 void NativeStackSamplerWin::CopyToSample( |
| 521 const std::vector<RecordedFrame>& stack, | 532 const std::vector<RecordedFrame>& stack, |
| 522 StackSamplingProfiler::Sample* sample, | 533 StackSamplingProfiler::Sample* sample, |
| 523 std::vector<StackSamplingProfiler::Module>* modules) { | 534 std::vector<StackSamplingProfiler::Module>* modules) { |
| 524 sample->clear(); | 535 sample->frames.clear(); |
| 525 sample->reserve(stack.size()); | 536 sample->frames.reserve(stack.size()); |
| 526 | 537 |
| 527 for (const RecordedFrame& frame : stack) { | 538 for (const RecordedFrame& frame : stack) { |
| 528 sample->push_back(StackSamplingProfiler::Frame( | 539 sample->frames.push_back(StackSamplingProfiler::Frame( |
| 529 reinterpret_cast<uintptr_t>(frame.instruction_pointer), | 540 reinterpret_cast<uintptr_t>(frame.instruction_pointer), |
| 530 GetModuleIndex(frame.module.Get(), modules))); | 541 GetModuleIndex(frame.module.Get(), modules))); |
| 531 } | 542 } |
| 532 } | 543 } |
| 533 | 544 |
| 534 } // namespace | 545 } // namespace |
| 535 | 546 |
| 536 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( | 547 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( |
| 537 PlatformThreadId thread_id, | 548 PlatformThreadId thread_id, |
| 549 AnnotateCallback annotator, |
| 538 NativeStackSamplerTestDelegate* test_delegate) { | 550 NativeStackSamplerTestDelegate* test_delegate) { |
| 539 #if _WIN64 | 551 #if _WIN64 |
| 540 // Get the thread's handle. | 552 // Get the thread's handle. |
| 541 HANDLE thread_handle = ::OpenThread( | 553 HANDLE thread_handle = ::OpenThread( |
| 542 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, | 554 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, |
| 543 FALSE, | 555 FALSE, |
| 544 thread_id); | 556 thread_id); |
| 545 | 557 |
| 546 if (thread_handle) { | 558 if (thread_handle) { |
| 547 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( | 559 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( |
| 548 win::ScopedHandle(thread_handle), test_delegate)); | 560 win::ScopedHandle(thread_handle), annotator, test_delegate)); |
| 549 } | 561 } |
| 550 #endif | 562 #endif |
| 551 return std::unique_ptr<NativeStackSampler>(); | 563 return std::unique_ptr<NativeStackSampler>(); |
| 552 } | 564 } |
| 553 | 565 |
| 554 } // namespace base | 566 } // namespace base |
| OLD | NEW |