Skip to content
Open
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
104 changes: 81 additions & 23 deletions ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ Java_com_datadoghq_profiler_JavaProfiler_init0(JNIEnv *env, jclass unused) {
return VM::initProfilerBridge(nullptr, true);
}

extern "C" JNIEXPORT jboolean JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_init0() {
return VM::initProfilerBridge(nullptr, true);
}

Comment on lines +71 to +75
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious, why have a JavaCritical variant for ìnit0`? This one doesn't look like it would ever be on the critical path so I don't see when the JVM would pick this one? 👀

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_stop0(JNIEnv *env, jobject unused) {
Error error = Profiler::instance()->stop();
Expand All @@ -78,10 +83,16 @@ Java_com_datadoghq_profiler_JavaProfiler_stop0(JNIEnv *env, jobject unused) {
}

extern "C" DLLEXPORT jint JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getTid0(JNIEnv *env, jobject unused) {
Java_com_datadoghq_profiler_JavaProfiler_getTid0(JNIEnv *env, jclass unused) {
return OS::threadId();
}

extern "C" DLLEXPORT jint JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_getTid0() {
return OS::threadId();
}


extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JavaProfiler_execute0(JNIEnv *env, jobject unused,
jstring command) {
Expand Down Expand Up @@ -113,22 +124,26 @@ Java_com_datadoghq_profiler_JavaProfiler_execute0(JNIEnv *env, jobject unused,

extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getStatus0(JNIEnv* env,
jobject unused) {
jclass unused) {
char msg[2048];
int ret = Profiler::instance()->status((char*)msg, sizeof(msg) - 1);
return env->NewStringUTF(msg);
}

extern "C" DLLEXPORT jlong JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getSamples(JNIEnv *env,
jobject unused) {
jclass unused) {
return (jlong)Profiler::instance()->total_samples();
}

extern "C" DLLEXPORT jlong JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_getSamples() {
return (jlong)Profiler::instance()->total_samples();
}
Comment on lines 133 to 142
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar note to init0 -- I only see getSamples being used for the MX bean so... not particularly perf-sensitive?


// some duplication between add and remove, though we want to avoid having an extra branch in the hot path
extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_filterThreadAdd0(JNIEnv *env,
jobject unused) {
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThreadAdd0() {
ProfiledThread *current = ProfiledThread::current();
if (unlikely(current == nullptr)) {
assert(false);
Expand Down Expand Up @@ -158,8 +173,13 @@ Java_com_datadoghq_profiler_JavaProfiler_filterThreadAdd0(JNIEnv *env,
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_filterThreadRemove0(JNIEnv *env,
jobject unused) {
Java_com_datadoghq_profiler_JavaProfiler_filterThreadAdd0(JNIEnv *env,
jclass unused) {
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThreadAdd0();
}
Comment on lines 175 to +179
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious -- do you know if this will add an extra indirection when calling this function? Or will the compiler inline/alias this call?


extern "C" DLLEXPORT void JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThreadRemove0() {
ProfiledThread *current = ProfiledThread::current();
if (unlikely(current == nullptr)) {
assert(false);
Expand All @@ -182,11 +202,15 @@ Java_com_datadoghq_profiler_JavaProfiler_filterThreadRemove0(JNIEnv *env,
thread_filter->remove(slot_id);
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_filterThreadRemove0(JNIEnv *env,
jclass unused) {
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThreadRemove0();
}

// Backward compatibility for existing code
extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_filterThread0(JNIEnv *env,
jobject unused,
jboolean enable) {
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThread0(jboolean enable) {
ProfiledThread *current = ProfiledThread::current();
Comment on lines 211 to 214
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, is this correct at all? I know this hasn't changed in this PR, but looking at AsyncProfiler::filterThread:

    private void filterThread(Thread thread, boolean enable) {
        if (thread == null || thread == Thread.currentThread()) {
            filterThread0(null, enable);
        } else {
            // Need to take lock to avoid race condition with a thread state change
            synchronized (thread) {
                Thread.State state = thread.getState();
                if (state != Thread.State.NEW && state != Thread.State.TERMINATED) {
                    filterThread0(thread, enable);
                }
            }
        }
    }

...that else branch seems to be completely broken?

(I looked a bit at java-profiler and dd-trace-java and it doesn't look like this code is still in-use... Perhaps easier to just remove it?)

if (unlikely(current == nullptr)) {
assert(false);
Expand Down Expand Up @@ -225,9 +249,16 @@ Java_com_datadoghq_profiler_JavaProfiler_filterThread0(JNIEnv *env,
}
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_filterThread0(JNIEnv *env,
jclass unused,
jboolean enable) {
JavaCritical_com_datadoghq_profiler_JavaProfiler_filterThread0(enable);
}

extern "C" DLLEXPORT jobject JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getContextPage0(JNIEnv *env,
jobject unused,
jclass unused,
jint tid) {
ContextPage page = Contexts::getPage((int)tid);
if (page.storage == 0) {
Expand All @@ -238,21 +269,32 @@ Java_com_datadoghq_profiler_JavaProfiler_getContextPage0(JNIEnv *env,

extern "C" DLLEXPORT jlong JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getContextPageOffset0(JNIEnv *env,
jobject unused,
jclass unused,
jint tid) {
ContextPage page = Contexts::getPage((int)tid);
return (jlong)page.storage;
}

extern "C" DLLEXPORT jlong JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_getContextPageOffset0(jint tid) {
ContextPage page = Contexts::getPage((int)tid);
return (jlong)page.storage;
}

extern "C" DLLEXPORT jint JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getMaxContextPages0(JNIEnv *env,
jobject unused) {
jclass unused) {
return (jint)Contexts::getMaxPages();
}

extern "C" DLLEXPORT jint JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_getMaxContextPages0() {
Comment on lines 284 to +291
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar note to init0 -- this doesn't look very performance-sensitive?

return (jint)Contexts::getMaxPages();
}

extern "C" DLLEXPORT jboolean JNICALL
Java_com_datadoghq_profiler_JavaProfiler_recordTrace0(
JNIEnv *env, jobject unused, jlong rootSpanId, jstring endpoint,
JNIEnv *env, jclass unused, jlong rootSpanId, jstring endpoint,
jstring operation, jint sizeLimit) {
JniString endpoint_str(env, endpoint);
u32 endpointLabel = Profiler::instance()->stringLabelMap()->bounded_lookup(
Expand All @@ -274,7 +316,7 @@ Java_com_datadoghq_profiler_JavaProfiler_recordTrace0(

extern "C" DLLEXPORT jint JNICALL
Java_com_datadoghq_profiler_JavaProfiler_registerConstant0(JNIEnv *env,
jobject unused,
jclass unused,
jstring value) {
JniString value_str(env, value);
u32 encoding = Profiler::instance()->contextValueMap()->bounded_lookup(
Expand All @@ -283,15 +325,15 @@ Java_com_datadoghq_profiler_JavaProfiler_registerConstant0(JNIEnv *env,
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_dump0(JNIEnv *env, jobject unused,
Java_com_datadoghq_profiler_JavaProfiler_dump0(JNIEnv *env, jclass unused,
jstring path) {
JniString path_str(env, path);
Profiler::instance()->dump(path_str.c_str(), path_str.length());
}

extern "C" DLLEXPORT jobject JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getDebugCounters0(JNIEnv *env,
jobject unused) {
jclass unused) {
#ifdef COUNTERS
return env->NewDirectByteBuffer((void *)Counters::getCounters(),
(jlong)Counters::size());
Expand All @@ -302,7 +344,7 @@ Java_com_datadoghq_profiler_JavaProfiler_getDebugCounters0(JNIEnv *env,

extern "C" DLLEXPORT jobjectArray JNICALL
Java_com_datadoghq_profiler_JavaProfiler_describeDebugCounters0(
JNIEnv *env, jobject unused) {
JNIEnv *env, jclass unused) {
#ifdef COUNTERS
std::vector<const char *> counter_names = Counters::describeCounters();
jobjectArray array = (jobjectArray)env->NewObjectArray(
Expand All @@ -320,7 +362,7 @@ Java_com_datadoghq_profiler_JavaProfiler_describeDebugCounters0(

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_recordSettingEvent0(
JNIEnv *env, jobject unused, jstring name, jstring value, jstring unit) {
JNIEnv *env, jclass unused, jstring name, jstring value, jstring unit) {
int tid = ProfiledThread::currentTid();
if (tid < 0) {
return;
Expand All @@ -343,7 +385,7 @@ static int dictionarizeClassName(JNIEnv* env, jstring className) {

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_recordQueueEnd0(
JNIEnv *env, jobject unused, jlong startTime, jlong endTime, jstring task,
JNIEnv *env, jclass unused, jlong startTime, jlong endTime, jstring task,
jstring scheduler, jthread origin, jstring queueType, jint queueLength) {
int tid = ProfiledThread::currentTid();
if (tid < 0) {
Expand Down Expand Up @@ -379,23 +421,39 @@ Java_com_datadoghq_profiler_JavaProfiler_recordQueueEnd0(

extern "C" DLLEXPORT jlong JNICALL
Java_com_datadoghq_profiler_JavaProfiler_currentTicks0(JNIEnv *env,
jobject unused) {
jclass unused) {
return TSC::ticks();
}

extern "C" DLLEXPORT jlong JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_currentTicks0() {
return TSC::ticks();
}

extern "C" DLLEXPORT jlong JNICALL
Java_com_datadoghq_profiler_JavaProfiler_tscFrequency0(JNIEnv *env,
jobject unused) {
jclass unused) {
return TSC::frequency();
}

extern "C" DLLEXPORT jlong JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_tscFrequency0() {
Comment on lines 433 to +440
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar note to init0 -- this value seems to be saved in a static final on the Java side and never called again.

return TSC::frequency();
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_mallocArenaMax0(JNIEnv *env,
jobject unused,
jclass unused,
jint maxArenas) {
ddprof::OS::mallocArenaMax(maxArenas);
}

extern "C" DLLEXPORT void JNICALL
JavaCritical_com_datadoghq_profiler_JavaProfiler_mallocArenaMax0(jint maxArenas) {
ddprof::OS::mallocArenaMax(maxArenas);
}


Comment on lines 444 to +456
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar note to init0 and others above.

extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JVMAccess_findStringJVMFlag0(JNIEnv *env,
jobject unused,
Expand Down
11 changes: 11 additions & 0 deletions ddprof-lib/src/main/cpp/vmStructs_dd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace ddprof {
initOffsets();
initJvmFunctions();
initUnsafeFunctions();
initCriticalJNINatives();
}

void VMStructs_::initOffsets() {
Expand Down Expand Up @@ -98,6 +99,16 @@ namespace ddprof {
}
}

void VMStructs_::initCriticalJNINatives() {
#ifdef __aarch64__
// aarch64 does not support CriticalJNINatives
JVMFlag* flag = JVMFlag::find("CriticalJNINatives", {JVMFlag::Type::Bool});
if (flag != nullptr && flag->get()) {
flag->set(0);
}
#endif // __aarch64__
}
Comment on lines +102 to +110
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious -- why is this needed? E.g. if the feature isn't supported, what does disabling it do?


const void *VMStructs_::findHeapUsageFunc() {
if (VM::hotspot_version() < 17) {
// For JDK 11 it is really unreliable to find the memory_usage function -
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/vmStructs_dd.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace ddprof {
static void initOffsets();
static void initJvmFunctions();
static void initUnsafeFunctions();
static void initCriticalJNINatives();

static void checkNativeBinding(jvmtiEnv *jvmti, JNIEnv *jni, jmethodID method,
void *address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public void stop() throws IllegalStateException {
*
* @return Number of samples
*/
public native long getSamples();
public static native long getSamples();

/**
* Get profiler agent version, e.g. "1.0"
Expand Down Expand Up @@ -470,10 +470,10 @@ public Map<String, Long> getDebugCounters() {
private native void stop0() throws IllegalStateException;
private native String execute0(String command) throws IllegalArgumentException, IllegalStateException, IOException;

private native void filterThreadAdd0();
private native void filterThreadRemove0();
private static native void filterThreadAdd0();
private static native void filterThreadRemove0();
// Backward compatibility for existing code
private native void filterThread0(boolean enable);
private static native void filterThread0(boolean enable);

private static native int getTid0();
private static native ByteBuffer getContextPage0(int tid);
Expand Down
Loading