Commit e7a1ddfb authored by Etienne Bergeron's avatar Etienne Bergeron Committed by Commit Bot

Add error code for sampling profiler failures

This CL is adding a trace events to debug some failures happening in the
field. An instant event will be present with an error code.

R=wittman@chromium.org
BUG=882982

Change-Id: I0a55ca82c4312bb212a5b7d1f3e391b42d3d38c9
Reviewed-on: https://chromium-review.googlesource.com/c/1297065
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602397}
parent b9a687f1
...@@ -78,6 +78,37 @@ const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) { ...@@ -78,6 +78,37 @@ const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
return basic_info.Teb; return basic_info.Teb;
} }
enum NativeStackSamplerError {
NATIVE_STACK_SAMPLER_SUCCESS,
NATIVE_STACK_SAMPLER_SUSPEND_FAILED,
NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED,
NATIVE_STACK_SAMPLER_STACK_TOO_BIG,
NATIVE_STACK_SAMPLER_POINTS_TO_GUARD,
NATIVE_STACK_SAMPLER_UNWIND_UNSUPPORTED,
NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED,
};
const char* NativeStackSamplerErrorToString(NativeStackSamplerError code) {
switch (code) {
case NATIVE_STACK_SAMPLER_SUCCESS:
return "SUCCESS";
case NATIVE_STACK_SAMPLER_SUSPEND_FAILED:
return "SUSPEND_FAILED";
case NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED:
return "GET_THREAD_CONTEXT_FAILED";
case NATIVE_STACK_SAMPLER_STACK_TOO_BIG:
return "STACK_TOO_BIG";
case NATIVE_STACK_SAMPLER_POINTS_TO_GUARD:
return "POINTS_TO_GUARD";
case NATIVE_STACK_SAMPLER_UNWIND_UNSUPPORTED:
return "UNWIND_UNSUPPORTED";
case NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED:
return "TRY_UNWIND";
default:
return "UNKNWON";
}
}
#if defined(_WIN64) #if defined(_WIN64)
// If the value at |pointer| points to the original stack, rewrite it to point // If the value at |pointer| points to the original stack, rewrite it to point
// to the corresponding location in the copied stack. // to the corresponding location in the copied stack.
...@@ -171,7 +202,8 @@ struct RecordedFrame { ...@@ -171,7 +202,8 @@ struct RecordedFrame {
// Walks the stack represented by |context| from the current frame downwards, // Walks the stack represented by |context| from the current frame downwards,
// recording the instruction pointer and associated module for each frame in // recording the instruction pointer and associated module for each frame in
// |stack|. // |stack|.
void RecordStack(CONTEXT* context, std::vector<RecordedFrame>* stack) { NativeStackSamplerError RecordStack(CONTEXT* context,
std::vector<RecordedFrame>* stack) {
#ifdef _WIN64 #ifdef _WIN64
DCHECK(stack->empty()); DCHECK(stack->empty());
...@@ -186,12 +218,15 @@ void RecordStack(CONTEXT* context, std::vector<RecordedFrame>* stack) { ...@@ -186,12 +218,15 @@ void RecordStack(CONTEXT* context, std::vector<RecordedFrame>* stack) {
reinterpret_cast<const void*>(context->Rip); reinterpret_cast<const void*>(context->Rip);
ScopedModuleHandle module; ScopedModuleHandle module;
if (!frame_unwinder.TryUnwind(context, &module)) if (!frame_unwinder.TryUnwind(context, &module))
return; return NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED;
RecordedFrame frame; RecordedFrame frame;
frame.instruction_pointer = instruction_pointer; frame.instruction_pointer = instruction_pointer;
frame.module = std::move(module); frame.module = std::move(module);
stack->push_back(std::move(frame)); stack->push_back(std::move(frame));
} }
return NATIVE_STACK_SAMPLER_SUCCESS;
#else
return NATIVE_STACK_SAMPLER_UNWIND_UNSUPPORTED;
#endif #endif
} }
...@@ -291,7 +326,7 @@ bool PointsToGuardPage(uintptr_t stack_pointer) { ...@@ -291,7 +326,7 @@ bool PointsToGuardPage(uintptr_t stack_pointer) {
// ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
// other logging statements. Otherwise this code can deadlock on heap locks in // other logging statements. Otherwise this code can deadlock on heap locks in
// the default heap acquired by the target thread before it was suspended. // the default heap acquired by the target thread before it was suspended.
void SuspendThreadAndRecordStack( NativeStackSamplerError SuspendThreadAndRecordStack(
HANDLE thread_handle, HANDLE thread_handle,
const void* base_address, const void* base_address,
void* stack_copy_buffer, void* stack_copy_buffer,
...@@ -315,10 +350,10 @@ void SuspendThreadAndRecordStack( ...@@ -315,10 +350,10 @@ void SuspendThreadAndRecordStack(
ScopedSuspendThread suspend_thread(thread_handle); ScopedSuspendThread suspend_thread(thread_handle);
if (!suspend_thread.was_successful()) if (!suspend_thread.was_successful())
return; return NATIVE_STACK_SAMPLER_SUSPEND_FAILED;
if (!::GetThreadContext(thread_handle, &thread_context)) if (!::GetThreadContext(thread_handle, &thread_context))
return; return NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED;
#if defined(_WIN64) #if defined(_WIN64)
bottom = thread_context.Rsp; bottom = thread_context.Rsp;
...@@ -327,13 +362,13 @@ void SuspendThreadAndRecordStack( ...@@ -327,13 +362,13 @@ void SuspendThreadAndRecordStack(
#endif #endif
if ((top - bottom) > stack_copy_buffer_size) if ((top - bottom) > stack_copy_buffer_size)
return; return NATIVE_STACK_SAMPLER_STACK_TOO_BIG;
// Dereferencing a pointer in the guard page in a thread that doesn't own // Dereferencing a pointer in the guard page in a thread that doesn't own
// the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a
// crash. This occurs very rarely, but reliably over the population. // crash. This occurs very rarely, but reliably over the population.
if (PointsToGuardPage(bottom)) if (PointsToGuardPage(bottom))
return; return NATIVE_STACK_SAMPLER_POINTS_TO_GUARD;
profile_builder->RecordAnnotations(); profile_builder->RecordAnnotations();
...@@ -351,7 +386,7 @@ void SuspendThreadAndRecordStack( ...@@ -351,7 +386,7 @@ void SuspendThreadAndRecordStack(
RewritePointersToStackMemory(top, bottom, &thread_context, RewritePointersToStackMemory(top, bottom, &thread_context,
stack_copy_buffer); stack_copy_buffer);
RecordStack(&thread_context, stack); return RecordStack(&thread_context, stack);
} }
} }
...@@ -409,12 +444,22 @@ std::vector<Frame> NativeStackSamplerWin::RecordStackFrames( ...@@ -409,12 +444,22 @@ std::vector<Frame> NativeStackSamplerWin::RecordStackFrames(
"NativeStackSamplerWin::RecordStackFrames"); "NativeStackSamplerWin::RecordStackFrames");
DCHECK(stack_buffer); DCHECK(stack_buffer);
std::vector<Frame> recorded_stackframes;
std::vector<RecordedFrame> stack; std::vector<RecordedFrame> stack;
SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, NativeStackSamplerError error_code = SuspendThreadAndRecordStack(
stack_buffer->buffer(), stack_buffer->size(), thread_handle_.Get(), thread_stack_base_address_, stack_buffer->buffer(),
&stack, profile_builder, test_delegate_); stack_buffer->size(), &stack, profile_builder, test_delegate_);
if (error_code != NATIVE_STACK_SAMPLER_SUCCESS) {
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
"RecordStackFramesFailed", TRACE_EVENT_SCOPE_THREAD,
"error_code",
NativeStackSamplerErrorToString(error_code));
}
return CreateFrames(stack); recorded_stackframes = CreateFrames(stack);
return recorded_stackframes;
} }
std::vector<Frame> NativeStackSamplerWin::CreateFrames( std::vector<Frame> NativeStackSamplerWin::CreateFrames(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment