< prev index next >

test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitor.c

Print this page
rev 49244 : [mq]: event-only
rev 49246 : [mq]: event4
rev 49247 : [mq]: event5

*** 20,29 **** --- 20,30 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ #include <assert.h> + #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "jvmti.h"
*** 48,66 **** #define PRINT_OUT 1 #define MAX_TRACES 400 static jvmtiEnv *jvmti = NULL; ! typedef struct _LiveObjectTrace{ jvmtiFrameInfo* frames; size_t frame_count; ! } LiveObjectTrace; typedef struct _EventStorage { int live_object_size; int live_object_count; ! LiveObjectTrace** live_objects; } EventStorage; typedef struct _ExpectedContentFrame { const char *name; const char *signature; --- 49,77 ---- #define PRINT_OUT 1 #define MAX_TRACES 400 static jvmtiEnv *jvmti = NULL; ! typedef struct _ObjectTrace{ ! jweak object; ! size_t size; jvmtiFrameInfo* frames; size_t frame_count; ! jthread thread; ! } ObjectTrace; typedef struct _EventStorage { + int compaction_required; int live_object_size; int live_object_count; ! ObjectTrace** live_objects; ! ! int garbage_history_size; ! int garbage_history_index; ! ObjectTrace** garbage_collected_objects; ! ! pthread_mutex_t mutex; } EventStorage; typedef struct _ExpectedContentFrame { const char *name; const char *signature;
*** 108,118 **** return -1; } } static jboolean check_sample_content(JNIEnv *env, ! LiveObjectTrace* trace, ExpectedContentFrame *expected, size_t expected_count, int print_out_comparisons) { if (expected_count > trace->frame_count) { return FALSE; --- 119,129 ---- return -1; } } static jboolean check_sample_content(JNIEnv *env, ! ObjectTrace* trace, ExpectedContentFrame *expected, size_t expected_count, int print_out_comparisons) { if (expected_count > trace->frame_count) { return FALSE;
*** 220,296 **** // Internal storage system implementation. static EventStorage global_event_storage; static int event_storage_get_count(EventStorage* storage) { ! return storage->live_object_count; } static jboolean event_storage_contains(JNIEnv* env, EventStorage* storage, ExpectedContentFrame* frames, size_t size) { fprintf(stderr, "Checking storage count %d\n", storage->live_object_count); int i; for (i = 0; i < storage->live_object_count; i++) { ! LiveObjectTrace* trace = storage->live_objects[i]; if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { return TRUE; } } return FALSE; } static void event_storage_augment_storage(EventStorage* storage) { int new_max = (storage->live_object_size * 2) + 1; ! LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); int current_count = storage->live_object_count; memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); free(storage->live_objects); storage->live_objects = new_objects; storage->live_object_size = new_max; } static void event_storage_add(EventStorage* storage, jthread thread, jobject object, jclass klass, jlong size) { jvmtiFrameInfo frames[64]; jint count; jvmtiError err; err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); if (err == JVMTI_ERROR_NONE && count >= 1) { if (storage->live_object_count >= storage->live_object_size) { event_storage_augment_storage(storage); } assert(storage->live_object_count < storage->live_object_size); jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames)); memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); ! LiveObjectTrace* live_object = malloc(sizeof(*live_object)); live_object->frames = allocated_frames; live_object->frame_count = count; storage->live_objects[storage->live_object_count] = live_object; storage->live_object_count++; } } ! static void event_storage_reset(EventStorage* storage) { int max = storage->live_object_count; int i; for (i = 0; i < max; i++) { ! LiveObjectTrace* object = storage->live_objects[i]; ! free(object); } ! free(storage->live_objects); ! memset(storage, 0, sizeof(*storage)); } // Start of the JVMTI agent code. static const char *EXC_CNAME = "java/lang/Exception"; --- 231,434 ---- // Internal storage system implementation. static EventStorage global_event_storage; + static void event_storage_set_compaction_required(EventStorage* storage) { + pthread_mutex_lock(&storage->mutex); + storage->compaction_required = 1; + pthread_mutex_unlock(&storage->mutex); + } + + static int event_storage_get_compaction_required(EventStorage* storage) { + pthread_mutex_lock(&storage->mutex); + int result = storage->compaction_required; + pthread_mutex_unlock(&storage->mutex); + return result; + } + + static void event_storage_set_garbage_history(EventStorage* storage, int value) { + pthread_mutex_lock(&storage->mutex); + global_event_storage.garbage_history_size = value; + free(global_event_storage.garbage_collected_objects); + size_t size = + sizeof(*global_event_storage.garbage_collected_objects) * value; + global_event_storage.garbage_collected_objects = malloc(size); + memset(global_event_storage.garbage_collected_objects, 0, size); + pthread_mutex_unlock(&storage->mutex); + } + + // No mutex here, it is handled by the caller. + static void event_storage_add_garbage_collected_object(EventStorage* storage, + ObjectTrace* object) { + int idx = storage->garbage_history_index; + free(storage->garbage_collected_objects[idx]); + storage->garbage_collected_objects[idx] = object; + storage->garbage_history_index = (idx + 1) % storage->garbage_history_size; + } + static int event_storage_get_count(EventStorage* storage) { ! pthread_mutex_lock(&storage->mutex); ! int result = storage->live_object_count; ! pthread_mutex_unlock(&storage->mutex); ! return result; ! } ! ! static double event_storage_get_average_rate(EventStorage* storage) { ! double accumulation = 0; ! ! pthread_mutex_lock(&storage->mutex); ! int max_size = storage->live_object_count; ! ! for (int i = 0; i < max_size; i++) { ! accumulation += storage->live_objects[i]->size; ! } ! pthread_mutex_unlock(&storage->mutex); ! return accumulation / max_size; } static jboolean event_storage_contains(JNIEnv* env, EventStorage* storage, ExpectedContentFrame* frames, size_t size) { + pthread_mutex_lock(&storage->mutex); fprintf(stderr, "Checking storage count %d\n", storage->live_object_count); int i; for (i = 0; i < storage->live_object_count; i++) { ! ObjectTrace* trace = storage->live_objects[i]; ! ! if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { ! pthread_mutex_unlock(&storage->mutex); ! return TRUE; ! } ! } ! pthread_mutex_unlock(&storage->mutex); ! return FALSE; ! } ! ! static jboolean event_storage_garbage_contains(JNIEnv* env, ! EventStorage* storage, ! ExpectedContentFrame* frames, ! size_t size) { ! pthread_mutex_lock(&storage->mutex); ! fprintf(stderr, "Checking garbage storage count %d\n", ! storage->garbage_history_size); ! int i; ! for (i = 0; i < storage->garbage_history_size; i++) { ! ObjectTrace* trace = storage->garbage_collected_objects[i]; ! ! if (trace == NULL) { ! continue; ! } if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { + pthread_mutex_unlock(&storage->mutex); return TRUE; } } + pthread_mutex_unlock(&storage->mutex); return FALSE; } + // No mutex here, handled by the caller. static void event_storage_augment_storage(EventStorage* storage) { int new_max = (storage->live_object_size * 2) + 1; ! ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); int current_count = storage->live_object_count; memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); free(storage->live_objects); storage->live_objects = new_objects; storage->live_object_size = new_max; } static void event_storage_add(EventStorage* storage, + JNIEnv* jni, jthread thread, jobject object, jclass klass, jlong size) { jvmtiFrameInfo frames[64]; jint count; jvmtiError err; + err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); if (err == JVMTI_ERROR_NONE && count >= 1) { + pthread_mutex_lock(&storage->mutex); + if (storage->live_object_count >= storage->live_object_size) { event_storage_augment_storage(storage); } assert(storage->live_object_count < storage->live_object_size); jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames)); memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); ! ObjectTrace* live_object = malloc(sizeof(*live_object)); live_object->frames = allocated_frames; live_object->frame_count = count; + live_object->size = size; + live_object->thread = thread; + live_object->object = (*jni)->NewWeakGlobalRef(jni, object); storage->live_objects[storage->live_object_count] = live_object; storage->live_object_count++; + + pthread_mutex_unlock(&storage->mutex); } } ! static void event_storage_compact(EventStorage* storage, JNIEnv* jni) { ! pthread_mutex_lock(&storage->mutex); ! storage->compaction_required = 0; ! int max = storage->live_object_count; + int i, dest; + ObjectTrace** live_objects = storage->live_objects; + + for (i = 0, dest = 0; i < max; i++) { + ObjectTrace* live_object = live_objects[i]; + jweak object = live_object->object; + + if (!(*jni)->IsSameObject(jni, object, NULL)) { + if (dest != i) { + live_objects[dest] = live_object; + dest++; + } + } else { + event_storage_add_garbage_collected_object(storage, live_object); + } + } + + storage->live_object_count = dest; + pthread_mutex_unlock(&storage->mutex); + } + + static void event_storage_free_objects(ObjectTrace** array, int max) { int i; for (i = 0; i < max; i++) { ! free(array[i]), array[i] = NULL; } ! } ! ! static void event_storage_reset(EventStorage* storage) { ! pthread_mutex_lock(&storage->mutex); ! ! // Reset everything except the mutex and the garbage collection. ! event_storage_free_objects(storage->live_objects, ! storage->live_object_count); ! storage->live_object_size = 0; ! storage->live_object_count = 0; ! free(storage->live_objects), storage->live_objects = NULL; ! ! event_storage_free_objects(storage->garbage_collected_objects, ! storage->garbage_history_size); ! ! storage->compaction_required = 0; ! storage->garbage_history_index = 0; ! ! pthread_mutex_unlock(&storage->mutex); } // Start of the JVMTI agent code. static const char *EXC_CNAME = "java/lang/Exception";
*** 347,360 **** JNIEnv* jni_env, jthread thread, jobject object, jclass object_klass, jlong size) { ! event_storage_add(&global_event_storage, thread, object, object_klass, size); } static int enable_notifications() { return check_error((*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), "Set event notifications"); } --- 485,514 ---- JNIEnv* jni_env, jthread thread, jobject object, jclass object_klass, jlong size) { ! if (event_storage_get_compaction_required(&global_event_storage)) { ! event_storage_compact(&global_event_storage, jni_env); ! } ! ! event_storage_add(&global_event_storage, jni_env, thread, object, ! object_klass, size); ! } ! ! JNIEXPORT ! void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) { ! event_storage_set_compaction_required(&global_event_storage); } static int enable_notifications() { + if (check_error((*jvmti)->SetEventNotificationMode( + jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), + "Set event notifications")) { + return 1; + } + return check_error((*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), "Set event notifications"); }
*** 367,386 **** --- 521,545 ---- if (res != JNI_OK || jvmti == NULL) { printf(" Error: wrong result of a valid call to GetEnv!\n"); return JNI_ERR; } + pthread_mutex_init(&global_event_storage.mutex, 0); + event_storage_set_garbage_history(&global_event_storage, 200); + jvmtiEventCallbacks callbacks; memset(&callbacks, 0, sizeof(callbacks)); callbacks.SampledObjectAlloc = &SampledObjectAlloc; + callbacks.GarbageCollectionFinish = &GarbageCollectionFinish; jvmtiCapabilities caps; memset(&caps, 0, sizeof(caps)); // Get line numbers, sample heap, sample events, and filename for the test. caps.can_get_line_numbers = 1; caps.can_sample_heap = 1; caps.can_get_source_file_name = 1; + caps.can_generate_garbage_collection_events = 1; if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){ return JNI_ERR; } if (enable_notifications()) {
*** 395,436 **** return JNI_OK; } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) { ! (*jvmti)->SetTlabHeapSampling(jvmti, value); } JNIEXPORT jboolean JNICALL Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { return event_storage_get_count(&global_event_storage) == 0; } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) { enable_notifications(); } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { check_error((*jvmti)->SetEventNotificationMode( jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), "Set event notifications"); - } ! JNIEXPORT void JNICALL ! Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { } JNIEXPORT jboolean JNICALL Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { jsize size = (*env)->GetArrayLength(env, frames); ExpectedContentFrame native_frames[size]; fill_native_frames(env, frames, native_frames, size); return event_storage_contains(env, &global_event_storage, native_frames, size); } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { return event_storage_reset(&global_event_storage); } --- 554,619 ---- return JNI_OK; } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) { ! (*jvmti)->SetHeapSamplingRate(jvmti, value); ! } ! ! JNIEXPORT void JNICALL ! Java_MyPackage_HeapMonitor_setGarbageHistory(JNIEnv* env, jclass cls, jint value) { ! event_storage_set_garbage_history(&global_event_storage, value); } JNIEXPORT jboolean JNICALL Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { return event_storage_get_count(&global_event_storage) == 0; } + JNIEXPORT jint JNICALL + Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) { + return event_storage_get_count(&global_event_storage); + } + JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) { enable_notifications(); } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { check_error((*jvmti)->SetEventNotificationMode( jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), "Set event notifications"); ! check_error((*jvmti)->SetEventNotificationMode( ! jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), ! "Garbage Collection Finish"); } JNIEXPORT jboolean JNICALL Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { jsize size = (*env)->GetArrayLength(env, frames); ExpectedContentFrame native_frames[size]; fill_native_frames(env, frames, native_frames, size); return event_storage_contains(env, &global_event_storage, native_frames, size); } + JNIEXPORT jboolean JNICALL + Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) { + jsize size = (*env)->GetArrayLength(env, frames); + ExpectedContentFrame native_frames[size]; + fill_native_frames(env, frames, native_frames, size); + return event_storage_garbage_contains(env, &global_event_storage, native_frames, size); + } + + JNIEXPORT void JNICALL + Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) { + check_error((*jvmti)->ForceGarbageCollection(jvmti), + "Forced Garbage Collection"); + } + JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { return event_storage_reset(&global_event_storage); }
*** 443,457 **** if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), "Add capabilities\n")){ return FALSE; } ! if (check_capability_error((*jvmti)->SetTlabHeapSampling(jvmti, 1<<19), ! "Set Tlab Heap Sampling")) { return FALSE; } return TRUE; } #ifdef __cplusplus } #endif --- 626,720 ---- if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), "Add capabilities\n")){ return FALSE; } ! if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19), ! "Set Heap Sampling Rate")) { return FALSE; } return TRUE; } + JNIEXPORT jdouble JNICALL + Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { + return event_storage_get_average_rate(&global_event_storage); + } + + typedef struct sThreadsFound { + jthread* threads; + int num_threads; + } ThreadsFound; + + static void find_threads_in_array(ThreadsFound* thread_data, + ObjectTrace** array, + int array_size) { + int i; + jthread* threads = thread_data->threads; + int num_threads = thread_data->num_threads; + + for (i = 0; i < array_size; i++) { + ObjectTrace* object = array[i]; + + if (object == NULL) { + continue; + } + + // Check it is the right frame: only accept helper top framed traces. + if (object->frame_count == 0) { + continue; + } + + jvmtiFrameInfo* frames = object->frames; + jthread thread = object->thread; + + jmethodID methodid = frames[0].method; + char *name = NULL, *signature = NULL, *file_name = NULL; + (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); + + if (strcmp(name, "helper")) { + continue; + } + + // Really not efficient look-up but it's for a test... + int found = 0; + int j; + for (j = 0; j < num_threads; j++) { + if (thread == threads[j]) { + found = 1; + break; + } + } + + if (!found) { + threads[num_threads] = thread; + num_threads++; + } + } + thread_data->num_threads = num_threads; + } + + JNIEXPORT jboolean JNICALL + Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, + jint num_threads) { + pthread_mutex_lock(&global_event_storage.mutex); + jint trace_counter; + + ThreadsFound thread_data; + thread_data.num_threads = 0; + thread_data.threads = malloc(sizeof(jthread) * num_threads); + memset(thread_data.threads, 0, sizeof(jthread) * num_threads); + + find_threads_in_array(&thread_data, global_event_storage.live_objects, + global_event_storage.live_object_count); + find_threads_in_array(&thread_data, + global_event_storage.garbage_collected_objects, + global_event_storage.garbage_history_size); + + free(thread_data.threads); + pthread_mutex_unlock(&global_event_storage.mutex); + return thread_data.num_threads == num_threads; + } + #ifdef __cplusplus } #endif
< prev index next >