| 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 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 // IMPORTANT NOTE: No allocations from the default heap may occur in the | 312 // IMPORTANT NOTE: No allocations from the default heap may occur in the |
| 313 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or | 313 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or |
| 314 // other logging statements. Otherwise this code can deadlock on heap locks in | 314 // other logging statements. Otherwise this code can deadlock on heap locks in |
| 315 // the default heap acquired by the target thread before it was suspended. | 315 // the default heap acquired by the target thread before it was suspended. |
| 316 void SuspendThreadAndRecordStack( | 316 void SuspendThreadAndRecordStack( |
| 317 HANDLE thread_handle, | 317 HANDLE thread_handle, |
| 318 const void* base_address, | 318 const void* base_address, |
| 319 void* stack_copy_buffer, | 319 void* stack_copy_buffer, |
| 320 size_t stack_copy_buffer_size, | 320 size_t stack_copy_buffer_size, |
| 321 std::vector<RecordedFrame>* stack, | 321 std::vector<RecordedFrame>* stack, |
| 322 NativeStackSampler::AnnotateCallback annotator, |
| 323 StackSamplingProfiler::Sample* sample, |
| 322 NativeStackSamplerTestDelegate* test_delegate) { | 324 NativeStackSamplerTestDelegate* test_delegate) { |
| 323 DCHECK(stack->empty()); | 325 DCHECK(stack->empty()); |
| 324 | 326 |
| 325 CONTEXT thread_context = {0}; | 327 CONTEXT thread_context = {0}; |
| 326 thread_context.ContextFlags = CONTEXT_FULL; | 328 thread_context.ContextFlags = CONTEXT_FULL; |
| 327 // The stack bounds are saved to uintptr_ts for use outside | 329 // The stack bounds are saved to uintptr_ts for use outside |
| 328 // ScopedSuspendThread, as the thread's memory is not safe to dereference | 330 // ScopedSuspendThread, as the thread's memory is not safe to dereference |
| 329 // beyond that point. | 331 // beyond that point. |
| 330 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); | 332 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); |
| 331 uintptr_t bottom = 0u; | 333 uintptr_t bottom = 0u; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 346 | 348 |
| 347 if ((top - bottom) > stack_copy_buffer_size) | 349 if ((top - bottom) > stack_copy_buffer_size) |
| 348 return; | 350 return; |
| 349 | 351 |
| 350 // Dereferencing a pointer in the guard page in a thread that doesn't own | 352 // Dereferencing a pointer in the guard page in a thread that doesn't own |
| 351 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. | 353 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. |
| 352 // This occurs very rarely, but reliably over the population. | 354 // This occurs very rarely, but reliably over the population. |
| 353 if (PointsToGuardPage(bottom)) | 355 if (PointsToGuardPage(bottom)) |
| 354 return; | 356 return; |
| 355 | 357 |
| 358 (*annotator)(sample); |
| 359 |
| 356 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom), | 360 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom), |
| 357 top - bottom); | 361 top - bottom); |
| 358 } | 362 } |
| 359 | 363 |
| 360 if (test_delegate) | 364 if (test_delegate) |
| 361 test_delegate->OnPreStackWalk(); | 365 test_delegate->OnPreStackWalk(); |
| 362 | 366 |
| 363 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); | 367 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); |
| 364 | 368 |
| 365 RecordStack(&thread_context, stack); | 369 RecordStack(&thread_context, stack); |
| 366 } | 370 } |
| 367 | 371 |
| 368 // NativeStackSamplerWin ------------------------------------------------------ | 372 // NativeStackSamplerWin ------------------------------------------------------ |
| 369 | 373 |
| 370 class NativeStackSamplerWin : public NativeStackSampler { | 374 class NativeStackSamplerWin : public NativeStackSampler { |
| 371 public: | 375 public: |
| 372 NativeStackSamplerWin(win::ScopedHandle thread_handle, | 376 NativeStackSamplerWin(win::ScopedHandle thread_handle, |
| 377 AnnotateCallback annotator, |
| 373 NativeStackSamplerTestDelegate* test_delegate); | 378 NativeStackSamplerTestDelegate* test_delegate); |
| 374 ~NativeStackSamplerWin() override; | 379 ~NativeStackSamplerWin() override; |
| 375 | 380 |
| 376 // StackSamplingProfiler::NativeStackSampler: | 381 // StackSamplingProfiler::NativeStackSampler: |
| 377 void ProfileRecordingStarting( | 382 void ProfileRecordingStarting( |
| 378 std::vector<StackSamplingProfiler::Module>* modules) override; | 383 std::vector<StackSamplingProfiler::Module>* modules) override; |
| 379 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; | 384 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; |
| 380 void ProfileRecordingStopped() override; | 385 void ProfileRecordingStopped() override; |
| 381 | 386 |
| 382 private: | 387 private: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 401 size_t GetModuleIndex(HMODULE module_handle, | 406 size_t GetModuleIndex(HMODULE module_handle, |
| 402 std::vector<StackSamplingProfiler::Module>* modules); | 407 std::vector<StackSamplingProfiler::Module>* modules); |
| 403 | 408 |
| 404 // Copies the information represented by |stack| into |sample| and |modules|. | 409 // Copies the information represented by |stack| into |sample| and |modules|. |
| 405 void CopyToSample(const std::vector<RecordedFrame>& stack, | 410 void CopyToSample(const std::vector<RecordedFrame>& stack, |
| 406 StackSamplingProfiler::Sample* sample, | 411 StackSamplingProfiler::Sample* sample, |
| 407 std::vector<StackSamplingProfiler::Module>* modules); | 412 std::vector<StackSamplingProfiler::Module>* modules); |
| 408 | 413 |
| 409 win::ScopedHandle thread_handle_; | 414 win::ScopedHandle thread_handle_; |
| 410 | 415 |
| 416 const AnnotateCallback annotator_; |
| 417 |
| 411 NativeStackSamplerTestDelegate* const test_delegate_; | 418 NativeStackSamplerTestDelegate* const test_delegate_; |
| 412 | 419 |
| 413 // The stack base address corresponding to |thread_handle_|. | 420 // The stack base address corresponding to |thread_handle_|. |
| 414 const void* const thread_stack_base_address_; | 421 const void* const thread_stack_base_address_; |
| 415 | 422 |
| 416 // Buffer to use for copies of the stack. We use the same buffer for all the | 423 // Buffer to use for copies of the stack. We use the same buffer for all the |
| 417 // samples to avoid the overhead of multiple allocations and frees. | 424 // samples to avoid the overhead of multiple allocations and frees. |
| 418 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; | 425 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; |
| 419 | 426 |
| 420 // Weak. Points to the modules associated with the profile being recorded | 427 // Weak. Points to the modules associated with the profile being recorded |
| 421 // between ProfileRecordingStarting() and ProfileRecordingStopped(). | 428 // between ProfileRecordingStarting() and ProfileRecordingStopped(). |
| 422 std::vector<StackSamplingProfiler::Module>* current_modules_; | 429 std::vector<StackSamplingProfiler::Module>* current_modules_; |
| 423 | 430 |
| 424 // Maps a module handle to the corresponding Module's index within | 431 // Maps a module handle to the corresponding Module's index within |
| 425 // current_modules_. | 432 // current_modules_. |
| 426 std::map<HMODULE, size_t> profile_module_index_; | 433 std::map<HMODULE, size_t> profile_module_index_; |
| 427 | 434 |
| 428 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); | 435 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); |
| 429 }; | 436 }; |
| 430 | 437 |
| 431 NativeStackSamplerWin::NativeStackSamplerWin( | 438 NativeStackSamplerWin::NativeStackSamplerWin( |
| 432 win::ScopedHandle thread_handle, | 439 win::ScopedHandle thread_handle, |
| 440 AnnotateCallback annotator, |
| 433 NativeStackSamplerTestDelegate* test_delegate) | 441 NativeStackSamplerTestDelegate* test_delegate) |
| 434 : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate), | 442 : thread_handle_(thread_handle.Take()), |
| 443 annotator_(annotator), |
| 444 test_delegate_(test_delegate), |
| 435 thread_stack_base_address_( | 445 thread_stack_base_address_( |
| 436 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), | 446 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), |
| 437 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { | 447 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { |
| 448 DCHECK(annotator_); |
| 438 } | 449 } |
| 439 | 450 |
| 440 NativeStackSamplerWin::~NativeStackSamplerWin() { | 451 NativeStackSamplerWin::~NativeStackSamplerWin() { |
| 441 } | 452 } |
| 442 | 453 |
| 443 void NativeStackSamplerWin::ProfileRecordingStarting( | 454 void NativeStackSamplerWin::ProfileRecordingStarting( |
| 444 std::vector<StackSamplingProfiler::Module>* modules) { | 455 std::vector<StackSamplingProfiler::Module>* modules) { |
| 445 current_modules_ = modules; | 456 current_modules_ = modules; |
| 446 profile_module_index_.clear(); | 457 profile_module_index_.clear(); |
| 447 } | 458 } |
| 448 | 459 |
| 449 void NativeStackSamplerWin::RecordStackSample( | 460 void NativeStackSamplerWin::RecordStackSample( |
| 450 StackSamplingProfiler::Sample* sample) { | 461 StackSamplingProfiler::Sample* sample) { |
| 451 DCHECK(current_modules_); | 462 DCHECK(current_modules_); |
| 452 | 463 |
| 453 if (!stack_copy_buffer_) | 464 if (!stack_copy_buffer_) |
| 454 return; | 465 return; |
| 455 | 466 |
| 456 std::vector<RecordedFrame> stack; | 467 std::vector<RecordedFrame> stack; |
| 457 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, | 468 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, |
| 458 stack_copy_buffer_.get(), kStackCopyBufferSize, | 469 stack_copy_buffer_.get(), kStackCopyBufferSize, |
| 459 &stack, test_delegate_); | 470 &stack, annotator_, sample, test_delegate_); |
| 460 CopyToSample(stack, sample, current_modules_); | 471 CopyToSample(stack, sample, current_modules_); |
| 461 } | 472 } |
| 462 | 473 |
| 463 void NativeStackSamplerWin::ProfileRecordingStopped() { | 474 void NativeStackSamplerWin::ProfileRecordingStopped() { |
| 464 current_modules_ = nullptr; | 475 current_modules_ = nullptr; |
| 465 } | 476 } |
| 466 | 477 |
| 467 // static | 478 // static |
| 468 bool NativeStackSamplerWin::GetModuleForHandle( | 479 bool NativeStackSamplerWin::GetModuleForHandle( |
| 469 HMODULE module_handle, | 480 HMODULE module_handle, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 module_handle, modules->size() - 1)).first; | 512 module_handle, modules->size() - 1)).first; |
| 502 } | 513 } |
| 503 | 514 |
| 504 return loc->second; | 515 return loc->second; |
| 505 } | 516 } |
| 506 | 517 |
| 507 void NativeStackSamplerWin::CopyToSample( | 518 void NativeStackSamplerWin::CopyToSample( |
| 508 const std::vector<RecordedFrame>& stack, | 519 const std::vector<RecordedFrame>& stack, |
| 509 StackSamplingProfiler::Sample* sample, | 520 StackSamplingProfiler::Sample* sample, |
| 510 std::vector<StackSamplingProfiler::Module>* modules) { | 521 std::vector<StackSamplingProfiler::Module>* modules) { |
| 511 sample->clear(); | 522 sample->frames.clear(); |
| 512 sample->reserve(stack.size()); | 523 sample->frames.reserve(stack.size()); |
| 513 | 524 |
| 514 for (const RecordedFrame& frame : stack) { | 525 for (const RecordedFrame& frame : stack) { |
| 515 sample->push_back(StackSamplingProfiler::Frame( | 526 sample->frames.push_back(StackSamplingProfiler::Frame( |
| 516 reinterpret_cast<uintptr_t>(frame.instruction_pointer), | 527 reinterpret_cast<uintptr_t>(frame.instruction_pointer), |
| 517 GetModuleIndex(frame.module.Get(), modules))); | 528 GetModuleIndex(frame.module.Get(), modules))); |
| 518 } | 529 } |
| 519 } | 530 } |
| 520 | 531 |
| 521 } // namespace | 532 } // namespace |
| 522 | 533 |
| 523 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( | 534 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( |
| 524 PlatformThreadId thread_id, | 535 PlatformThreadId thread_id, |
| 536 AnnotateCallback annotator, |
| 525 NativeStackSamplerTestDelegate* test_delegate) { | 537 NativeStackSamplerTestDelegate* test_delegate) { |
| 526 #if _WIN64 | 538 #if _WIN64 |
| 527 // Get the thread's handle. | 539 // Get the thread's handle. |
| 528 HANDLE thread_handle = ::OpenThread( | 540 HANDLE thread_handle = ::OpenThread( |
| 529 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, | 541 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, |
| 530 FALSE, | 542 FALSE, |
| 531 thread_id); | 543 thread_id); |
| 532 | 544 |
| 533 if (thread_handle) { | 545 if (thread_handle) { |
| 534 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( | 546 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( |
| 535 win::ScopedHandle(thread_handle), test_delegate)); | 547 win::ScopedHandle(thread_handle), annotator, test_delegate)); |
| 536 } | 548 } |
| 537 #endif | 549 #endif |
| 538 return std::unique_ptr<NativeStackSampler>(); | 550 return std::unique_ptr<NativeStackSampler>(); |
| 539 } | 551 } |
| 540 | 552 |
| 541 } // namespace base | 553 } // namespace base |
| OLD | NEW |