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 @@
#include "base/profiler/native_stack_sampler.h"
#include <pthread.h>
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
namespace base {
std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
......@@ -13,7 +18,24 @@ std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
}
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
......@@ -29,7 +29,7 @@ NativeStackSamplerAndroid::RecordStackFrames(
unwinder_.Initialize();
}
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;
frames.reserve(depth);
for (size_t i = 0; i < depth; ++i) {
......
......@@ -12,7 +12,6 @@
#include "link.h"
#include <algorithm>
#include <memory>
#include "base/android/jni_generator/jni_generator_helper.h"
#include "base/debug/proc_maps_linux.h"
......@@ -171,8 +170,6 @@ bool GetCFIForPC(CFIBacktraceAndroid* cfi_unwinder,
pc - CFIBacktraceAndroid::executable_start_addr(), cfi);
}
constexpr size_t kMaxStackBytesCopied = 1024 * 1024;
// Struct to store the arguments to the signal handler.
struct HandlerParams {
const tracing::StackUnwinderAndroid* unwinder;
......@@ -186,8 +183,8 @@ struct HandlerParams {
unw_context_t* context;
// The value of Stack pointer of the thread.
uintptr_t* sp;
// The address where the full stack is copied to.
char* stack_copy_buffer;
// Buffer to copy the stack segment.
base::NativeStackSampler::StackBuffer* stack_buffer;
size_t* stack_size;
};
......@@ -219,9 +216,10 @@ static void ThreadSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) {
uintptr_t stack_base_addr = params->unwinder->GetEndAddressOfRegion(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;
memcpy(params->stack_copy_buffer, reinterpret_cast<void*>(sp),
memcpy(params->stack_buffer->buffer(), reinterpret_cast<void*>(sp),
*params->stack_size);
*params->success = true;
}
......@@ -303,22 +301,22 @@ size_t StackUnwinderAndroid::TraceStack(const void** out_trace,
/* stack_segment_base=*/0, JniMarkers(), out_trace, max_depth);
}
size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
const void** out_trace,
size_t max_depth) const {
size_t StackUnwinderAndroid::TraceStack(
base::PlatformThreadId tid,
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
// copies the stack of the thread and returns. This function tries to unwind
// stack frames from the copied stack.
DCHECK(is_initialized_);
AsyncSafeWaitableEvent wait_event;
size_t stack_size;
std::unique_ptr<char[]> stack_copy_buffer(new char[kMaxStackBytesCopied]);
bool copied = false;
unw_context_t context;
uintptr_t sp = 0;
HandlerParams params = {this, &wait_event, &copied,
&context, &sp, stack_copy_buffer.get(),
&stack_size};
HandlerParams params = {this, &wait_event, &copied, &context,
&sp, stack_buffer, &stack_size};
base::subtle::Release_Store(&g_handler_params,
reinterpret_cast<uintptr_t>(&params));
......@@ -353,7 +351,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
// 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.
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;
uintptr_t* register_context = reinterpret_cast<uintptr_t*>(&context);
for (size_t i = 0; i < 16; ++i) {
......@@ -364,7 +362,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
}
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 =
jni_generator::kJniStackMarkerValue & 0xFFFFFFFF,
marker_r = jni_generator::kJniStackMarkerValue >> 32;
......@@ -398,7 +396,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
}
uintptr_t ip = 0;
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);
// Unwind handler function (ThreadSignalHandler()) since libunwind cannot
......@@ -427,7 +425,7 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
return TraceStackWithContext(
&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);
}
......
......@@ -8,6 +8,7 @@
#include <map>
#include "base/debug/proc_maps_linux.h"
#include "base/profiler/native_stack_sampler.h"
#include "base/threading/platform_thread.h"
#include "components/tracing/tracing_export.h"
......@@ -38,6 +39,7 @@ class TRACING_EXPORT StackUnwinderAndroid {
// Same as above function, but pauses the thread with the given |tid| and then
// unwinds. |tid| should not be current thread's.
size_t TraceStack(base::PlatformThreadId tid,
base::NativeStackSampler::StackBuffer* stack_buffer,
const void** out_trace,
size_t max_depth) const;
......
......@@ -66,7 +66,10 @@ TEST_F(StackUnwinderTest, UnwindOtherThread) {
base::WaitableEvent* unwind_finished_event,
uintptr_t test_pc) {
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);
for (size_t i = 0; i < result; ++i) {
uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]);
......@@ -104,7 +107,11 @@ TEST_F(StackUnwinderTest, UnwindOtherThreadOnJNICall) {
auto callback = [](StackUnwinderAndroid* unwinder, base::PlatformThreadId tid,
uintptr_t test_pc) {
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;
uintptr_t jni_address =
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