Skip to content

Commit 82a3272

Browse files
JVM Flags access API (#149)
Co-authored-by: datadog-datadog-prod-us1[bot] <88084959+datadog-datadog-prod-us1[bot]@users.noreply.github.com>
1 parent 86f94bd commit 82a3272

27 files changed

+1023
-245
lines changed

ddprof-lib/src/main/cpp/common.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef _COMMON_H
2+
#define _COMMON_H
3+
4+
#ifdef DEBUG
5+
#define TEST_LOG(fmt, ...) do { \
6+
fprintf(stdout, "[TEST::INFO] " fmt "\n", ##__VA_ARGS__); \
7+
fflush(stdout); \
8+
} while (0)
9+
#else
10+
#define TEST_LOG(fmt, ...) // No-op in non-debug mode
11+
#endif
12+
13+
#endif // _COMMON_H

ddprof-lib/src/main/cpp/ctimer_linux.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "ctimer.h"
2020
#include "debugSupport.h"
21+
#include "libraries.h"
2122
#include "profiler.h"
2223
#include "vmStructs.h"
2324
#include <assert.h>
@@ -64,7 +65,7 @@ static void **lookupThreadEntry() {
6465
// Depending on Zing version, pthread_setspecific is called either from
6566
// libazsys.so or from libjvm.so
6667
if (VM::isZing()) {
67-
CodeCache *libazsys = Profiler::instance()->findLibraryByName("libazsys");
68+
CodeCache *libazsys = Libraries::instance()->findLibraryByName("libazsys");
6869
if (libazsys != NULL) {
6970
void **entry = libazsys->findImport(im_pthread_setspecific);
7071
if (entry != NULL) {
@@ -73,7 +74,7 @@ static void **lookupThreadEntry() {
7374
}
7475
}
7576

76-
CodeCache *lib = Profiler::instance()->findJvmLibrary("libj9thr");
77+
CodeCache *lib = Libraries::instance()->findJvmLibrary("libj9thr");
7778
return lib != NULL ? lib->findImport(im_pthread_setspecific) : NULL;
7879
}
7980

ddprof-lib/src/main/cpp/javaApi.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "profiler.h"
2525
#include "thread.h"
2626
#include "tsc.h"
27+
#include "vmEntry.h"
2728
#include "vmStructs.h"
2829
#include "wallClock.h"
2930
#include <errno.h>
@@ -59,6 +60,12 @@ class JniString {
5960
int length() const { return _length; }
6061
};
6162

63+
extern "C" DLLEXPORT jboolean JNICALL
64+
Java_com_datadoghq_profiler_JavaProfiler_init0(JNIEnv *env, jclass unused) {
65+
// JavaVM* has already been stored when the native library was loaded so we can pass nullptr here
66+
return VM::initProfilerBridge(nullptr, true);
67+
}
68+
6269
extern "C" DLLEXPORT void JNICALL
6370
Java_com_datadoghq_profiler_JavaProfiler_stop0(JNIEnv *env, jobject unused) {
6471
Error error = Profiler::instance()->stop();
@@ -283,3 +290,82 @@ Java_com_datadoghq_profiler_JavaProfiler_mallocArenaMax0(JNIEnv *env,
283290
jint maxArenas) {
284291
OS::mallocArenaMax(maxArenas);
285292
}
293+
294+
extern "C" DLLEXPORT jstring JNICALL
295+
Java_com_datadoghq_profiler_JVMAccess_findStringJVMFlag0(JNIEnv *env,
296+
jobject unused,
297+
jstring flagName) {
298+
JniString flag_str(env, flagName);
299+
char** value = static_cast<char**>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::String}));
300+
if (value != NULL && *value != NULL) {
301+
return env->NewStringUTF(*value);
302+
}
303+
return NULL;
304+
}
305+
306+
extern "C" DLLEXPORT void JNICALL
307+
Java_com_datadoghq_profiler_JVMAccess_setStringJVMFlag0(JNIEnv *env,
308+
jobject unused,
309+
jstring flagName,
310+
jstring flagValue) {
311+
JniString flag_str(env, flagName);
312+
JniString value_str(env, flagValue);
313+
char** value = static_cast<char**>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::String}));
314+
if (value != NULL) {
315+
*value = strdup(value_str.c_str());
316+
}
317+
}
318+
319+
extern "C" DLLEXPORT jboolean JNICALL
320+
Java_com_datadoghq_profiler_JVMAccess_findBooleanJVMFlag0(JNIEnv *env,
321+
jobject unused,
322+
jstring flagName) {
323+
JniString flag_str(env, flagName);
324+
char* value = static_cast<char*>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::Bool}));
325+
if (value != NULL) {
326+
return ((*value) & 0xff) == 1;
327+
}
328+
return false;
329+
}
330+
331+
extern "C" DLLEXPORT void JNICALL
332+
Java_com_datadoghq_profiler_JVMAccess_setBooleanJVMFlag0(JNIEnv *env,
333+
jobject unused,
334+
jstring flagName,
335+
jboolean flagValue) {
336+
JniString flag_str(env, flagName);
337+
char* value = static_cast<char*>(JVMFlag::find(flag_str.c_str(), {JVMFlag::Type::Bool}));
338+
if (value != NULL) {
339+
*value = flagValue ? 1 : 0;
340+
}
341+
}
342+
343+
extern "C" DLLEXPORT jlong JNICALL
344+
Java_com_datadoghq_profiler_JVMAccess_findIntJVMFlag0(JNIEnv *env,
345+
jobject unused,
346+
jstring flagName) {
347+
JniString flag_str(env, flagName);
348+
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}));
349+
if (value != NULL) {
350+
return *value;
351+
}
352+
return 0;
353+
}
354+
355+
extern "C" DLLEXPORT jdouble JNICALL
356+
Java_com_datadoghq_profiler_JVMAccess_findFloatJVMFlag0(JNIEnv *env,
357+
jobject unused,
358+
jstring flagName) {
359+
JniString flag_str(env, flagName);
360+
double* value = static_cast<double*>(JVMFlag::find(flag_str.c_str(),{ JVMFlag::Type::Double}));
361+
if (value != NULL) {
362+
return *value;
363+
}
364+
return 0.0;
365+
}
366+
367+
extern "C" DLLEXPORT jboolean JNICALL
368+
Java_com_datadoghq_profiler_JVMAccess_healthCheck0(JNIEnv *env,
369+
jobject unused) {
370+
return true;
371+
}

ddprof-lib/src/main/cpp/libraries.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "codeCache.h"
2+
#include "libraries.h"
3+
#include "log.h"
4+
#include "symbols.h"
5+
#include "vmEntry.h"
6+
#include "vmStructs.h"
7+
8+
Libraries* Libraries::_instance = new Libraries();
9+
10+
void Libraries::mangle(const char *name, char *buf, size_t size) {
11+
char *buf_end = buf + size;
12+
strcpy(buf, "_ZN");
13+
buf += 3;
14+
15+
const char *c;
16+
while ((c = strstr(name, "::")) != NULL && buf + (c - name) + 4 < buf_end) {
17+
int n = snprintf(buf, buf_end - buf, "%d", (int)(c - name));
18+
if (n < 0 || n >= buf_end - buf) {
19+
if (n < 0) {
20+
Log::debug("Error in snprintf.");
21+
}
22+
goto end;
23+
}
24+
buf += n;
25+
memcpy(buf, name, c - name);
26+
buf += c - name;
27+
name = c + 2;
28+
}
29+
if (buf < buf_end) {
30+
snprintf(buf, buf_end - buf, "%d%sE*", (int)strlen(name), name);
31+
}
32+
33+
end:
34+
buf_end[-1] = '\0';
35+
}
36+
37+
void Libraries::updateSymbols(bool kernel_symbols) {
38+
Symbols::parseLibraries(&_native_libs, kernel_symbols);
39+
}
40+
41+
const void *Libraries::resolveSymbol(const char *name) {
42+
char mangled_name[256];
43+
if (strstr(name, "::") != NULL) {
44+
mangle(name, mangled_name, sizeof(mangled_name));
45+
name = mangled_name;
46+
}
47+
48+
size_t len = strlen(name);
49+
int native_lib_count = _native_libs.count();
50+
if (len > 0 && name[len - 1] == '*') {
51+
for (int i = 0; i < native_lib_count; i++) {
52+
const void *address = _native_libs[i]->findSymbolByPrefix(name, len - 1);
53+
if (address != NULL) {
54+
return address;
55+
}
56+
}
57+
} else {
58+
for (int i = 0; i < native_lib_count; i++) {
59+
const void *address = _native_libs[i]->findSymbol(name);
60+
if (address != NULL) {
61+
return address;
62+
}
63+
}
64+
}
65+
66+
return NULL;
67+
}
68+
69+
CodeCache *Libraries::findJvmLibrary(const char *j9_lib_name) {
70+
return VM::isOpenJ9() ? findLibraryByName(j9_lib_name) : VMStructs::libjvm();
71+
}
72+
73+
CodeCache *Libraries::findLibraryByName(const char *lib_name) {
74+
const size_t lib_name_len = strlen(lib_name);
75+
const int native_lib_count = _native_libs.count();
76+
for (int i = 0; i < native_lib_count; i++) {
77+
const char *s = _native_libs[i]->name();
78+
if (s != NULL) {
79+
const char *p = strrchr(s, '/');
80+
if (p != NULL && strncmp(p + 1, lib_name, lib_name_len) == 0) {
81+
return _native_libs[i];
82+
}
83+
}
84+
}
85+
return NULL;
86+
}
87+
88+
CodeCache *Libraries::findLibraryByAddress(const void *address) {
89+
const int native_lib_count = _native_libs.count();
90+
for (int i = 0; i < native_lib_count; i++) {
91+
if (_native_libs[i]->contains(address)) {
92+
return _native_libs[i];
93+
}
94+
}
95+
return NULL;
96+
}

ddprof-lib/src/main/cpp/libraries.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef _LIBRARIES_H
2+
#define _LIBRARIES_H
3+
4+
#include "codeCache.h"
5+
6+
class Libraries {
7+
private:
8+
static Libraries * _instance;
9+
10+
CodeCacheArray _native_libs;
11+
CodeCache _runtime_stubs;
12+
13+
static void mangle(const char *name, char *buf, size_t size);
14+
public:
15+
Libraries() : _native_libs(), _runtime_stubs("runtime stubs") {}
16+
void updateSymbols(bool kernel_symbols);
17+
const void *resolveSymbol(const char *name);
18+
// In J9 the 'libjvm' functionality is spread across multiple libraries
19+
// This function will return the 'libjvm' on non-J9 VMs and the library with the given name on J9 VMs
20+
CodeCache *findJvmLibrary(const char *j9_lib_name);
21+
CodeCache *findLibraryByName(const char *lib_name);
22+
CodeCache *findLibraryByAddress(const void *address);
23+
24+
static Libraries *instance() { return _instance; }
25+
};
26+
27+
#endif // _LIBRARIES_H

ddprof-lib/src/main/cpp/log.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void Log::log(LogLevel level, const char *msg, va_list args) {
8585
// be done at WARN level, and any logging done which prevents creation of the
8686
// JFR should be done at ERROR level
8787
if (level == LOG_WARN || (level >= _level && level < LOG_ERROR)) {
88-
Profiler::instance()->writeLog(level, buf, len);
88+
// Profiler::instance()->writeLog(level, buf, len);
8989
}
9090

9191
// always log errors, but only errors

ddprof-lib/src/main/cpp/perfEvents_linux.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "arch.h"
2020
#include "context.h"
2121
#include "debugSupport.h"
22+
#include "libraries.h"
2223
#include "log.h"
2324
#include "os.h"
2425
#include "perfEvents.h"
@@ -188,7 +189,7 @@ static void **lookupThreadEntry() {
188189
// Depending on Zing version, pthread_setspecific is called either from
189190
// libazsys.so or from libjvm.so
190191
if (VM::isZing()) {
191-
CodeCache *libazsys = Profiler::instance()->findLibraryByName("libazsys");
192+
CodeCache *libazsys = Libraries::instance()->findLibraryByName("libazsys");
192193
if (libazsys != NULL) {
193194
void **entry = libazsys->findImport(im_pthread_setspecific);
194195
if (entry != NULL) {
@@ -197,7 +198,7 @@ static void **lookupThreadEntry() {
197198
}
198199
}
199200

200-
CodeCache *lib = Profiler::instance()->findJvmLibrary("libj9thr");
201+
CodeCache *lib = Libraries::instance()->findJvmLibrary("libj9thr");
201202
return lib != NULL ? lib->findImport(im_pthread_setspecific) : NULL;
202203
}
203204

@@ -295,7 +296,7 @@ struct PerfEventType {
295296
} else {
296297
addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, buf);
297298
if (addr == 0) {
298-
addr = (__u64)(uintptr_t)Profiler::instance()->resolveSymbol(buf);
299+
addr = (__u64)(uintptr_t)Libraries::instance()->resolveSymbol(buf);
299300
}
300301
if (c == NULL) {
301302
// If offset is not specified explicitly, add the default breakpoint
@@ -794,7 +795,7 @@ Error PerfEvents::check(Arguments &args) {
794795
if (!(_ring & RING_KERNEL)) {
795796
attr.exclude_kernel = 1;
796797
} else if (!Symbols::haveKernelSymbols()) {
797-
Profiler::instance()->updateSymbols(true);
798+
Libraries::instance()->updateSymbols(true);
798799
attr.exclude_kernel = Symbols::haveKernelSymbols() ? 0 : 1;
799800
}
800801
if (!(_ring & RING_USER)) {

0 commit comments

Comments
 (0)