Chromium Code Reviews| 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> |
| 11 | 11 |
| 12 #include <cstdlib> | 12 #include <cstdlib> |
| 13 #include <map> | 13 #include <map> |
| 14 #include <memory> | 14 #include <memory> |
| 15 #include <utility> | 15 #include <utility> |
| 16 #include <vector> | 16 #include <vector> |
| 17 | 17 |
| 18 #include "base/bind.h" | |
|
Mike Wittman
2016/11/02 21:44:04
This can be removed.
bcwhite
2016/11/03 18:29:49
Done.
| |
| 18 #include "base/lazy_instance.h" | 19 #include "base/lazy_instance.h" |
| 19 #include "base/logging.h" | 20 #include "base/logging.h" |
| 20 #include "base/macros.h" | 21 #include "base/macros.h" |
| 21 #include "base/profiler/win32_stack_frame_unwinder.h" | 22 #include "base/profiler/win32_stack_frame_unwinder.h" |
| 22 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 23 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 24 #include "base/strings/utf_string_conversions.h" | 25 #include "base/strings/utf_string_conversions.h" |
| 25 #include "base/time/time.h" | 26 #include "base/time/time.h" |
| 26 #include "base/win/pe_image.h" | 27 #include "base/win/pe_image.h" |
| 27 #include "base/win/scoped_handle.h" | 28 #include "base/win/scoped_handle.h" |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 // IMPORTANT NOTE: No allocations from the default heap may occur in the | 313 // IMPORTANT NOTE: No allocations from the default heap may occur in the |
| 313 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or | 314 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or |
| 314 // other logging statements. Otherwise this code can deadlock on heap locks in | 315 // 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. | 316 // the default heap acquired by the target thread before it was suspended. |
| 316 void SuspendThreadAndRecordStack( | 317 void SuspendThreadAndRecordStack( |
| 317 HANDLE thread_handle, | 318 HANDLE thread_handle, |
| 318 const void* base_address, | 319 const void* base_address, |
| 319 void* stack_copy_buffer, | 320 void* stack_copy_buffer, |
| 320 size_t stack_copy_buffer_size, | 321 size_t stack_copy_buffer_size, |
| 321 std::vector<RecordedFrame>* stack, | 322 std::vector<RecordedFrame>* stack, |
| 323 NativeStackSampler::AnnotateCallback annotator, | |
| 324 StackSamplingProfiler::Sample* sample, | |
| 322 NativeStackSamplerTestDelegate* test_delegate) { | 325 NativeStackSamplerTestDelegate* test_delegate) { |
| 323 DCHECK(stack->empty()); | 326 DCHECK(stack->empty()); |
| 324 | 327 |
| 325 CONTEXT thread_context = {0}; | 328 CONTEXT thread_context = {0}; |
| 326 thread_context.ContextFlags = CONTEXT_FULL; | 329 thread_context.ContextFlags = CONTEXT_FULL; |
| 327 // The stack bounds are saved to uintptr_ts for use outside | 330 // The stack bounds are saved to uintptr_ts for use outside |
| 328 // ScopedSuspendThread, as the thread's memory is not safe to dereference | 331 // ScopedSuspendThread, as the thread's memory is not safe to dereference |
| 329 // beyond that point. | 332 // beyond that point. |
| 330 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); | 333 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); |
| 331 uintptr_t bottom = 0u; | 334 uintptr_t bottom = 0u; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 346 | 349 |
| 347 if ((top - bottom) > stack_copy_buffer_size) | 350 if ((top - bottom) > stack_copy_buffer_size) |
| 348 return; | 351 return; |
| 349 | 352 |
| 350 // Dereferencing a pointer in the guard page in a thread that doesn't own | 353 // 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. | 354 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. |
| 352 // This occurs very rarely, but reliably over the population. | 355 // This occurs very rarely, but reliably over the population. |
| 353 if (PointsToGuardPage(bottom)) | 356 if (PointsToGuardPage(bottom)) |
| 354 return; | 357 return; |
| 355 | 358 |
| 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]) { |
| 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 |