-
-
Save qsLI/75413bc337c9d2f7b19a88e6ea3c4504 to your computer and use it in GitHub Desktop.
Java monitor contention profiler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <jvmti.h> | |
static jvmtiEnv* jvmti; | |
static jobject monitor; | |
static jlong blockTime; | |
static jlong blockCount; | |
extern "C" { | |
void JNICALL MonitorContendedEnter(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, jobject obj) { | |
if (env->IsSameObject(obj, monitor)) { | |
jlong blockStartTime; | |
jvmti->GetTime(&blockStartTime); | |
jvmti->SetThreadLocalStorage(thread, (const void*)(intptr_t)blockStartTime); | |
} | |
} | |
void JNICALL MonitorContendedEntered(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, jobject obj) { | |
if (env->IsSameObject(obj, monitor)) { | |
jlong blockStartTime, blockEndTime; | |
jvmti->GetTime(&blockEndTime); | |
jvmti->GetThreadLocalStorage(thread, (void**)&blockStartTime); | |
blockTime += (blockEndTime - blockStartTime); | |
blockCount++; | |
} | |
} | |
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { | |
vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0); | |
jvmtiCapabilities capabilities = {0}; | |
capabilities.can_generate_monitor_events = 1; | |
jvmti->AddCapabilities(&capabilities); | |
jvmtiEventCallbacks callbacks = {0}; | |
callbacks.MonitorContendedEnter = MonitorContendedEnter; | |
callbacks.MonitorContendedEntered = MonitorContendedEntered; | |
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); | |
return JNI_VERSION_1_4; | |
} | |
JNIEXPORT void JNICALL Java_Monitors_startProfiling(JNIEnv* env, jclass cls, jobject obj) { | |
monitor = env->NewGlobalRef(obj); | |
blockTime = 0; | |
blockCount = 0; | |
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL); | |
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL); | |
} | |
JNIEXPORT void JNICALL Java_Monitors_stopProfiling(JNIEnv* env, jclass cls) { | |
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL); | |
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL); | |
env->DeleteGlobalRef(monitor); | |
} | |
JNIEXPORT jlong JNICALL Java_Monitors_getBlockTime(JNIEnv* env, jclass cls) { | |
return blockTime; | |
} | |
JNIEXPORT jlong JNICALL Java_Monitors_getBlockCount(JNIEnv* env, jclass cls) { | |
return blockCount; | |
} | |
} // extern "C" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Monitors { | |
public static native void startProfiling(Object monitor); | |
public static native void stopProfiling(); | |
public static native long getBlockTime(); | |
public static native long getBlockCount(); | |
static { | |
System.loadLibrary("monitors"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MonitorsTest implements Runnable { | |
private final Object lock = new Object(); | |
private int counter; | |
@Override | |
public void run() { | |
for (int i = 0; i < 1000_000_000; i++) { | |
synchronized (lock) { | |
counter++; | |
} | |
} | |
} | |
public static void main(String[] args) throws InterruptedException { | |
MonitorsTest test = new MonitorsTest(); | |
Monitors.startProfiling(test.lock); | |
Thread[] threads = new Thread[4]; | |
for (int i = 0; i < threads.length; i++) { | |
threads[i] = new Thread(test); | |
threads[i].start(); | |
} | |
for (Thread thread : threads) { | |
thread.join(); | |
} | |
Monitors.stopProfiling(); | |
System.out.println("Total block time = " + Monitors.getBlockTime() + " ns"); | |
System.out.println("Total block count = " + Monitors.getBlockCount()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment