Commit c67f7905 authored by Siddhartha's avatar Siddhartha Committed by Commit Bot

Linux: Find default stack size from pthread for CPU profiler

BUG=859260

Change-Id: I23044240996b52cc532de618fa0fef7164713d30
Reviewed-on: https://chromium-review.googlesource.com/c/1233233
Commit-Queue: ssid <ssid@chromium.org>
Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603781}
parent 2a2eea66
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include "base/profiler/native_stack_sampler.h" #include "base/profiler/native_stack_sampler.h"
#include <pthread.h>
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
namespace base { namespace base {
std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
...@@ -13,7 +18,24 @@ std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( ...@@ -13,7 +18,24 @@ std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
} }
size_t NativeStackSampler::GetStackBufferSize() { size_t NativeStackSampler::GetStackBufferSize() {
return 0; size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
pthread_attr_t attr;
if (stack_size == 0 && pthread_attr_init(&attr) == 0) {
if (pthread_attr_getstacksize(&attr, &stack_size) != 0)
stack_size = 0;
pthread_attr_destroy(&attr);
}
// If we can't get stack limit from pthreads then use default value.
#if defined(OS_ANDROID)
// 1MB is default thread limit set by Android at art/runtime/thread_pool.h.
constexpr size_t kDefaultStackLimit = 1 << 20;
#else
// Maximum limits under NPTL implementation.
constexpr size_t kDefaultStackLimit = 4 * (1 << 20);
#endif
return stack_size > 0 ? stack_size : kDefaultStackLimit;
} }
} // namespace base } // namespace base
...@@ -29,7 +29,7 @@ NativeStackSamplerAndroid::RecordStackFrames( ...@@ -29,7 +29,7 @@ NativeStackSamplerAndroid::RecordStackFrames(
unwinder_.Initialize(); unwinder_.Initialize();
} }
const void* pcs[kMaxFrameDepth]; const void* pcs[kMaxFrameDepth];
size_t depth = unwinder_.TraceStack(tid_, pcs, kMaxFrameDepth); size_t depth = unwinder_.TraceStack(tid_, stack_buffer, pcs, kMaxFrameDepth);
std::vector<base::StackSamplingProfiler::Frame> frames; std::vector<base::StackSamplingProfiler::Frame> frames;
frames.reserve(depth); frames.reserve(depth);
for (size_t i = 0; i < depth; ++i) { for (size_t i = 0; i < depth; ++i) {
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "link.h" #include "link.h"
#include <algorithm> #include <algorithm>
#include <memory>
#include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_generator/jni_generator_helper.h"
#include "base/debug/proc_maps_linux.h" #include "base/debug/proc_maps_linux.h"
...@@ -171,8 +170,6 @@ bool GetCFIForPC(CFIBacktraceAndroid* cfi_unwinder, ...@@ -171,8 +170,6 @@ bool GetCFIForPC(CFIBacktraceAndroid* cfi_unwinder,
pc - CFIBacktraceAndroid::executable_start_addr(), cfi); pc - CFIBacktraceAndroid::executable_start_addr(), cfi);
} }
constexpr size_t kMaxStackBytesCopied = 1024 * 1024;
// Struct to store the arguments to the signal handler. // Struct to store the arguments to the signal handler.
struct HandlerParams { struct HandlerParams {
const tracing::StackUnwinderAndroid* unwinder; const tracing::StackUnwinderAndroid* unwinder;
...@@ -186,8 +183,8 @@ struct HandlerParams { ...@@ -186,8 +183,8 @@ struct HandlerParams {
unw_context_t* context; unw_context_t* context;
// The value of Stack pointer of the thread. // The value of Stack pointer of the thread.
uintptr_t* sp; uintptr_t* sp;
// The address where the full stack is copied to. // Buffer to copy the stack segment.
char* stack_copy_buffer; base::NativeStackSampler::StackBuffer* stack_buffer;
size_t* stack_size; size_t* stack_size;
}; };
...@@ -219,9 +216,10 @@ static void ThreadSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) { ...@@ -219,9 +216,10 @@ static void ThreadSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) {
uintptr_t stack_base_addr = params->unwinder->GetEndAddressOfRegion(sp); uintptr_t stack_base_addr = params->unwinder->GetEndAddressOfRegion(sp);
*params->stack_size = stack_base_addr - sp; *params->stack_size = stack_base_addr - sp;
if (stack_base_addr == 0 || *params->stack_size > kMaxStackBytesCopied) if (stack_base_addr == 0 ||
*params->stack_size > params->stack_buffer->size())
return; return;
memcpy(params->stack_copy_buffer, reinterpret_cast<void*>(sp), memcpy(params->stack_buffer->buffer(), reinterpret_cast<void*>(sp),
*params->stack_size); *params->stack_size);
*params->success = true; *params->success = true;
} }
...@@ -303,22 +301,22 @@ size_t StackUnwinderAndroid::TraceStack(const void** out_trace, ...@@ -303,22 +301,22 @@ size_t StackUnwinderAndroid::TraceStack(const void** out_trace,
/* stack_segment_base=*/0, JniMarkers(), out_trace, max_depth); /* stack_segment_base=*/0, JniMarkers(), out_trace, max_depth);
} }
size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid, size_t StackUnwinderAndroid::TraceStack(
const void** out_trace, base::PlatformThreadId tid,
size_t max_depth) const { base::NativeStackSampler::StackBuffer* stack_buffer,
const void** out_trace,
size_t max_depth) const {
// Stops the thread with given tid with a signal handler. The signal handler // Stops the thread with given tid with a signal handler. The signal handler
// copies the stack of the thread and returns. This function tries to unwind // copies the stack of the thread and returns. This function tries to unwind
// stack frames from the copied stack. // stack frames from the copied stack.
DCHECK(is_initialized_); DCHECK(is_initialized_);
AsyncSafeWaitableEvent wait_event; AsyncSafeWaitableEvent wait_event;
size_t stack_size; size_t stack_size;
std::unique_ptr<char[]> stack_copy_buffer(new char[kMaxStackBytesCopied]);
bool copied = false; bool copied = false;
unw_context_t context; unw_context_t context;
uintptr_t sp = 0; uintptr_t sp = 0;
HandlerParams params = {this, &wait_event, &copied, HandlerParams params = {this, &wait_event, &copied, &context,
&context, &sp, stack_copy_buffer.get(), &sp, stack_buffer, &stack_size};
&stack_size};
base::subtle::Release_Store(&g_handler_params, base::subtle::Release_Store(&g_handler_params,
reinterpret_cast<uintptr_t>(&params)); reinterpret_cast<uintptr_t>(&params));
...@@ -353,7 +351,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid, ...@@ -353,7 +351,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
// Context contains list of saved registers. Replace the SP and any register // Context contains list of saved registers. Replace the SP and any register
// that points to address on the previous stack to point to the copied stack. // that points to address on the previous stack to point to the copied stack.
const uintptr_t relocation_offset = const uintptr_t relocation_offset =
reinterpret_cast<uintptr_t>(stack_copy_buffer.get()) - sp; reinterpret_cast<uintptr_t>(stack_buffer->buffer()) - sp;
bool replaced_sp = false; bool replaced_sp = false;
uintptr_t* register_context = reinterpret_cast<uintptr_t*>(&context); uintptr_t* register_context = reinterpret_cast<uintptr_t*>(&context);
for (size_t i = 0; i < 16; ++i) { for (size_t i = 0; i < 16; ++i) {
...@@ -364,7 +362,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid, ...@@ -364,7 +362,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
} }
DCHECK(replaced_sp); DCHECK(replaced_sp);
uintptr_t* new_stack = reinterpret_cast<uintptr_t*>(stack_copy_buffer.get()); uintptr_t* new_stack = reinterpret_cast<uintptr_t*>(stack_buffer->buffer());
constexpr uintptr_t marker_l = constexpr uintptr_t marker_l =
jni_generator::kJniStackMarkerValue & 0xFFFFFFFF, jni_generator::kJniStackMarkerValue & 0xFFFFFFFF,
marker_r = jni_generator::kJniStackMarkerValue >> 32; marker_r = jni_generator::kJniStackMarkerValue >> 32;
...@@ -398,7 +396,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid, ...@@ -398,7 +396,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
} }
uintptr_t ip = 0; uintptr_t ip = 0;
unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_get_reg(&cursor, UNW_REG_SP, &sp);
DCHECK_EQ(sp, reinterpret_cast<uintptr_t>(stack_copy_buffer.get())); DCHECK_EQ(sp, reinterpret_cast<uintptr_t>(stack_buffer->buffer()));
unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_IP, &ip);
// Unwind handler function (ThreadSignalHandler()) since libunwind cannot // Unwind handler function (ThreadSignalHandler()) since libunwind cannot
...@@ -427,7 +425,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid, ...@@ -427,7 +425,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
return TraceStackWithContext( return TraceStackWithContext(
&cursor, cfi_unwinder, this, &cursor, cfi_unwinder, this,
reinterpret_cast<uintptr_t>(stack_copy_buffer.get()) + stack_size, reinterpret_cast<uintptr_t>(stack_buffer->buffer()) + stack_size,
jni_markers, out_trace, max_depth); jni_markers, out_trace, max_depth);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <map> #include <map>
#include "base/debug/proc_maps_linux.h" #include "base/debug/proc_maps_linux.h"
#include "base/profiler/native_stack_sampler.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "components/tracing/tracing_export.h" #include "components/tracing/tracing_export.h"
...@@ -38,6 +39,7 @@ class TRACING_EXPORT StackUnwinderAndroid { ...@@ -38,6 +39,7 @@ class TRACING_EXPORT StackUnwinderAndroid {
// Same as above function, but pauses the thread with the given |tid| and then // Same as above function, but pauses the thread with the given |tid| and then
// unwinds. |tid| should not be current thread's. // unwinds. |tid| should not be current thread's.
size_t TraceStack(base::PlatformThreadId tid, size_t TraceStack(base::PlatformThreadId tid,
base::NativeStackSampler::StackBuffer* stack_buffer,
const void** out_trace, const void** out_trace,
size_t max_depth) const; size_t max_depth) const;
......
...@@ -66,7 +66,10 @@ TEST_F(StackUnwinderTest, UnwindOtherThread) { ...@@ -66,7 +66,10 @@ TEST_F(StackUnwinderTest, UnwindOtherThread) {
base::WaitableEvent* unwind_finished_event, base::WaitableEvent* unwind_finished_event,
uintptr_t test_pc) { uintptr_t test_pc) {
const void* frames[kMaxStackFrames]; const void* frames[kMaxStackFrames];
size_t result = unwinder->TraceStack(tid, frames, kMaxStackFrames); auto stack_buffer = base::NativeStackSampler::CreateStackBuffer();
EXPECT_GT(stack_buffer->size(), 0u);
size_t result =
unwinder->TraceStack(tid, stack_buffer.get(), frames, kMaxStackFrames);
EXPECT_GT(result, 0u); EXPECT_GT(result, 0u);
for (size_t i = 0; i < result; ++i) { for (size_t i = 0; i < result; ++i) {
uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]); uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]);
...@@ -104,7 +107,11 @@ TEST_F(StackUnwinderTest, UnwindOtherThreadOnJNICall) { ...@@ -104,7 +107,11 @@ TEST_F(StackUnwinderTest, UnwindOtherThreadOnJNICall) {
auto callback = [](StackUnwinderAndroid* unwinder, base::PlatformThreadId tid, auto callback = [](StackUnwinderAndroid* unwinder, base::PlatformThreadId tid,
uintptr_t test_pc) { uintptr_t test_pc) {
const void* frames[kMaxStackFrames]; const void* frames[kMaxStackFrames];
size_t result = unwinder->TraceStack(tid, frames, kMaxStackFrames); auto stack_buffer = base::NativeStackSampler::CreateStackBuffer();
EXPECT_GT(stack_buffer->size(), 0u);
size_t result =
unwinder->TraceStack(tid, stack_buffer.get(), frames, kMaxStackFrames);
bool found_jni = false; bool found_jni = false;
uintptr_t jni_address = uintptr_t jni_address =
reinterpret_cast<uintptr_t>(&Java_UnwindTestHelper_blockCurrentThread); reinterpret_cast<uintptr_t>(&Java_UnwindTestHelper_blockCurrentThread);
......
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