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

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

Issue 2554123002: Support parallel captures from the StackSamplingProfiler. (Closed)
Patch Set: merged synchronized-stop CL Created 3 years, 10 months 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>
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 return result != 0 && (memory_info.Protect & PAGE_GUARD); 319 return result != 0 && (memory_info.Protect & PAGE_GUARD);
320 } 320 }
321 321
322 // Suspends the thread with |thread_handle|, copies its stack and resumes the 322 // Suspends the thread with |thread_handle|, copies its stack and resumes the
323 // thread, then records the stack frames and associated modules into |stack|. 323 // thread, then records the stack frames and associated modules into |stack|.
324 // 324 //
325 // IMPORTANT NOTE: No allocations from the default heap may occur in the 325 // IMPORTANT NOTE: No allocations from the default heap may occur in the
326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or 326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
327 // other logging statements. Otherwise this code can deadlock on heap locks in 327 // other logging statements. Otherwise this code can deadlock on heap locks in
328 // the default heap acquired by the target thread before it was suspended. 328 // the default heap acquired by the target thread before it was suspended.
329 void SuspendThreadAndRecordStack( 329 NativeStackSampler::ThreadState SuspendThreadAndRecordStack(
330 HANDLE thread_handle, 330 HANDLE thread_handle,
331 const void* base_address, 331 const void* base_address,
332 void* stack_copy_buffer, 332 void* stack_copy_buffer,
333 size_t stack_copy_buffer_size, 333 size_t stack_copy_buffer_size,
334 std::vector<RecordedFrame>* stack, 334 std::vector<RecordedFrame>* stack,
335 NativeStackSampler::AnnotateCallback annotator, 335 NativeStackSampler::AnnotateCallback annotator,
336 StackSamplingProfiler::Sample* sample, 336 StackSamplingProfiler::Sample* sample,
337 NativeStackSamplerTestDelegate* test_delegate) { 337 NativeStackSamplerTestDelegate* test_delegate) {
338 DCHECK(stack->empty()); 338 DCHECK(stack->empty());
339 339
340 CONTEXT thread_context = {0}; 340 CONTEXT thread_context = {0};
341 thread_context.ContextFlags = CONTEXT_FULL; 341 thread_context.ContextFlags = CONTEXT_FULL;
342 // The stack bounds are saved to uintptr_ts for use outside 342 // The stack bounds are saved to uintptr_ts for use outside
343 // ScopedSuspendThread, as the thread's memory is not safe to dereference 343 // ScopedSuspendThread, as the thread's memory is not safe to dereference
344 // beyond that point. 344 // beyond that point.
345 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); 345 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
346 uintptr_t bottom = 0u; 346 uintptr_t bottom = 0u;
347 347
348 { 348 {
349 ScopedSuspendThread suspend_thread(thread_handle); 349 ScopedSuspendThread suspend_thread(thread_handle);
350 350
351 if (!suspend_thread.was_successful()) 351 if (!suspend_thread.was_successful())
352 return; 352 return NativeStackSampler::THREAD_UNSUSPENDABLE;
353 353
354 if (!::GetThreadContext(thread_handle, &thread_context)) 354 if (!::GetThreadContext(thread_handle, &thread_context))
355 return; 355 return NativeStackSampler::THREAD_NO_INFO;
356
356 #if defined(_WIN64) 357 #if defined(_WIN64)
357 bottom = thread_context.Rsp; 358 bottom = thread_context.Rsp;
358 #else 359 #else
359 bottom = thread_context.Esp; 360 bottom = thread_context.Esp;
360 #endif 361 #endif
361 362
362 if ((top - bottom) > stack_copy_buffer_size) 363 if ((top - bottom) > stack_copy_buffer_size)
363 return; 364 return NativeStackSampler::THREAD_STACK_TOO_BIG;
364 365
365 // Dereferencing a pointer in the guard page in a thread that doesn't own 366 // Dereferencing a pointer in the guard page in a thread that doesn't own
366 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. 367 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash.
367 // This occurs very rarely, but reliably over the population. 368 // This occurs very rarely, but reliably over the population.
368 if (PointsToGuardPage(bottom)) 369 if (PointsToGuardPage(bottom))
369 return; 370 return NativeStackSampler::THREAD_INACCESSIBLE;
370 371
371 (*annotator)(sample); 372 (*annotator)(sample);
372 373
373 CopyMemoryFromStack(stack_copy_buffer, 374 CopyMemoryFromStack(stack_copy_buffer,
374 reinterpret_cast<const void*>(bottom), top - bottom); 375 reinterpret_cast<const void*>(bottom), top - bottom);
375 } 376 }
376 377
377 if (test_delegate) 378 if (test_delegate)
378 test_delegate->OnPreStackWalk(); 379 test_delegate->OnPreStackWalk();
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);
384 return NativeStackSampler::THREAD_RUNNING;
383 } 385 }
384 386
385 // NativeStackSamplerWin ------------------------------------------------------ 387 // NativeStackSamplerWin ------------------------------------------------------
386 388
387 class NativeStackSamplerWin : public NativeStackSampler { 389 class NativeStackSamplerWin : public NativeStackSampler {
388 public: 390 public:
389 NativeStackSamplerWin(win::ScopedHandle thread_handle, 391 NativeStackSamplerWin(win::ScopedHandle thread_handle,
390 AnnotateCallback annotator, 392 AnnotateCallback annotator,
391 NativeStackSamplerTestDelegate* test_delegate); 393 NativeStackSamplerTestDelegate* test_delegate);
392 ~NativeStackSamplerWin() override; 394 ~NativeStackSamplerWin() override;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 profile_module_index_.clear(); 472 profile_module_index_.clear();
471 } 473 }
472 474
473 void NativeStackSamplerWin::RecordStackSample( 475 void NativeStackSamplerWin::RecordStackSample(
474 StackSamplingProfiler::Sample* sample) { 476 StackSamplingProfiler::Sample* sample) {
475 DCHECK(current_modules_); 477 DCHECK(current_modules_);
476 478
477 if (!stack_copy_buffer_) 479 if (!stack_copy_buffer_)
478 return; 480 return;
479 481
482 if (thread_state() == THREAD_EXITED)
483 return;
484
480 std::vector<RecordedFrame> stack; 485 std::vector<RecordedFrame> stack;
481 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, 486 set_thread_state(SuspendThreadAndRecordStack(
482 stack_copy_buffer_.get(), kStackCopyBufferSize, 487 thread_handle_.Get(), thread_stack_base_address_,
483 &stack, annotator_, sample, test_delegate_); 488 stack_copy_buffer_.get(), kStackCopyBufferSize, &stack, annotator_,
489 sample, test_delegate_));
484 CopyToSample(stack, sample, current_modules_); 490 CopyToSample(stack, sample, current_modules_);
491
492 if (test_delegate_)
493 test_delegate_->OnPostRecordSample(thread_state());
485 } 494 }
486 495
487 void NativeStackSamplerWin::ProfileRecordingStopped() { 496 void NativeStackSamplerWin::ProfileRecordingStopped() {
488 current_modules_ = nullptr; 497 current_modules_ = nullptr;
489 } 498 }
490 499
491 // static 500 // static
492 bool NativeStackSamplerWin::GetModuleForHandle( 501 bool NativeStackSamplerWin::GetModuleForHandle(
493 HMODULE module_handle, 502 HMODULE module_handle,
494 StackSamplingProfiler::Module* module) { 503 StackSamplingProfiler::Module* module) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 566
558 if (thread_handle) { 567 if (thread_handle) {
559 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( 568 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin(
560 win::ScopedHandle(thread_handle), annotator, test_delegate)); 569 win::ScopedHandle(thread_handle), annotator, test_delegate));
561 } 570 }
562 #endif 571 #endif
563 return std::unique_ptr<NativeStackSampler>(); 572 return std::unique_ptr<NativeStackSampler>();
564 } 573 }
565 574
566 } // namespace base 575 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698