Skip to content

JVM Flags access API #149

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

Merged
merged 15 commits into from
Nov 12, 2024
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
13 changes: 13 additions & 0 deletions ddprof-lib/src/main/cpp/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef _COMMON_H
#define _COMMON_H

#ifdef DEBUG
#define TEST_LOG(fmt, ...) do { \
fprintf(stdout, "[TEST::INFO] " fmt "\n", ##__VA_ARGS__); \
fflush(stdout); \
} while (0)
#else
#define TEST_LOG(fmt, ...) // No-op in non-debug mode
#endif

#endif // _COMMON_H
5 changes: 3 additions & 2 deletions ddprof-lib/src/main/cpp/ctimer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "ctimer.h"
#include "debugSupport.h"
#include "libraries.h"
#include "profiler.h"
#include "vmStructs.h"
#include <assert.h>
Expand Down Expand Up @@ -64,7 +65,7 @@ static void **lookupThreadEntry() {
// Depending on Zing version, pthread_setspecific is called either from
// libazsys.so or from libjvm.so
if (VM::isZing()) {
CodeCache *libazsys = Profiler::instance()->findLibraryByName("libazsys");
CodeCache *libazsys = Libraries::instance()->findLibraryByName("libazsys");
if (libazsys != NULL) {
void **entry = libazsys->findImport(im_pthread_setspecific);
if (entry != NULL) {
Expand All @@ -73,7 +74,7 @@ static void **lookupThreadEntry() {
}
}

CodeCache *lib = Profiler::instance()->findJvmLibrary("libj9thr");
CodeCache *lib = Libraries::instance()->findJvmLibrary("libj9thr");
return lib != NULL ? lib->findImport(im_pthread_setspecific) : NULL;
}

Expand Down
86 changes: 86 additions & 0 deletions ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "profiler.h"
#include "thread.h"
#include "tsc.h"
#include "vmEntry.h"
#include "vmStructs.h"
#include "wallClock.h"
#include <errno.h>
Expand Down Expand Up @@ -59,6 +60,12 @@ class JniString {
int length() const { return _length; }
};

extern "C" DLLEXPORT jboolean JNICALL
Java_com_datadoghq_profiler_JavaProfiler_init0(JNIEnv *env, jclass unused) {
// JavaVM* has already been stored when the native library was loaded so we can pass nullptr here
return VM::initProfilerBridge(nullptr, true);
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_stop0(JNIEnv *env, jobject unused) {
Error error = Profiler::instance()->stop();
Expand Down Expand Up @@ -283,3 +290,82 @@ Java_com_datadoghq_profiler_JavaProfiler_mallocArenaMax0(JNIEnv *env,
jint maxArenas) {
OS::mallocArenaMax(maxArenas);
}

extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JVMAccess_findStringJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName) {
JniString flag_str(env, flagName);
char** value = static_cast<char**>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::String}));
if (value != NULL && *value != NULL) {
return env->NewStringUTF(*value);
}
return NULL;
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JVMAccess_setStringJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName,
jstring flagValue) {
JniString flag_str(env, flagName);
JniString value_str(env, flagValue);
char** value = static_cast<char**>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::String}));
if (value != NULL) {
*value = strdup(value_str.c_str());
}
}

extern "C" DLLEXPORT jboolean JNICALL
Java_com_datadoghq_profiler_JVMAccess_findBooleanJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName) {
JniString flag_str(env, flagName);
char* value = static_cast<char*>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::Bool}));
if (value != NULL) {
return ((*value) & 0xff) == 1;
}
return false;
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JVMAccess_setBooleanJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName,
jboolean flagValue) {
JniString flag_str(env, flagName);
char* value = static_cast<char*>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::Bool}));
if (value != NULL) {
*value = flagValue ? 1 : 0;
}
}

extern "C" DLLEXPORT jlong JNICALL
Java_com_datadoghq_profiler_JVMAccess_findIntJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName) {
JniString flag_str(env, flagName);
long* value = static_cast<long*>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::Int, JVMFlag::Type::Uint, JVMFlag::Type::Intx, JVMFlag::Type::Uintx, JVMFlag::Type::Uint64_t, JVMFlag::Type::Size_t}));
if (value != NULL) {
return *value;
}
return 0;
}

extern "C" DLLEXPORT jdouble JNICALL
Java_com_datadoghq_profiler_JVMAccess_findFloatJVMFlag0(JNIEnv *env,
jobject unused,
jstring flagName) {
JniString flag_str(env, flagName);
double* value = static_cast<double*>(JVMFlag::find(flag_str.c_str(),{ JVMFlag::Type::Double}));
if (value != NULL) {
return *value;
}
return 0.0;
}

extern "C" DLLEXPORT jboolean JNICALL
Java_com_datadoghq_profiler_JVMAccess_healthCheck0(JNIEnv *env,
jobject unused) {
return true;
}
96 changes: 96 additions & 0 deletions ddprof-lib/src/main/cpp/libraries.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "codeCache.h"
#include "libraries.h"
#include "log.h"
#include "symbols.h"
#include "vmEntry.h"
#include "vmStructs.h"

Libraries* Libraries::_instance = new Libraries();

void Libraries::mangle(const char *name, char *buf, size_t size) {
char *buf_end = buf + size;
strcpy(buf, "_ZN");
buf += 3;

const char *c;
while ((c = strstr(name, "::")) != NULL && buf + (c - name) + 4 < buf_end) {
int n = snprintf(buf, buf_end - buf, "%d", (int)(c - name));
if (n < 0 || n >= buf_end - buf) {
if (n < 0) {
Log::debug("Error in snprintf.");
}
goto end;
}
buf += n;
memcpy(buf, name, c - name);
buf += c - name;
name = c + 2;
}
if (buf < buf_end) {
snprintf(buf, buf_end - buf, "%d%sE*", (int)strlen(name), name);
}

end:
buf_end[-1] = '\0';
}

void Libraries::updateSymbols(bool kernel_symbols) {
Symbols::parseLibraries(&_native_libs, kernel_symbols);
}

const void *Libraries::resolveSymbol(const char *name) {
char mangled_name[256];
if (strstr(name, "::") != NULL) {
mangle(name, mangled_name, sizeof(mangled_name));
name = mangled_name;
}

size_t len = strlen(name);
int native_lib_count = _native_libs.count();
if (len > 0 && name[len - 1] == '*') {
for (int i = 0; i < native_lib_count; i++) {
const void *address = _native_libs[i]->findSymbolByPrefix(name, len - 1);
if (address != NULL) {
return address;
}
}
} else {
for (int i = 0; i < native_lib_count; i++) {
const void *address = _native_libs[i]->findSymbol(name);
if (address != NULL) {
return address;
}
}
}

return NULL;
}

CodeCache *Libraries::findJvmLibrary(const char *j9_lib_name) {
return VM::isOpenJ9() ? findLibraryByName(j9_lib_name) : VMStructs::libjvm();
}

CodeCache *Libraries::findLibraryByName(const char *lib_name) {
const size_t lib_name_len = strlen(lib_name);
const int native_lib_count = _native_libs.count();
for (int i = 0; i < native_lib_count; i++) {
const char *s = _native_libs[i]->name();
if (s != NULL) {
const char *p = strrchr(s, '/');
if (p != NULL && strncmp(p + 1, lib_name, lib_name_len) == 0) {
return _native_libs[i];
}
}
}
return NULL;
}

CodeCache *Libraries::findLibraryByAddress(const void *address) {
const int native_lib_count = _native_libs.count();
for (int i = 0; i < native_lib_count; i++) {
if (_native_libs[i]->contains(address)) {
return _native_libs[i];
}
}
return NULL;
}
27 changes: 27 additions & 0 deletions ddprof-lib/src/main/cpp/libraries.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef _LIBRARIES_H
#define _LIBRARIES_H

#include "codeCache.h"

class Libraries {
private:
static Libraries * _instance;

CodeCacheArray _native_libs;
CodeCache _runtime_stubs;

static void mangle(const char *name, char *buf, size_t size);
public:
Libraries() : _native_libs(), _runtime_stubs("runtime stubs") {}
void updateSymbols(bool kernel_symbols);
const void *resolveSymbol(const char *name);
// In J9 the 'libjvm' functionality is spread across multiple libraries
// This function will return the 'libjvm' on non-J9 VMs and the library with the given name on J9 VMs
CodeCache *findJvmLibrary(const char *j9_lib_name);
CodeCache *findLibraryByName(const char *lib_name);
CodeCache *findLibraryByAddress(const void *address);

static Libraries *instance() { return _instance; }
};

#endif // _LIBRARIES_H
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void Log::log(LogLevel level, const char *msg, va_list args) {
// be done at WARN level, and any logging done which prevents creation of the
// JFR should be done at ERROR level
if (level == LOG_WARN || (level >= _level && level < LOG_ERROR)) {
Profiler::instance()->writeLog(level, buf, len);
// Profiler::instance()->writeLog(level, buf, len);
}

// always log errors, but only errors
Expand Down
9 changes: 5 additions & 4 deletions ddprof-lib/src/main/cpp/perfEvents_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "arch.h"
#include "context.h"
#include "debugSupport.h"
#include "libraries.h"
#include "log.h"
#include "os.h"
#include "perfEvents.h"
Expand Down Expand Up @@ -188,7 +189,7 @@ static void **lookupThreadEntry() {
// Depending on Zing version, pthread_setspecific is called either from
// libazsys.so or from libjvm.so
if (VM::isZing()) {
CodeCache *libazsys = Profiler::instance()->findLibraryByName("libazsys");
CodeCache *libazsys = Libraries::instance()->findLibraryByName("libazsys");
if (libazsys != NULL) {
void **entry = libazsys->findImport(im_pthread_setspecific);
if (entry != NULL) {
Expand All @@ -197,7 +198,7 @@ static void **lookupThreadEntry() {
}
}

CodeCache *lib = Profiler::instance()->findJvmLibrary("libj9thr");
CodeCache *lib = Libraries::instance()->findJvmLibrary("libj9thr");
return lib != NULL ? lib->findImport(im_pthread_setspecific) : NULL;
}

Expand Down Expand Up @@ -295,7 +296,7 @@ struct PerfEventType {
} else {
addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, buf);
if (addr == 0) {
addr = (__u64)(uintptr_t)Profiler::instance()->resolveSymbol(buf);
addr = (__u64)(uintptr_t)Libraries::instance()->resolveSymbol(buf);
}
if (c == NULL) {
// If offset is not specified explicitly, add the default breakpoint
Expand Down Expand Up @@ -794,7 +795,7 @@ Error PerfEvents::check(Arguments &args) {
if (!(_ring & RING_KERNEL)) {
attr.exclude_kernel = 1;
} else if (!Symbols::haveKernelSymbols()) {
Profiler::instance()->updateSymbols(true);
Libraries::instance()->updateSymbols(true);
attr.exclude_kernel = Symbols::haveKernelSymbols() ? 0 : 1;
}
if (!(_ring & RING_USER)) {
Expand Down
Loading
Loading