Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downstream async-profiler fixes and workarounds #52

Merged
merged 6 commits into from
Dec 18, 2023
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
46 changes: 44 additions & 2 deletions ddprof-lib/src/main/cpp/perfEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
#ifndef _PERFEVENTS_H
#define _PERFEVENTS_H

#ifdef __linux__

#include <signal.h>
#include "arch.h"
#include "engine.h"


class PerfEvent;
class PerfEventType;
class StackContext;
Expand Down Expand Up @@ -58,7 +59,7 @@ class PerfEvents : public Engine {
return "PerfEvents";
}

static int walkKernel(int tid, const void** callchain, int max_depth, StackContext *java_ctx);
static int walkKernel(int tid, const void** callchain, int max_depth, StackContext* java_ctx);

static void resetBuffer(int tid);

Expand All @@ -69,4 +70,45 @@ class PerfEvents : public Engine {
}
};

#else

#include "engine.h"

class StackContext;

class PerfEvents : public Engine {
public:
Error check(Arguments& args) {
return Error("PerfEvents are unsupported on this platform");
}

Error start(Arguments& args) {
return Error("PerfEvents are unsupported on this platform");
}

static int walkKernel(int tid, const void** callchain, int max_depth, StackContext* java_ctx) {
return 0;
}

inline void enableEvents(bool enabled) {}

static void resetBuffer(int tid) {
}

static const char* getEventName(int event_id) {
return NULL;
}

virtual int registerThread(int tid) {
return -1;
}
virtual void unregisterThread(int tid) {}

long interval() const {
return -1;
}
};

#endif // __linux__

#endif // _PERFEVENTS_H
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/perfEvents_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ struct PerfEventType {

static PerfEventType* forName(const char* name) {
// Look through the table of predefined perf events
for (int i = 0; i < IDX_PREDEFINED; i++) {
for (int i = 0; i <= IDX_PREDEFINED; i++) {
if (strcmp(name, AVAILABLE_EVENTS[i].name) == 0) {
return &AVAILABLE_EVENTS[i];
}
Expand Down
67 changes: 0 additions & 67 deletions ddprof-lib/src/main/cpp/perfEvents_macos.cpp

This file was deleted.

14 changes: 11 additions & 3 deletions ddprof-lib/src/main/cpp/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,14 +828,22 @@ void Profiler::trapHandler(int signo, siginfo_t* siginfo, void* ucontext) {
void Profiler::segvHandler(int signo, siginfo_t* siginfo, void* ucontext) {
StackFrame frame(ucontext);

uintptr_t length = SafeAccess::skipFaultInstruction(frame.pc());
uintptr_t length = SafeAccess::skipLoad(frame.pc());
if (length > 0) {
// Skip the fault instruction, as if it successfully loaded NULL
frame.pc() += length;
frame.retval() = 0;
return;
}

length = SafeAccess::skipLoadArg(frame.pc());
if (length > 0) {
// Act as if the load returned default_value argument
frame.pc() += length;
frame.retval() = frame.arg1();
return;
}

if (WX_MEMORY && Trap::isFaultInstruction(frame.pc())) {
return;
}
Expand Down Expand Up @@ -1201,10 +1209,10 @@ Error Profiler::dump(const char* path, const int length) {
Counters::set(CODECACHE_NATIVE_COUNT, _native_libs.count());
Counters::set(CODECACHE_NATIVE_SIZE_BYTES, _native_libs.memoryUsage());
Counters::set(CODECACHE_RUNTIME_STUBS_SIZE_BYTES, _native_libs.memoryUsage());

lockAll();
Error err = _jfr.dump(path, length);

// Reset calltrace storage
if (!_omit_stacktraces) {
_call_trace_storage.clear();
Expand Down
21 changes: 20 additions & 1 deletion ddprof-lib/src/main/cpp/safeAccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ class SafeAccess {
return *ptr;
}

static uintptr_t skipFaultInstruction(uintptr_t pc) {
NOINLINE __attribute__((aligned(16)))
static u32 load32(u32* ptr, u32 default_value) {
return *ptr;
}

NOINLINE __attribute__((aligned(16)))
static void* loadPtr(void** ptr, void* default_value) {
return *ptr;
}

static uintptr_t skipLoad(uintptr_t pc) {
if (pc - (uintptr_t)load < 16) {
#if defined(__x86_64__)
return *(u16*)pc == 0x8b48 ? 3 : 0; // mov rax, [reg]
Expand All @@ -51,6 +61,15 @@ class SafeAccess {
}
return 0;
}

static uintptr_t skipLoadArg(uintptr_t pc) {
#if defined(__aarch64__)
if ((pc - (uintptr_t)load32) < 16 || (pc - (uintptr_t)loadPtr) < 16) {
return 4;
}
#endif
return 0;
}
};

#endif // _SAFEACCESS_H
25 changes: 24 additions & 1 deletion ddprof-lib/src/main/cpp/stackFrame_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,30 @@ bool StackFrame::checkInterruptedSyscall() {
return retval() == (uintptr_t)-EINTR;
}
#else
return retval() == (uintptr_t)-EINTR;
if (retval() == (uintptr_t)-EINTR) {
// Workaround for JDK-8237858: restart the interrupted poll / epoll_wait manually
uintptr_t nr = (uintptr_t)REG(regs[8], x[8]);
if (nr == SYS_ppoll || (nr == SYS_epoll_pwait && (int)arg3() == -1)) {
// Check against unreadable page for the loop below
const uintptr_t max_distance = 24;
if ((pc() & 0xfff) < max_distance && SafeAccess::load32((u32*)(pc() - max_distance), 0) == 0) {
return true;
}
// Try to restore the original value of x0 saved in another register
for (uintptr_t prev_pc = pc() - 4; pc() - prev_pc <= max_distance; prev_pc -= 4) {
instruction_t insn = *(instruction_t*)prev_pc;
unsigned int reg = (insn >> 16) & 31;
if ((insn & 0xffe0ffff) == 0xaa0003e0 && reg >= 6) {
// mov x0, reg
REG(regs[0], x[0]) = REG(regs[reg], x[reg]);
pc() -= sizeof(instruction_t);
break;
}
}
}
return true;
}
return false;
#endif
}

Expand Down
13 changes: 9 additions & 4 deletions ddprof-lib/src/main/cpp/stackFrame_x64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,15 @@ bool StackFrame::checkInterruptedSyscall() {
#else
if (retval() == (uintptr_t)-EINTR) {
// Workaround for JDK-8237858: restart the interrupted poll() manually.
// Check if the previous instruction is mov eax, SYS_poll with infinite timeout
if ((int)arg2() == -1) {
uintptr_t pc = this->pc();
if ((pc & 0xfff) >= 7 && *(unsigned char*)(pc - 7) == 0xb8 && *(int*)(pc - 6) == SYS_poll) {
// Check if the previous instruction is mov eax, SYS_poll with infinite timeout or
// mov eax, SYS_ppoll with any timeout (ppoll adjusts timeout automatically)
uintptr_t pc = this->pc();
if ((pc & 0xfff) >= 7 && *(instruction_t*)(pc - 7) == 0xb8) {
int nr = *(int*)(pc - 6);
if (nr == SYS_ppoll
|| (nr == SYS_poll && (int)REG(RDX, rdx) == -1)
|| (nr == SYS_epoll_wait && (int)REG(R10, r10) == -1)
|| (nr == SYS_epoll_pwait && (int)REG(R10, r10) == -1)) {
this->pc() = pc - 7;
}
}
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/vmEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "j9ObjectSampler.h"
#include "os.h"
#include "profiler.h"
#include "safeAccess.h"
#include "log.h"
#include "vmStructs.h"
#include "jniHelper.h"
Expand Down
47 changes: 35 additions & 12 deletions ddprof-lib/src/main/cpp/vmStructs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ void VMStructs::init(CodeCache* libjvm) {
// Run when VM is initialized and JNI is available
void VMStructs::ready() {
resolveOffsets();
patchSafeFetch();

JNIEnv* env = VM::jni();
initThreadBridge(env);
Expand Down Expand Up @@ -417,6 +418,21 @@ void VMStructs::initJvmFunctions() {
initUnsafeFunctions();
}

void VMStructs::patchSafeFetch() {
// Workarounds for JDK-8307549 and JDK-8321116
if (WX_MEMORY && VM::isHotspot() && VM::java_version() == 17) {
void** entry = (void**)_libjvm->findSymbol("_ZN12StubRoutines18_safefetch32_entryE");
if (entry != NULL) {
*entry = (void*)SafeAccess::load32;
}
} else if (WX_MEMORY && VM::isHotspot() && VM::java_version() == 11) {
void** entry = (void**)_libjvm->findSymbol("_ZN12StubRoutines17_safefetchN_entryE");
if (entry != NULL) {
*entry = (void*)SafeAccess::loadPtr;
}
}
}

void VMStructs::initTLS(void* vm_thread) {
for (int i = 0; i < 1024; i++) {
if (pthread_getspecific((pthread_key_t)i) == vm_thread) {
Expand Down Expand Up @@ -460,20 +476,27 @@ void VMStructs::initLogging(JNIEnv* env) {
if (VM::java_version() >= 15 && !VM::isOpenJ9()) {
VMManagement* management = VM::management();
if (management != NULL) {
jstring log_config = management->ExecuteDiagnosticCommand(env, env->NewStringUTF("VM.log list"));
if (log_config != NULL) {
char cmd[128] = "VM.log what=jni+resolve=error decorators=";
const char* s = env->GetStringUTFChars(log_config, NULL);
if (s != NULL) {
const char* p = strstr(s, "#0: ");
const char* q;
if (p != NULL && (p = strchr(p + 4, ' ')) != NULL && (p = strchr(p + 1, ' ')) != NULL &&
(q = strchr(p + 1, '\n')) != NULL && q - p < sizeof(cmd) - 41) {
memcpy(cmd + 41, p + 1, q - p - 1);
jstring vm_log_str = env->NewStringUTF("VM.log list");
if (vm_log_str != NULL) {
jstring log_config = management->ExecuteDiagnosticCommand(env, vm_log_str);
if (log_config != NULL) {
char cmd[128] = "VM.log what=jni+resolve=error decorators=";
const char* s = env->GetStringUTFChars(log_config, NULL);
if (s != NULL) {
const char* p = strstr(s, "#0: ");
if (p != NULL && (p = strchr(p + 4, ' ')) != NULL && (p = strchr(p + 1, ' ')) != NULL) {
const char* q = p + 1; // start of decorators
while (*q > ' ') q++;
if (q - p < sizeof(cmd) - 41) {
memcpy(cmd + 41, p + 1, q - p - 1);
}
}
env->ReleaseStringUTFChars(log_config, s);
}
if ((vm_log_str = env->NewStringUTF(cmd)) != NULL) {
management->ExecuteDiagnosticCommand(env, vm_log_str);
}
env->ReleaseStringUTFChars(log_config, s);
}
management->ExecuteDiagnosticCommand(env, env->NewStringUTF(cmd));
}
}
env->ExceptionClear();
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/vmStructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class VMStructs {
static uintptr_t readSymbol(const char* symbol_name);
static void initOffsets();
static void resolveOffsets();
static void patchSafeFetch();
static void initJvmFunctions();
static void initTLS(void* vm_thread);
static void initThreadBridge(JNIEnv* env);
Expand Down