Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: base/profiler/native_stack_sampler_win.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: addressed review comments by wittman Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
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
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 Closure annotator,
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
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.Run();
Mike Wittman 2016/10/26 16:28:17 Invoking Callback::Run while the thread is suspend
bcwhite 2016/10/26 18:30:43 Good point. We can document this code to say what
Mike Wittman 2016/10/26 19:41:14 That would work, but it would couple the implement
bcwhite 2016/10/26 20:02:10 It might be possible to just make it testable via
Mike Wittman 2016/10/26 20:20:36 That's reasonable, although I feel like this may b
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 StackSamplingProfiler::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
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 StackSamplingProfiler::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 StackSamplingProfiler::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]) {
438 } 448 }
439 449
440 NativeStackSamplerWin::~NativeStackSamplerWin() { 450 NativeStackSamplerWin::~NativeStackSamplerWin() {
441 } 451 }
442 452
443 void NativeStackSamplerWin::ProfileRecordingStarting( 453 void NativeStackSamplerWin::ProfileRecordingStarting(
444 std::vector<StackSamplingProfiler::Module>* modules) { 454 std::vector<StackSamplingProfiler::Module>* modules) {
445 current_modules_ = modules; 455 current_modules_ = modules;
446 profile_module_index_.clear(); 456 profile_module_index_.clear();
447 } 457 }
448 458
449 void NativeStackSamplerWin::RecordStackSample( 459 void NativeStackSamplerWin::RecordStackSample(
450 StackSamplingProfiler::Sample* sample) { 460 StackSamplingProfiler::Sample* sample) {
451 DCHECK(current_modules_); 461 DCHECK(current_modules_);
452 462
453 if (!stack_copy_buffer_) 463 if (!stack_copy_buffer_)
454 return; 464 return;
455 465
456 std::vector<RecordedFrame> stack; 466 std::vector<RecordedFrame> stack;
457 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, 467 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_,
458 stack_copy_buffer_.get(), kStackCopyBufferSize, 468 stack_copy_buffer_.get(), kStackCopyBufferSize,
459 &stack, test_delegate_); 469 &stack, Bind(annotator_, sample), test_delegate_);
460 CopyToSample(stack, sample, current_modules_); 470 CopyToSample(stack, sample, current_modules_);
461 } 471 }
462 472
463 void NativeStackSamplerWin::ProfileRecordingStopped() { 473 void NativeStackSamplerWin::ProfileRecordingStopped() {
464 current_modules_ = nullptr; 474 current_modules_ = nullptr;
465 } 475 }
466 476
467 // static 477 // static
468 bool NativeStackSamplerWin::GetModuleForHandle( 478 bool NativeStackSamplerWin::GetModuleForHandle(
469 HMODULE module_handle, 479 HMODULE module_handle,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 module_handle, modules->size() - 1)).first; 511 module_handle, modules->size() - 1)).first;
502 } 512 }
503 513
504 return loc->second; 514 return loc->second;
505 } 515 }
506 516
507 void NativeStackSamplerWin::CopyToSample( 517 void NativeStackSamplerWin::CopyToSample(
508 const std::vector<RecordedFrame>& stack, 518 const std::vector<RecordedFrame>& stack,
509 StackSamplingProfiler::Sample* sample, 519 StackSamplingProfiler::Sample* sample,
510 std::vector<StackSamplingProfiler::Module>* modules) { 520 std::vector<StackSamplingProfiler::Module>* modules) {
511 sample->clear(); 521 sample->frames.clear();
512 sample->reserve(stack.size()); 522 sample->frames.reserve(stack.size());
513 523
514 for (const RecordedFrame& frame : stack) { 524 for (const RecordedFrame& frame : stack) {
515 sample->push_back(StackSamplingProfiler::Frame( 525 sample->frames.push_back(StackSamplingProfiler::Frame(
516 reinterpret_cast<uintptr_t>(frame.instruction_pointer), 526 reinterpret_cast<uintptr_t>(frame.instruction_pointer),
517 GetModuleIndex(frame.module.Get(), modules))); 527 GetModuleIndex(frame.module.Get(), modules)));
518 } 528 }
519 } 529 }
520 530
521 } // namespace 531 } // namespace
522 532
523 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( 533 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
524 PlatformThreadId thread_id, 534 PlatformThreadId thread_id,
535 StackSamplingProfiler::AnnotateCallback annotator,
525 NativeStackSamplerTestDelegate* test_delegate) { 536 NativeStackSamplerTestDelegate* test_delegate) {
526 #if _WIN64 537 #if _WIN64
527 // Get the thread's handle. 538 // Get the thread's handle.
528 HANDLE thread_handle = ::OpenThread( 539 HANDLE thread_handle = ::OpenThread(
529 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, 540 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
530 FALSE, 541 FALSE,
531 thread_id); 542 thread_id);
532 543
533 if (thread_handle) { 544 if (thread_handle) {
534 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( 545 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin(
535 win::ScopedHandle(thread_handle), test_delegate)); 546 win::ScopedHandle(thread_handle), annotator, test_delegate));
536 } 547 }
537 #endif 548 #endif
538 return std::unique_ptr<NativeStackSampler>(); 549 return std::unique_ptr<NativeStackSampler>();
539 } 550 }
540 551
541 } // namespace base 552 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698