< 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 >