Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ddprof-lib/src/main/cpp/itimer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include "os.h"
#include "profiler.h"
#include "stackWalker.h"
#include "context.h"
#include "thread.h"
#include "vmStructs.h"

Expand All @@ -30,7 +29,10 @@ CStack ITimer::_cstack;

void ITimer::signalHandler(int signo, siginfo_t* siginfo, void* ucontext) {
if (!_enabled) return;

AsyncSampleMutex mutex;
if (!mutex.acquired()) {
return;
}
int tid = 0;
ProfiledThread* current = ProfiledThread::current();
if (current != NULL) {
Expand Down
4 changes: 4 additions & 0 deletions ddprof-lib/src/main/cpp/perfEvents_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,10 @@ void PerfEvents::signalHandler(int signo, siginfo_t* siginfo, void* ucontext) {
// Looks like an external signal; don't treat as a profiling event
return;
}
AsyncSampleMutex mutex;
if (!mutex.acquired()) {
return;
}

ProfiledThread* current = ProfiledThread::current();
if (current != NULL) {
Expand Down
101 changes: 57 additions & 44 deletions ddprof-lib/src/main/cpp/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,58 @@ int Profiler::convertNativeTrace(int native_frames, const void** callchain, ASGC
return depth;
}

NOINLINE void Profiler::getJavaTraceAsyncRetryPopStub(void* ucontext, ASGCT_CallTrace* trace, int max_depth, CodeBlob* stub, StackFrame& frame) {
if (!(_safe_mode & POP_STUB) && frame.popStub((instruction_t*)stub->_start, stub->_name)
&& isAddressInCode(frame.pc() -= ADJUST_RET)) {
VM::_asyncGetCallTrace(trace, max_depth, ucontext);
}
}

NOINLINE void Profiler::getJavaTraceAsyncRetryPopMethod(void* ucontext, ASGCT_CallTrace* trace, int max_depth, CodeBlob* stub, StackFrame& frame, NMethod* nmethod) {
if (!(_safe_mode & POP_METHOD) && frame.popMethod((instruction_t*)nmethod->entry())
&& isAddressInCode(frame.pc() -= ADJUST_RET)) {
VM::_asyncGetCallTrace(trace, max_depth, ucontext);
}
}

NOINLINE void Profiler::getJavaTraceAsyncRetryMakeFrameWalkable(void* ucontext, ASGCT_CallTrace* trace, int max_depth, VMThread* vm_thread) {
uintptr_t& sp = vm_thread->lastJavaSP();
uintptr_t& pc = vm_thread->lastJavaPC();
if (sp != 0 && pc == 0) {
// We have the last Java frame anchor, but it is not marked as walkable.
// Make it walkable here
pc = ((uintptr_t*)sp)[-1];

NMethod* m = CodeHeap::findNMethod((const void*)pc);
if (m != NULL) {
// AGCT fails if the last Java frame is a Runtime Stub with an invalid _frame_complete_offset.
// In this case we patch _frame_complete_offset manually
if (!m->isNMethod() && m->frameSize() > 0 && m->frameCompleteOffset() == -1) {
m->setFrameCompleteOffset(0);
}
VM::_asyncGetCallTrace(trace, max_depth, ucontext);
} else if (findLibraryByAddress((const void*)pc) != NULL) {
VM::_asyncGetCallTrace(trace, max_depth, ucontext);
}

pc = 0;
}
}

NOINLINE void Profiler::getJavaTraceAsyncRetryInvalidRuntimeStubFrameCompleteOffset(void* ucontext, ASGCT_CallTrace* trace, int max_depth, VMThread* vm_thread) {
uintptr_t& sp = vm_thread->lastJavaSP();
uintptr_t& pc = vm_thread->lastJavaPC();
if (sp != 0 && pc != 0) {
// Similar to the above: last Java frame is set,
// but points to a Runtime Stub with an invalid _frame_complete_offset
NMethod* m = CodeHeap::findNMethod((const void*)pc);
if (m != NULL && !m->isNMethod() && m->frameSize() > 0 && m->frameCompleteOffset() == -1) {
m->setFrameCompleteOffset(0);
VM::_asyncGetCallTrace(trace, max_depth, ucontext);
}
}
}

int Profiler::getJavaTraceAsync(void* ucontext, ASGCT_CallFrame* frames, int max_depth, StackContext* java_ctx, bool *truncated) {
// Workaround for JDK-8132510: it's not safe to call GetEnv() inside a signal handler
// since JDK 9, so we do it only for threads already registered in ThreadLocalStorage
Expand Down Expand Up @@ -436,10 +488,7 @@ int Profiler::getJavaTraceAsync(void* ucontext, ASGCT_CallFrame* frames, int max
if (_cstack != CSTACK_NO) {
max_depth -= makeFrame(trace.frames++, BCI_NATIVE_FRAME, stub->_name);
}
if (!(_safe_mode & POP_STUB) && frame.popStub((instruction_t*)stub->_start, stub->_name)
&& isAddressInCode(frame.pc() -= ADJUST_RET)) {
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
}
getJavaTraceAsyncRetryPopStub(ucontext, &trace, max_depth, stub, frame);
} else if (VMStructs::hasMethodStructs()) {
NMethod* nmethod = CodeHeap::findNMethod((const void*)frame.pc());
if (nmethod != NULL && nmethod->isNMethod() && nmethod->isAlive()) {
Expand All @@ -449,55 +498,19 @@ int Profiler::getJavaTraceAsync(void* ucontext, ASGCT_CallFrame* frames, int max
if (method_id != NULL) {
max_depth -= makeFrame(trace.frames++, 0, method_id);
}
if (!(_safe_mode & POP_METHOD) && frame.popMethod((instruction_t*)nmethod->entry())
&& isAddressInCode(frame.pc() -= ADJUST_RET)) {
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
}
getJavaTraceAsyncRetryPopMethod(ucontext, &trace, max_depth, stub, frame, nmethod);
}
} else if (nmethod != NULL) {
if (_cstack != CSTACK_NO) {
max_depth -= makeFrame(trace.frames++, BCI_NATIVE_FRAME, nmethod->name());
}
if (!(_safe_mode & POP_STUB) && frame.popStub(NULL, nmethod->name())
&& isAddressInCode(frame.pc() -= ADJUST_RET)) {
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
}
getJavaTraceAsyncRetryPopStub(ucontext, &trace, max_depth, stub, frame);
}
}
} else if (trace.num_frames == ticks_unknown_not_Java && !(_safe_mode & LAST_JAVA_PC)) {
uintptr_t& sp = vm_thread->lastJavaSP();
uintptr_t& pc = vm_thread->lastJavaPC();
if (sp != 0 && pc == 0) {
// We have the last Java frame anchor, but it is not marked as walkable.
// Make it walkable here
pc = ((uintptr_t*)sp)[-1];

NMethod* m = CodeHeap::findNMethod((const void*)pc);
if (m != NULL) {
// AGCT fails if the last Java frame is a Runtime Stub with an invalid _frame_complete_offset.
// In this case we patch _frame_complete_offset manually
if (!m->isNMethod() && m->frameSize() > 0 && m->frameCompleteOffset() == -1) {
m->setFrameCompleteOffset(0);
}
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
} else if (findLibraryByAddress((const void*)pc) != NULL) {
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
}

pc = 0;
}
getJavaTraceAsyncRetryMakeFrameWalkable(ucontext, &trace, max_depth, vm_thread);
} else if (trace.num_frames == ticks_not_walkable_not_Java && !(_safe_mode & LAST_JAVA_PC)) {
uintptr_t& sp = vm_thread->lastJavaSP();
uintptr_t& pc = vm_thread->lastJavaPC();
if (sp != 0 && pc != 0) {
// Similar to the above: last Java frame is set,
// but points to a Runtime Stub with an invalid _frame_complete_offset
NMethod* m = CodeHeap::findNMethod((const void*)pc);
if (m != NULL && !m->isNMethod() && m->frameSize() > 0 && m->frameCompleteOffset() == -1) {
m->setFrameCompleteOffset(0);
VM::_asyncGetCallTrace(&trace, max_depth, ucontext);
}
}
getJavaTraceAsyncRetryInvalidRuntimeStubFrameCompleteOffset(ucontext, &trace, max_depth, vm_thread);
} else if (trace.num_frames == ticks_GC_active && !(_safe_mode & GC_TRACES)) {
if (vm_thread->lastJavaSP() == 0) {
// Do not add 'GC_active' for threads with no Java frames, e.g. Compiler threads
Expand Down
38 changes: 38 additions & 0 deletions ddprof-lib/src/main/cpp/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "vmEntry.h"
#include "objectSampler.h"
#include "thread.h"
#include "vmStructs.h"
#include "stackFrame.h"

// avoid linking against newer symbols here for wide compatibility
#ifdef __GLIBC__
Expand All @@ -45,6 +47,12 @@
#endif
#endif

#ifdef __clang__
# define NOINLINE __attribute__((noinline))
#else
# define NOINLINE __attribute__((noinline,noclone))
#endif

const int MAX_NATIVE_FRAMES = 128;
const int RESERVED_FRAMES = 4;

Expand All @@ -58,6 +66,32 @@ struct CallTraceBuffer {
ASGCT_CallFrame _asgct_frames[1];
};

// controls access to AGCT
class AsyncSampleMutex {
private:
bool _acquired;
bool try_set(bool flag) {
ProfiledThread* current = ProfiledThread::current();
if (current != NULL) {
bool was_set = current->is_unwinding_Java();
current->set_unwinding_Java(flag);
return !was_set;
}
return false;
}
public:
AsyncSampleMutex() {
_acquired = try_set(true);
}
AsyncSampleMutex(AsyncSampleMutex& other) = delete;
~AsyncSampleMutex() {
try_set(false);
}
bool acquired() {
return _acquired;
}
};


class FrameName;
class NMethod;
Expand Down Expand Up @@ -157,6 +191,10 @@ class Profiler {
Engine* selectWallEngine(Arguments& args);
Engine* selectAllocEngine(Arguments& args);
Error checkJvmCapabilities();
NOINLINE void getJavaTraceAsyncRetryPopStub(void* ucontext, ASGCT_CallTrace* trace, int max_depth, CodeBlob* stub, StackFrame& frame);
NOINLINE void getJavaTraceAsyncRetryPopMethod(void* ucontext, ASGCT_CallTrace* trace, int max_depth, CodeBlob* stub, StackFrame& frame, NMethod* nmethod);
NOINLINE void getJavaTraceAsyncRetryMakeFrameWalkable(void* ucontext, ASGCT_CallTrace* trace, int max_depth, VMThread* vm_thread);
NOINLINE void getJavaTraceAsyncRetryInvalidRuntimeStubFrameCompleteOffset(void* ucontext, ASGCT_CallTrace* trace, int max_depth, VMThread* vm_thread);

void lockAll();
void unlockAll();
Expand Down
10 changes: 9 additions & 1 deletion ddprof-lib/src/main/cpp/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ class ProfiledThread {
u64 _wall_epoch;
u64 _skipped_samples;
u64 _context_key;
bool _unwinding_java;

ProfiledThread(int buffer_pos, int tid) :
_buffer_pos(buffer_pos),
_tid(tid),
_cpu_epoch(0),
_wall_epoch(0),
_skipped_samples(0),
_context_key(0){};
_context_key(0),
_unwinding_java(false){};

void releaseFromBuffer();
public:
Expand All @@ -55,6 +57,12 @@ class ProfiledThread {

static ProfiledThread* current();
static int currentTid();
bool is_unwinding_Java() {
return _unwinding_java;
}
void set_unwinding_Java(bool flag) {
_unwinding_java = flag;
}

inline int tid() {
return _tid;
Expand Down
4 changes: 4 additions & 0 deletions ddprof-lib/src/main/cpp/wallClock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ void WallClock::sharedSignalHandler(int signo, siginfo_t* siginfo, void* ucontex
}

void WallClock::signalHandler(int signo, siginfo_t* siginfo, void* ucontext, u64 last_sample) {
AsyncSampleMutex mutex;
if (!mutex.acquired()) {
return;
}
ProfiledThread* current = ProfiledThread::current();
int tid = current != NULL ? current->tid() : OS::threadId();
Shims::instance().setSighandlerTid(tid);
Expand Down