--- old/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitor.c 2018-03-08 15:53:36.959570266 -0800 +++ new/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitor.c 2018-03-08 15:53:36.703571131 -0800 @@ -21,6 +21,8 @@ * questions. */ +#include +#include #include #include #include @@ -49,6 +51,108 @@ static const char *EXC_CNAME = "java/lang/Exception"; static jvmtiEnv *jvmti = NULL; +static pthread_mutex_t event_data_lock; + +// Event storage code. + +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; + const char *file_name; + int line_number; +} ExpectedContentFrame; + +static jboolean check_live_object_trace_content( + JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected, + size_t expected_count, int print_out_comparisons); + +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) { + int i; + fprintf(stderr, "Event storage contains: %d\n", storage->live_object_count); + for (i = 0; i < storage->live_object_count; i++) { + LiveObjectTrace* trace = storage->live_objects[i]; + + if (check_live_object_trace_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) { + pthread_mutex_lock(&event_data_lock); + 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++; + } + pthread_mutex_unlock(&event_data_lock); +} + +static void event_storage_reset(EventStorage* storage) { + pthread_mutex_lock(&event_data_lock); + 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)); + pthread_mutex_unlock(&event_data_lock); +} + +// General JVMTI agent code. static int check_error(jvmtiError err, const char *s) { if (err != JVMTI_ERROR_NONE) { @@ -97,6 +201,17 @@ return JNI_VERSION_1_8; } +JNIEXPORT +void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env, + JNIEnv* jni_env, + jthread thread, + jobject object, + jclass object_klass, + jlong size) { + // Not optimal to do this at the callback but makes testing easier for now. + event_storage_add(&global_event_storage, thread, object, object_klass, size); +} + static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res; @@ -110,22 +225,31 @@ jvmtiEventCallbacks callbacks; memset(&callbacks, 0, sizeof(callbacks)); + callbacks.SampledObjectAlloc = &SampledObjectAlloc; jvmtiCapabilities caps; memset(&caps, 0, sizeof(caps)); // Get line numbers, sample heap, and filename for the test. caps.can_get_line_numbers = 1; caps.can_sample_heap = 1; + caps.can_generate_sampled_object_alloc_events = 1; caps.can_get_source_file_name = 1; if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities\n")){ return JNI_ERR; } + if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(jvmtiEventCallbacks)), " Set Event Callbacks")) { return JNI_ERR; } + + + if (pthread_mutex_init(&event_data_lock, NULL) != 0) { + return JNI_ERR; + } + return JNI_OK; } @@ -170,28 +294,12 @@ } } -typedef struct _ExpectedContentFrame { - const char *name; - const char *signature; - const char *file_name; - int line_number; -} ExpectedContentFrame; - -static jboolean check_sample_content(JNIEnv *env, - jvmtiAllocTraceInfo* trace, - ExpectedContentFrame *expected, - int expected_count, - int print_out_comparisons) { +static jboolean check_frame_content(JNIEnv *env, + jvmtiFrameInfo* frames, + ExpectedContentFrame *expected, + int expected_count, + int print_out_comparisons) { int i; - - jvmtiStackInfo* stack_info = trace->stack_info; - - if (expected_count > stack_info->frame_count) { - return FALSE; - } - - jvmtiFrameInfo* frames = stack_info->frame_buffer; - for (i = 0; i < expected_count; i++) { // Get basic information out of the trace. int bci = frames[i].location; @@ -255,6 +363,33 @@ return TRUE; } +static jboolean check_live_object_trace_content( + JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected, + size_t expected_count, int print_out_comparisons) { + + if (expected_count > trace->frame_count) { + return FALSE; + } + + return check_frame_content(env, trace->frames, + expected, expected_count, print_out_comparisons); +} + +static jboolean check_sample_content(JNIEnv *env, + jvmtiAllocTraceInfo* trace, + ExpectedContentFrame *expected, + int expected_count, + int print_out_comparisons) { + jvmtiStackInfo* stack_info = trace->stack_info; + + if (expected_count > stack_info->frame_count) { + return FALSE; + } + + return check_frame_content(env, stack_info->frame_buffer, + expected, expected_count, print_out_comparisons); +} + static jboolean compare_samples(JNIEnv* env, jvmtiAllocTraceInfo* traces, int trace_count, ExpectedContentFrame* expected_content, @@ -473,11 +608,24 @@ int max_traces) { check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces), "Start Heap Sampling"); + check_error( + (*jvmti)->SetEventNotificationMode(jvmti, + JVMTI_ENABLE, + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, + NULL), + "Start sampling events"); } JNIEXPORT void JNICALL Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) { check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling"); + + check_error( + (*jvmti)->SetEventNotificationMode(jvmti, + JVMTI_DISABLE, + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, + NULL), + "Start sampling events"); } JNIEXPORT jboolean JNICALL @@ -762,6 +910,8 @@ int other_trace_count, int print_out_comparisons) { if (trace_count != other_trace_count) { + fprintf(stderr, "Trace count not the same!\n %d %d", + trace_count, other_trace_count); return FALSE; } @@ -774,20 +924,24 @@ jvmtiStackInfo* other_stack_info = trace->stack_info; if (stack_info->frame_count != other_stack_info->frame_count) { + fprintf(stderr, "Frame count not the same!\n"); return FALSE; } if (trace->size != other_trace->size) { + fprintf(stderr, "Size not the same!\n"); return FALSE; } if (trace->thread_id != other_trace->thread_id) { + fprintf(stderr, "Thread id not the same!\n"); return FALSE; } jvmtiFrameInfo* frames = stack_info->frame_buffer; jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer; if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) { + fprintf(stderr, "memcmp not the same!\n"); return FALSE; } } @@ -831,6 +985,16 @@ return result; } +JNIEXPORT jboolean JNICALL +Java_MyPackage_HeapMonitorCachedTest_forceGC(JNIEnv *env, jclass cls) { + jvmtiError error = (*jvmti)->ForceGarbageCollection(jvmti); + + if (error != JVMTI_ERROR_NONE) { + return FALSE; + } + return TRUE; +} + static long hash(long hash_code, long value) { return hash_code * 31 + value; } @@ -891,6 +1055,43 @@ return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); } +JNIEXPORT jboolean JNICALL +Java_MyPackage_HeapMonitorEventNoCapabilityTest_eventSamplingFail(JNIEnv *env, + jclass cls) { + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_sampled_object_alloc_events = 1; + if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), + "Add capabilities\n")){ + return FALSE; + } + + if (check_capability_error( + (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), + "Set Tlab Heap Sampling")) { + return FALSE; + } + return TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { + return event_storage_get_count(&global_event_storage) == 0; +} + +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); +} + #ifdef __cplusplus } #endif