| 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 DCHECK(annotator); |
| 359 (*annotator)(sample); |
| 360 |
| 356 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom), | 361 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom), |
| 357 top - bottom); | 362 top - bottom); |
| 358 } | 363 } |
| 359 | 364 |
| 360 if (test_delegate) | 365 if (test_delegate) |
| 361 test_delegate->OnPreStackWalk(); | 366 test_delegate->OnPreStackWalk(); |
| 362 | 367 |
| 363 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); | 368 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); |
| 364 | 369 |
| 365 RecordStack(&thread_context, stack); | 370 RecordStack(&thread_context, stack); |
| 366 } | 371 } |
| 367 | 372 |
| 368 // NativeStackSamplerWin ------------------------------------------------------ | 373 // NativeStackSamplerWin ------------------------------------------------------ |
| 369 | 374 |
| 370 class NativeStackSamplerWin : public NativeStackSampler { | 375 class NativeStackSamplerWin : public NativeStackSampler { |
| 371 public: | 376 public: |
| 372 NativeStackSamplerWin(win::ScopedHandle thread_handle, | 377 NativeStackSamplerWin(win::ScopedHandle thread_handle, |
| 378 AnnotateCallback annotator, |
| 373 NativeStackSamplerTestDelegate* test_delegate); | 379 NativeStackSamplerTestDelegate* test_delegate); |
| 374 ~NativeStackSamplerWin() override; | 380 ~NativeStackSamplerWin() override; |
| 375 | 381 |
| 376 // StackSamplingProfiler::NativeStackSampler: | 382 // StackSamplingProfiler::NativeStackSampler: |
| 377 void ProfileRecordingStarting( | 383 void ProfileRecordingStarting( |
| 378 std::vector<StackSamplingProfiler::Module>* modules) override; | 384 std::vector<StackSamplingProfiler::Module>* modules) override; |
| 379 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; | 385 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; |
| 380 void ProfileRecordingStopped() override; | 386 void ProfileRecordingStopped() override; |
| 381 | 387 |
| 382 private: | 388 private: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 401 size_t GetModuleIndex(HMODULE module_handle, | 407 size_t GetModuleIndex(HMODULE module_handle, |
| 402 std::vector<StackSamplingProfiler::Module>* modules); | 408 std::vector<StackSamplingProfiler::Module>* modules); |
| 403 | 409 |
| 404 // Copies the information represented by |stack| into |sample| and |modules|. | 410 // Copies the information represented by |stack| into |sample| and |modules|. |
| 405 void CopyToSample(const std::vector<RecordedFrame>& stack, | 411 void CopyToSample(const std::vector<RecordedFrame>& stack, |
| 406 StackSamplingProfiler::Sample* sample, | 412 StackSamplingProfiler::Sample* sample, |
| 407 std::vector<StackSamplingProfiler::Module>* modules); | 413 std::vector<StackSamplingProfiler::Module>* modules); |
| 408 | 414 |
| 409 win::ScopedHandle thread_handle_; | 415 win::ScopedHandle thread_handle_; |
| 410 | 416 |
| 417 const AnnotateCallback annotator_; |
| 418 |
| 411 NativeStackSamplerTestDelegate* const test_delegate_; | 419 NativeStackSamplerTestDelegate* const test_delegate_; |
| 412 | 420 |
| 413 // The stack base address corresponding to |thread_handle_|. | 421 // The stack base address corresponding to |thread_handle_|. |
| 414 const void* const thread_stack_base_address_; | 422 const void* const thread_stack_base_address_; |
| 415 | 423 |
| 416 // Buffer to use for copies of the stack. We use the same buffer for all the | 424 // 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. | 425 // samples to avoid the overhead of multiple allocations and frees. |
| 418 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; | 426 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; |
| 419 | 427 |
| 420 // Weak. Points to the modules associated with the profile being recorded | 428 // Weak. Points to the modules associated with the profile being recorded |
| 421 // between ProfileRecordingStarting() and ProfileRecordingStopped(). | 429 // between ProfileRecordingStarting() and ProfileRecordingStopped(). |
| 422 std::vector<StackSamplingProfiler::Module>* current_modules_; | 430 std::vector<StackSamplingProfiler::Module>* current_modules_; |
| 423 | 431 |
| 424 // Maps a module handle to the corresponding Module's index within | 432 // Maps a module handle to the corresponding Module's index within |
| 425 // current_modules_. | 433 // current_modules_. |
| 426 std::map<HMODULE, size_t> profile_module_index_; | 434 std::map<HMODULE, size_t> profile_module_index_; |
| 427 | 435 |
| 428 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); | 436 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); |
| 429 }; | 437 }; |
| 430 | 438 |
| 431 NativeStackSamplerWin::NativeStackSamplerWin( | 439 NativeStackSamplerWin::NativeStackSamplerWin( |
| 432 win::ScopedHandle thread_handle, | 440 win::ScopedHandle thread_handle, |
| 441 AnnotateCallback annotator, |
| 433 NativeStackSamplerTestDelegate* test_delegate) | 442 NativeStackSamplerTestDelegate* test_delegate) |
| 434 : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate), | 443 : thread_handle_(thread_handle.Take()), |
| 444 annotator_(annotator), |
| 445 test_delegate_(test_delegate), |
| 435 thread_stack_base_address_( | 446 thread_stack_base_address_( |
| 436 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), | 447 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), |
| 437 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { | 448 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { |
| 449 DCHECK(annotator_); |
| 438 } | 450 } |
| 439 | 451 |
| 440 NativeStackSamplerWin::~NativeStackSamplerWin() { | 452 NativeStackSamplerWin::~NativeStackSamplerWin() { |
| 441 } | 453 } |
| 442 | 454 |
| 443 void NativeStackSamplerWin::ProfileRecordingStarting( | 455 void NativeStackSamplerWin::ProfileRecordingStarting( |
| 444 std::vector<StackSamplingProfiler::Module>* modules) { | 456 std::vector<StackSamplingProfiler::Module>* modules) { |
| 445 current_modules_ = modules; | 457 current_modules_ = modules; |
| 446 profile_module_index_.clear(); | 458 profile_module_index_.clear(); |
| 447 } | 459 } |
| 448 | 460 |
| 449 void NativeStackSamplerWin::RecordStackSample( | 461 void NativeStackSamplerWin::RecordStackSample( |
| 450 StackSamplingProfiler::Sample* sample) { | 462 StackSamplingProfiler::Sample* sample) { |
| 451 DCHECK(current_modules_); | 463 DCHECK(current_modules_); |
| 452 | 464 |
| 453 if (!stack_copy_buffer_) | 465 if (!stack_copy_buffer_) |
| 454 return; | 466 return; |
| 455 | 467 |
| 456 std::vector<RecordedFrame> stack; | 468 std::vector<RecordedFrame> stack; |
| 457 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, | 469 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, |
| 458 stack_copy_buffer_.get(), kStackCopyBufferSize, | 470 stack_copy_buffer_.get(), kStackCopyBufferSize, |
| 459 &stack, test_delegate_); | 471 &stack, annotator_, sample, test_delegate_); |
| 460 CopyToSample(stack, sample, current_modules_); | 472 CopyToSample(stack, sample, current_modules_); |
| 461 } | 473 } |
| 462 | 474 |
| 463 void NativeStackSamplerWin::ProfileRecordingStopped() { | 475 void NativeStackSamplerWin::ProfileRecordingStopped() { |
| 464 current_modules_ = nullptr; | 476 current_modules_ = nullptr; |
| 465 } | 477 } |
| 466 | 478 |
| 467 // static | 479 // static |
| 468 bool NativeStackSamplerWin::GetModuleForHandle( | 480 bool NativeStackSamplerWin::GetModuleForHandle( |
| 469 HMODULE module_handle, | 481 HMODULE module_handle, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 module_handle, modules->size() - 1)).first; | 513 module_handle, modules->size() - 1)).first; |
| 502 } | 514 } |
| 503 | 515 |
| 504 return loc->second; | 516 return loc->second; |
| 505 } | 517 } |
| 506 | 518 |
| 507 void NativeStackSamplerWin::CopyToSample( | 519 void NativeStackSamplerWin::CopyToSample( |
| 508 const std::vector<RecordedFrame>& stack, | 520 const std::vector<RecordedFrame>& stack, |
| 509 StackSamplingProfiler::Sample* sample, | 521 StackSamplingProfiler::Sample* sample, |
| 510 std::vector<StackSamplingProfiler::Module>* modules) { | 522 std::vector<StackSamplingProfiler::Module>* modules) { |
| 511 sample->clear(); | 523 sample->frames.clear(); |
| 512 sample->reserve(stack.size()); | 524 sample->frames.reserve(stack.size()); |
| 513 | 525 |
| 514 for (const RecordedFrame& frame : stack) { | 526 for (const RecordedFrame& frame : stack) { |
| 515 sample->push_back(StackSamplingProfiler::Frame( | 527 sample->frames.push_back(StackSamplingProfiler::Frame( |
| 516 reinterpret_cast<uintptr_t>(frame.instruction_pointer), | 528 reinterpret_cast<uintptr_t>(frame.instruction_pointer), |
| 517 GetModuleIndex(frame.module.Get(), modules))); | 529 GetModuleIndex(frame.module.Get(), modules))); |
| 518 } | 530 } |
| 519 } | 531 } |
| 520 | 532 |
| 521 } // namespace | 533 } // namespace |
| 522 | 534 |
| 523 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( | 535 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( |
| 524 PlatformThreadId thread_id, | 536 PlatformThreadId thread_id, |
| 537 AnnotateCallback annotator, |
| 525 NativeStackSamplerTestDelegate* test_delegate) { | 538 NativeStackSamplerTestDelegate* test_delegate) { |
| 526 #if _WIN64 | 539 #if _WIN64 |
| 527 // Get the thread's handle. | 540 // Get the thread's handle. |
| 528 HANDLE thread_handle = ::OpenThread( | 541 HANDLE thread_handle = ::OpenThread( |
| 529 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, | 542 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, |
| 530 FALSE, | 543 FALSE, |
| 531 thread_id); | 544 thread_id); |
| 532 | 545 |
| 533 if (thread_handle) { | 546 if (thread_handle) { |
| 534 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( | 547 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( |
| 535 win::ScopedHandle(thread_handle), test_delegate)); | 548 win::ScopedHandle(thread_handle), annotator, test_delegate)); |
| 536 } | 549 } |
| 537 #endif | 550 #endif |
| 538 return std::unique_ptr<NativeStackSampler>(); | 551 return std::unique_ptr<NativeStackSampler>(); |
| 539 } | 552 } |
| 540 | 553 |
| 541 } // namespace base | 554 } // namespace base |
| OLD | NEW |