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
4 changes: 2 additions & 2 deletions ddprof-lib/src/main/cpp/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class JitWriteProtection {
~JitWriteProtection();
};


class OS {
public:
static const size_t page_size;
Expand Down Expand Up @@ -79,7 +78,8 @@ class OS {
static bool isLinux();

static SigAction installSignalHandler(int signo, SigAction action, SigHandler handler = NULL);
static SigAction replaceCrashHandler(SigAction action);
static SigAction replaceSigsegvHandler(SigAction action);
static SigAction replaceSigbusHandler(SigAction action);
static bool sendSignalToThread(int thread_id, int signo);

static void* safeAlloc(size_t size);
Expand Down
11 changes: 10 additions & 1 deletion ddprof-lib/src/main/cpp/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ SigAction OS::installSignalHandler(int signo, SigAction action, SigHandler handl
return oldsa.sa_sigaction;
}

SigAction OS::replaceCrashHandler(SigAction action) {
SigAction OS::replaceSigsegvHandler(SigAction action) {
struct sigaction sa;
sigaction(SIGSEGV, NULL, &sa);
SigAction old_action = sa.sa_sigaction;
Expand All @@ -253,6 +253,15 @@ SigAction OS::replaceCrashHandler(SigAction action) {
return old_action;
}

SigAction OS::replaceSigbusHandler(SigAction action) {
struct sigaction sa;
sigaction(SIGBUS, NULL, &sa);
SigAction old_action = sa.sa_sigaction;
sa.sa_sigaction = action;
sigaction(SIGBUS, &sa, NULL);
return old_action;
}

bool OS::sendSignalToThread(int thread_id, int signo) {
return syscall(__NR_tgkill, processId(), thread_id, signo) == 0;
}
Expand Down
11 changes: 10 additions & 1 deletion ddprof-lib/src/main/cpp/os_macos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,16 @@ SigAction OS::installSignalHandler(int signo, SigAction action, SigHandler handl
return oldsa.sa_sigaction;
}

SigAction OS::replaceCrashHandler(SigAction action) {
SigAction OS::replaceSigsegvHandler(SigAction action) {
struct sigaction sa;
sigaction(SIGSEGV, NULL, &sa);
SigAction old_action = sa.sa_sigaction;
sa.sa_sigaction = action;
sigaction(SIGSEGV, &sa, NULL);
return old_action;
}

SigAction OS::replaceSigbusHandler(SigAction action) {
struct sigaction sa;
sigaction(SIGBUS, NULL, &sa);
SigAction old_action = sa.sa_sigaction;
Expand Down
28 changes: 21 additions & 7 deletions ddprof-lib/src/main/cpp/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Profiler* const Profiler::_instance = new Profiler();

static void (*orig_trapHandler)(int signo, siginfo_t* siginfo, void* ucontext);
static void (*orig_segvHandler)(int signo, siginfo_t* siginfo, void* ucontext);
static void (*orig_busHandler)(int signo, siginfo_t* siginfo, void* ucontext);

static Engine noop_engine;
static PerfEvents perf_events;
Expand Down Expand Up @@ -689,7 +690,7 @@ void Profiler::recordSample(void* ucontext, u64 counter, int tid, jint event_typ
ASGCT_CallFrame *native_stop = frames + num_frames;
num_frames += getNativeTrace(ucontext, native_stop, event_type, tid, &java_ctx, &truncated);
if (_cstack == CSTACK_VM) {
num_frames += StackWalker::walkVM(ucontext, frames + num_frames, _max_stack_depth);
num_frames += StackWalker::walkVM(ucontext, frames + num_frames, _max_stack_depth, _call_stub_begin, _call_stub_end);
} else if (event_type == BCI_CPU || event_type == BCI_WALL) {
int java_frames = 0;
{
Expand Down Expand Up @@ -841,6 +842,18 @@ void Profiler::trapHandler(int signo, siginfo_t* siginfo, void* ucontext) {
}

void Profiler::segvHandler(int signo, siginfo_t* siginfo, void* ucontext) {
if (!crashHandler(signo, siginfo, ucontext)) {
orig_segvHandler(signo, siginfo, ucontext);
}
}

void Profiler::busHandler(int signo, siginfo_t* siginfo, void* ucontext) {
if (!crashHandler(signo, siginfo, ucontext)) {
orig_busHandler(signo, siginfo, ucontext);
}
}

bool Profiler::crashHandler(int signo, siginfo_t* siginfo, void* ucontext) {
StackFrame frame(ucontext);
uintptr_t pc = frame.pc();

Expand All @@ -850,7 +863,7 @@ void Profiler::segvHandler(int signo, siginfo_t* siginfo, void* ucontext) {
frame.pc() += length;
frame.retval() = 0;
Counters::increment(HANDLED_SIGSEGV_SAFEFETCH);
return;
return true;
}

length = SafeAccess::skipLoadArg(pc);
Expand All @@ -859,21 +872,21 @@ void Profiler::segvHandler(int signo, siginfo_t* siginfo, void* ucontext) {
frame.pc() += length;
frame.retval() = frame.arg1();
Counters::increment(HANDLED_SIGSEGV_SAFEFETCH);
return;
return true;
}

StackWalker::checkFault();

// Workaround for JDK-8313796. Setting cstack=dwarf also helps
if (VMStructs::isInterpretedFrameValidFunc((const void*)pc) && frame.skipFaultInstruction()) {
return;
return true;
}

if (WX_MEMORY && Trap::isFaultInstruction(pc)) {
return;
return true;
}

orig_segvHandler(signo, siginfo, ucontext);
return false;
}

void Profiler::setupSignalHandlers() {
Expand All @@ -883,7 +896,8 @@ void Profiler::setupSignalHandlers() {
}
if (VM::java_version() > 0) {
// HotSpot and J9 tolerate interposed SIGSEGV/SIGBUS handler; other JVMs probably not
orig_segvHandler = OS::replaceCrashHandler(segvHandler);
orig_segvHandler = OS::replaceSigsegvHandler(segvHandler);
orig_busHandler = OS::replaceSigbusHandler(busHandler);
}
}

Expand Down
3 changes: 3 additions & 0 deletions ddprof-lib/src/main/cpp/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class Profiler {
void lockAll();
void unlockAll();

static bool crashHandler(int signo, siginfo_t* siginfo, void* ucontext);

static Profiler* const _instance;

public:
Expand Down Expand Up @@ -291,6 +293,7 @@ class Profiler {
static void trapHandlerEntry(int signo, siginfo_t* siginfo, void* ucontext);
void trapHandler(int signo, siginfo_t* siginfo, void* ucontext);
static void segvHandler(int signo, siginfo_t* siginfo, void* ucontext);
static void busHandler(int signo, siginfo_t* siginfo, void* ucontext);
static void setupSignalHandlers();

static int registerThread(int tid);
Expand Down
6 changes: 5 additions & 1 deletion ddprof-lib/src/main/cpp/stackWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ int StackWalker::walkDwarf(void* ucontext, const void** callchain, int max_depth
return depth;
}

int StackWalker::walkVM(void* ucontext, ASGCT_CallFrame* frames, int max_depth) {
int StackWalker::walkVM(void* ucontext, ASGCT_CallFrame* frames, int max_depth,
const void* _termination_frame_begin, const void* _termination_frame_end) {
const void* pc;
uintptr_t fp;
uintptr_t sp;
Expand Down Expand Up @@ -257,6 +258,9 @@ int StackWalker::walkVM(void* ucontext, ASGCT_CallFrame* frames, int max_depth)

// Walk until the bottom of the stack or until the first Java frame
while (depth < max_depth) {
if (pc >= _termination_frame_begin && pc < _termination_frame_end) {
break;
}
if (CodeHeap::contains(pc)) {
NMethod* nm = CodeHeap::findNMethod(pc);
if (nm == NULL) {
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/stackWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class StackWalker {
public:
static int walkFP(void* ucontext, const void** callchain, int max_depth, StackContext* java_ctx, bool *truncated);
static int walkDwarf(void* ucontext, const void** callchain, int max_depth, StackContext* java_ctx, bool *truncated);
static int walkVM(void* ucontext, ASGCT_CallFrame* frames, int max_depth);
static int walkVM(void* ucontext, ASGCT_CallFrame* frames, int max_depth, const void* _termination_frame_begin, const void* _termination_frame_end);

static void checkFault();
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.datadoghq.profiler.cpu;

import com.datadoghq.profiler.AbstractProfilerTest;
import com.datadoghq.profiler.Platform;
import org.junit.jupiter.api.Test;
import org.openjdk.jmc.common.item.IItem;
import org.openjdk.jmc.common.item.IItemCollection;
import org.openjdk.jmc.common.item.IItemIterable;
import org.openjdk.jmc.common.item.IMemberAccessor;
import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;

import java.util.concurrent.ExecutionException;

import static org.junit.jupiter.api.Assertions.assertFalse;


public class VMStructsBasedCpuTest extends AbstractProfilerTest {

private ProfiledCode profiledCode;

@Override
protected void before() {
profiledCode = new ProfiledCode(profiler);
}

@Test
public void test() throws ExecutionException, InterruptedException {
for (int i = 0, id = 1; i < 100; i++, id += 3) {
profiledCode.method1(id);
}
stopProfiler();
IItemCollection events = verifyEvents("datadog.ExecutionSample");
for (IItemIterable it : events) {
IMemberAccessor<String, IItem> stackTraceAccessor = JdkAttributes.STACK_TRACE_STRING.getAccessor(it.getType());
for (IItem item : it) {
String stacktrace = stackTraceAccessor.getMember(item);
assertFalse(stacktrace.contains("JavaCalls::call_virtual()"),
"JavaCalls::call_virtual() (above call_stub) found in stack trace");
assertFalse(stacktrace.contains("call_stub()"),
"call_stub() (sentinel value used to halt unwinding) found in stack trace");
}
}
}

@Override
protected String getProfilerCommand() {
return "cpu=10ms" + (vmstructsUnwinderSupported() ? ",cstack=vm" : "");
}

private boolean vmstructsUnwinderSupported() {
return !Platform.isJ9() && !Platform.isZing();
}
}