| 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/lazy_instance.h" | 18 #include "base/lazy_instance.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/macros.h" | 20 #include "base/macros.h" |
| 21 #include "base/memory/ptr_util.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" |
| 28 | 29 |
| 29 namespace base { | 30 namespace base { |
| 30 | 31 |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 | 380 |
| 380 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); | 381 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); |
| 381 | 382 |
| 382 RecordStack(&thread_context, stack); | 383 RecordStack(&thread_context, stack); |
| 383 } | 384 } |
| 384 | 385 |
| 385 // NativeStackSamplerWin ------------------------------------------------------ | 386 // NativeStackSamplerWin ------------------------------------------------------ |
| 386 | 387 |
| 387 class NativeStackSamplerWin : public NativeStackSampler { | 388 class NativeStackSamplerWin : public NativeStackSampler { |
| 388 public: | 389 public: |
| 390 enum { |
| 391 // Intended to hold the largest stack used by Chrome. The default Win32 |
| 392 // reserved stack size is 1 MB and Chrome Windows threads currently always |
| 393 // use the default, but this allows for expansion if it occurs. The size |
| 394 // beyond the actual stack size consists of unallocated virtual memory pages |
| 395 // so carries little cost (just a bit of wasted address space). |
| 396 kStackCopyBufferSize = 2 * 1024 * 1024 |
| 397 }; |
| 398 |
| 399 class StackBufferWin : public StackBuffer { |
| 400 public: |
| 401 StackBufferWin() {} |
| 402 ~StackBufferWin() override {} |
| 403 |
| 404 // Buffer to use for copies of the stack. |
| 405 unsigned char stack_copy_buffer_[kStackCopyBufferSize]; |
| 406 }; |
| 407 |
| 389 NativeStackSamplerWin(win::ScopedHandle thread_handle, | 408 NativeStackSamplerWin(win::ScopedHandle thread_handle, |
| 390 AnnotateCallback annotator, | 409 AnnotateCallback annotator, |
| 391 NativeStackSamplerTestDelegate* test_delegate); | 410 NativeStackSamplerTestDelegate* test_delegate); |
| 392 ~NativeStackSamplerWin() override; | 411 ~NativeStackSamplerWin() override; |
| 393 | 412 |
| 394 // StackSamplingProfiler::NativeStackSampler: | 413 // StackSamplingProfiler::NativeStackSampler: |
| 395 void ProfileRecordingStarting( | 414 void ProfileRecordingStarting( |
| 396 std::vector<StackSamplingProfiler::Module>* modules) override; | 415 std::vector<StackSamplingProfiler::Module>* modules) override; |
| 397 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; | 416 void RecordStackSample(StackBuffer* stackbuffer, |
| 398 void ProfileRecordingStopped() override; | 417 StackSamplingProfiler::Sample* sample) override; |
| 418 void ProfileRecordingStopped(StackBuffer* stackbuffer) override; |
| 399 | 419 |
| 400 private: | 420 private: |
| 401 enum { | |
| 402 // Intended to hold the largest stack used by Chrome. The default Win32 | |
| 403 // reserved stack size is 1 MB and Chrome Windows threads currently always | |
| 404 // use the default, but this allows for expansion if it occurs. The size | |
| 405 // beyond the actual stack size consists of unallocated virtual memory pages | |
| 406 // so carries little cost (just a bit of wasted address space). | |
| 407 kStackCopyBufferSize = 2 * 1024 * 1024 | |
| 408 }; | |
| 409 | |
| 410 // Attempts to query the module filename, base address, and id for | 421 // Attempts to query the module filename, base address, and id for |
| 411 // |module_handle|, and store them in |module|. Returns true if it succeeded. | 422 // |module_handle|, and store them in |module|. Returns true if it succeeded. |
| 412 static bool GetModuleForHandle(HMODULE module_handle, | 423 static bool GetModuleForHandle(HMODULE module_handle, |
| 413 StackSamplingProfiler::Module* module); | 424 StackSamplingProfiler::Module* module); |
| 414 | 425 |
| 415 // Gets the index for the Module corresponding to |module_handle| in | 426 // Gets the index for the Module corresponding to |module_handle| in |
| 416 // |modules|, adding it if it's not already present. Returns | 427 // |modules|, adding it if it's not already present. Returns |
| 417 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be | 428 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be |
| 418 // determined for |module|. | 429 // determined for |module|. |
| 419 size_t GetModuleIndex(HMODULE module_handle, | 430 size_t GetModuleIndex(HMODULE module_handle, |
| 420 std::vector<StackSamplingProfiler::Module>* modules); | 431 std::vector<StackSamplingProfiler::Module>* modules); |
| 421 | 432 |
| 422 // Copies the information represented by |stack| into |sample| and |modules|. | 433 // Copies the information represented by |stack| into |sample| and |modules|. |
| 423 void CopyToSample(const std::vector<RecordedFrame>& stack, | 434 void CopyToSample(const std::vector<RecordedFrame>& stack, |
| 424 StackSamplingProfiler::Sample* sample, | 435 StackSamplingProfiler::Sample* sample, |
| 425 std::vector<StackSamplingProfiler::Module>* modules); | 436 std::vector<StackSamplingProfiler::Module>* modules); |
| 426 | 437 |
| 427 win::ScopedHandle thread_handle_; | 438 win::ScopedHandle thread_handle_; |
| 428 | 439 |
| 429 const AnnotateCallback annotator_; | 440 const AnnotateCallback annotator_; |
| 430 | 441 |
| 431 NativeStackSamplerTestDelegate* const test_delegate_; | 442 NativeStackSamplerTestDelegate* const test_delegate_; |
| 432 | 443 |
| 433 // The stack base address corresponding to |thread_handle_|. | 444 // The stack base address corresponding to |thread_handle_|. |
| 434 const void* const thread_stack_base_address_; | 445 const void* const thread_stack_base_address_; |
| 435 | 446 |
| 436 // Buffer to use for copies of the stack. We use the same buffer for all the | |
| 437 // samples to avoid the overhead of multiple allocations and frees. | |
| 438 const std::unique_ptr<unsigned char[]> stack_copy_buffer_; | |
| 439 | |
| 440 // Weak. Points to the modules associated with the profile being recorded | 447 // Weak. Points to the modules associated with the profile being recorded |
| 441 // between ProfileRecordingStarting() and ProfileRecordingStopped(). | 448 // between ProfileRecordingStarting() and ProfileRecordingStopped(). |
| 442 std::vector<StackSamplingProfiler::Module>* current_modules_; | 449 std::vector<StackSamplingProfiler::Module>* current_modules_; |
| 443 | 450 |
| 444 // Maps a module handle to the corresponding Module's index within | 451 // Maps a module handle to the corresponding Module's index within |
| 445 // current_modules_. | 452 // current_modules_. |
| 446 std::map<HMODULE, size_t> profile_module_index_; | 453 std::map<HMODULE, size_t> profile_module_index_; |
| 447 | 454 |
| 448 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); | 455 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); |
| 449 }; | 456 }; |
| 450 | 457 |
| 451 NativeStackSamplerWin::NativeStackSamplerWin( | 458 NativeStackSamplerWin::NativeStackSamplerWin( |
| 452 win::ScopedHandle thread_handle, | 459 win::ScopedHandle thread_handle, |
| 453 AnnotateCallback annotator, | 460 AnnotateCallback annotator, |
| 454 NativeStackSamplerTestDelegate* test_delegate) | 461 NativeStackSamplerTestDelegate* test_delegate) |
| 455 : thread_handle_(thread_handle.Take()), | 462 : thread_handle_(thread_handle.Take()), |
| 456 annotator_(annotator), | 463 annotator_(annotator), |
| 457 test_delegate_(test_delegate), | 464 test_delegate_(test_delegate), |
| 458 thread_stack_base_address_( | 465 thread_stack_base_address_( |
| 459 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), | 466 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase) { |
| 460 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { | |
| 461 DCHECK(annotator_); | 467 DCHECK(annotator_); |
| 462 } | 468 } |
| 463 | 469 |
| 464 NativeStackSamplerWin::~NativeStackSamplerWin() { | 470 NativeStackSamplerWin::~NativeStackSamplerWin() { |
| 465 } | 471 } |
| 466 | 472 |
| 467 void NativeStackSamplerWin::ProfileRecordingStarting( | 473 void NativeStackSamplerWin::ProfileRecordingStarting( |
| 468 std::vector<StackSamplingProfiler::Module>* modules) { | 474 std::vector<StackSamplingProfiler::Module>* modules) { |
| 469 current_modules_ = modules; | 475 current_modules_ = modules; |
| 470 profile_module_index_.clear(); | 476 profile_module_index_.clear(); |
| 471 } | 477 } |
| 472 | 478 |
| 473 void NativeStackSamplerWin::RecordStackSample( | 479 void NativeStackSamplerWin::RecordStackSample( |
| 480 StackBuffer* stackbuffer, |
| 474 StackSamplingProfiler::Sample* sample) { | 481 StackSamplingProfiler::Sample* sample) { |
| 482 DCHECK(stackbuffer); |
| 475 DCHECK(current_modules_); | 483 DCHECK(current_modules_); |
| 476 | 484 |
| 477 if (!stack_copy_buffer_) | |
| 478 return; | |
| 479 | |
| 480 std::vector<RecordedFrame> stack; | 485 std::vector<RecordedFrame> stack; |
| 481 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, | 486 SuspendThreadAndRecordStack( |
| 482 stack_copy_buffer_.get(), kStackCopyBufferSize, | 487 thread_handle_.Get(), thread_stack_base_address_, |
| 483 &stack, annotator_, sample, test_delegate_); | 488 static_cast<StackBufferWin*>(stackbuffer)->stack_copy_buffer_, |
| 489 kStackCopyBufferSize, &stack, annotator_, sample, test_delegate_); |
| 484 CopyToSample(stack, sample, current_modules_); | 490 CopyToSample(stack, sample, current_modules_); |
| 485 } | 491 } |
| 486 | 492 |
| 487 void NativeStackSamplerWin::ProfileRecordingStopped() { | 493 void NativeStackSamplerWin::ProfileRecordingStopped(StackBuffer* stackbuffer) { |
| 488 current_modules_ = nullptr; | 494 current_modules_ = nullptr; |
| 489 } | 495 } |
| 490 | 496 |
| 491 // static | 497 // static |
| 492 bool NativeStackSamplerWin::GetModuleForHandle( | 498 bool NativeStackSamplerWin::GetModuleForHandle( |
| 493 HMODULE module_handle, | 499 HMODULE module_handle, |
| 494 StackSamplingProfiler::Module* module) { | 500 StackSamplingProfiler::Module* module) { |
| 495 wchar_t module_name[MAX_PATH]; | 501 wchar_t module_name[MAX_PATH]; |
| 496 DWORD result_length = | 502 DWORD result_length = |
| 497 GetModuleFileName(module_handle, module_name, arraysize(module_name)); | 503 GetModuleFileName(module_handle, module_name, arraysize(module_name)); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 thread_id); | 562 thread_id); |
| 557 | 563 |
| 558 if (thread_handle) { | 564 if (thread_handle) { |
| 559 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( | 565 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( |
| 560 win::ScopedHandle(thread_handle), annotator, test_delegate)); | 566 win::ScopedHandle(thread_handle), annotator, test_delegate)); |
| 561 } | 567 } |
| 562 #endif | 568 #endif |
| 563 return std::unique_ptr<NativeStackSampler>(); | 569 return std::unique_ptr<NativeStackSampler>(); |
| 564 } | 570 } |
| 565 | 571 |
| 572 std::unique_ptr<NativeStackSampler::StackBuffer> |
| 573 NativeStackSampler::CreateStackBuffer() { |
| 574 return MakeUnique<NativeStackSamplerWin::StackBufferWin>(); |
| 575 } |
| 576 |
| 566 } // namespace base | 577 } // namespace base |
| OLD | NEW |