Skip to content

Instantly share code, notes, and snippets.

@apangin
Created July 5, 2016 20:30
Show Gist options
  • Save apangin/d9cdf0ae98309291b494a7c9f3954a29 to your computer and use it in GitHub Desktop.
Save apangin/d9cdf0ae98309291b494a7c9f3954a29 to your computer and use it in GitHub Desktop.
Java monitor contention profiler
#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"
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");
}
}
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