43 #endif
44
45 #endif
46
47 #define TRUE 1
48 #define FALSE 0
49 #define PRINT_OUT 1
50 #define MAX_TRACES 400
51
52 static jvmtiEnv *jvmti = NULL;
53
54 typedef struct _ObjectTrace{
55 jweak object;
56 size_t size;
57 jvmtiFrameInfo* frames;
58 size_t frame_count;
59 jthread thread;
60 } ObjectTrace;
61
62 typedef struct _EventStorage {
63 int compaction_required;
64 int live_object_size;
65 int live_object_count;
66 ObjectTrace** live_objects;
67
68 int garbage_history_size;
69 int garbage_history_index;
70 ObjectTrace** garbage_collected_objects;
71
72 pthread_mutex_t mutex;
73 } EventStorage;
74
75 typedef struct _ExpectedContentFrame {
76 const char *name;
77 const char *signature;
78 const char *file_name;
79 int line_number;
80 } ExpectedContentFrame;
81
82 // Given a method and a location, this method gets the line number.
83 static
84 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
85 jlocation location) {
86 // Read the line number table.
87 jvmtiLineNumberEntry *table_ptr = 0;
88 jint line_number_table_entries;
89 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
90 &line_number_table_entries,
91 &table_ptr);
92
217 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
218 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
219
220 string_id = (*env)->GetFieldID(env, frame_class, "signature",
221 "Ljava/lang/String;");
222 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
223 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
224
225 native_frames[i].name = method;
226 native_frames[i].file_name = file_name;
227 native_frames[i].signature = signature;
228 native_frames[i].line_number = line_number;
229 }
230 }
231
232 // Internal storage system implementation.
233
234 static EventStorage global_event_storage;
235
236 static void event_storage_set_compaction_required(EventStorage* storage) {
237 pthread_mutex_lock(&storage->mutex);
238 storage->compaction_required = 1;
239 pthread_mutex_unlock(&storage->mutex);
240 }
241
242 static int event_storage_get_compaction_required(EventStorage* storage) {
243 pthread_mutex_lock(&storage->mutex);
244 int result = storage->compaction_required;
245 pthread_mutex_unlock(&storage->mutex);
246 return result;
247 }
248
249 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
250 pthread_mutex_lock(&storage->mutex);
251 global_event_storage.garbage_history_size = value;
252 free(global_event_storage.garbage_collected_objects);
253 size_t size =
254 sizeof(*global_event_storage.garbage_collected_objects) * value;
255 global_event_storage.garbage_collected_objects = malloc(size);
256 memset(global_event_storage.garbage_collected_objects, 0, size);
257 pthread_mutex_unlock(&storage->mutex);
258 }
259
260 // No mutex here, it is handled by the caller.
261 static void event_storage_add_garbage_collected_object(EventStorage* storage,
262 ObjectTrace* object) {
263 int idx = storage->garbage_history_index;
264 free(storage->garbage_collected_objects[idx]);
265 storage->garbage_collected_objects[idx] = object;
266 storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
267 }
268
269 static int event_storage_get_count(EventStorage* storage) {
270 pthread_mutex_lock(&storage->mutex);
271 int result = storage->live_object_count;
272 pthread_mutex_unlock(&storage->mutex);
273 return result;
274 }
275
276 static double event_storage_get_average_rate(EventStorage* storage) {
277 double accumulation = 0;
278
279 pthread_mutex_lock(&storage->mutex);
280 int max_size = storage->live_object_count;
281
282 for (int i = 0; i < max_size; i++) {
283 accumulation += storage->live_objects[i]->size;
284 }
285 pthread_mutex_unlock(&storage->mutex);
286 return accumulation / max_size;
287 }
288
289 static jboolean event_storage_contains(JNIEnv* env,
290 EventStorage* storage,
291 ExpectedContentFrame* frames,
292 size_t size) {
293 pthread_mutex_lock(&storage->mutex);
294 fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
295 int i;
296 for (i = 0; i < storage->live_object_count; i++) {
297 ObjectTrace* trace = storage->live_objects[i];
298
299 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
300 pthread_mutex_unlock(&storage->mutex);
301 return TRUE;
302 }
303 }
304 pthread_mutex_unlock(&storage->mutex);
305 return FALSE;
306 }
307
308 static jboolean event_storage_garbage_contains(JNIEnv* env,
309 EventStorage* storage,
310 ExpectedContentFrame* frames,
311 size_t size) {
312 pthread_mutex_lock(&storage->mutex);
313 fprintf(stderr, "Checking garbage storage count %d\n",
314 storage->garbage_history_size);
315 int i;
316 for (i = 0; i < storage->garbage_history_size; i++) {
317 ObjectTrace* trace = storage->garbage_collected_objects[i];
318
319 if (trace == NULL) {
320 continue;
321 }
322
323 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
324 pthread_mutex_unlock(&storage->mutex);
325 return TRUE;
326 }
327 }
328 pthread_mutex_unlock(&storage->mutex);
329 return FALSE;
330 }
331
332 // No mutex here, handled by the caller.
333 static void event_storage_augment_storage(EventStorage* storage) {
334 int new_max = (storage->live_object_size * 2) + 1;
335 ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
336
337 int current_count = storage->live_object_count;
338 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
339 free(storage->live_objects);
340 storage->live_objects = new_objects;
341
342 storage->live_object_size = new_max;
343 }
344
345 static void event_storage_add(EventStorage* storage,
346 JNIEnv* jni,
347 jthread thread,
348 jobject object,
349 jclass klass,
350 jlong size) {
351 jvmtiFrameInfo frames[64];
352 jint count;
353 jvmtiError err;
354
355 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
356 if (err == JVMTI_ERROR_NONE && count >= 1) {
357 pthread_mutex_lock(&storage->mutex);
358
359 if (storage->live_object_count >= storage->live_object_size) {
360 event_storage_augment_storage(storage);
361 }
362 assert(storage->live_object_count < storage->live_object_size);
363
364 jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames));
365 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
366
367 ObjectTrace* live_object = malloc(sizeof(*live_object));
368 live_object->frames = allocated_frames;
369 live_object->frame_count = count;
370 live_object->size = size;
371 live_object->thread = thread;
372 live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
373 storage->live_objects[storage->live_object_count] = live_object;
374 storage->live_object_count++;
375
376 pthread_mutex_unlock(&storage->mutex);
377 }
378 }
379
380 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
381 pthread_mutex_lock(&storage->mutex);
382 storage->compaction_required = 0;
383
384 int max = storage->live_object_count;
385 int i, dest;
386 ObjectTrace** live_objects = storage->live_objects;
387
388 for (i = 0, dest = 0; i < max; i++) {
389 ObjectTrace* live_object = live_objects[i];
390 jweak object = live_object->object;
391
392 if (!(*jni)->IsSameObject(jni, object, NULL)) {
393 if (dest != i) {
394 live_objects[dest] = live_object;
395 dest++;
396 }
397 } else {
398 event_storage_add_garbage_collected_object(storage, live_object);
399 }
400 }
401
402 storage->live_object_count = dest;
403 pthread_mutex_unlock(&storage->mutex);
404 }
405
406 static void event_storage_free_objects(ObjectTrace** array, int max) {
407 int i;
408 for (i = 0; i < max; i++) {
409 free(array[i]), array[i] = NULL;
410 }
411 }
412
413 static void event_storage_reset(EventStorage* storage) {
414 pthread_mutex_lock(&storage->mutex);
415
416 // Reset everything except the mutex and the garbage collection.
417 event_storage_free_objects(storage->live_objects,
418 storage->live_object_count);
419 storage->live_object_size = 0;
420 storage->live_object_count = 0;
421 free(storage->live_objects), storage->live_objects = NULL;
422
423 event_storage_free_objects(storage->garbage_collected_objects,
424 storage->garbage_history_size);
425
426 storage->compaction_required = 0;
427 storage->garbage_history_index = 0;
428
429 pthread_mutex_unlock(&storage->mutex);
430 }
431
432 // Start of the JVMTI agent code.
433
434 static const char *EXC_CNAME = "java/lang/Exception";
435
436 static int check_error(jvmtiError err, const char *s) {
437 if (err != JVMTI_ERROR_NONE) {
438 printf(" ## %s error: %d\n", s, err);
439 return 1;
440 }
441 return 0;
442 }
443
444 static int check_capability_error(jvmtiError err, const char *s) {
445 if (err != JVMTI_ERROR_NONE) {
446 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
447 return 0;
448 }
449 printf(" ## %s error: %d\n", s, err);
506 "Set event notifications")) {
507 return 1;
508 }
509
510 return check_error((*jvmti)->SetEventNotificationMode(
511 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
512 "Set event notifications");
513 }
514
515 static
516 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
517 jint res;
518
519 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
520 JVMTI_VERSION_9);
521 if (res != JNI_OK || jvmti == NULL) {
522 printf(" Error: wrong result of a valid call to GetEnv!\n");
523 return JNI_ERR;
524 }
525
526 pthread_mutex_init(&global_event_storage.mutex, 0);
527 event_storage_set_garbage_history(&global_event_storage, 200);
528
529 jvmtiEventCallbacks callbacks;
530 memset(&callbacks, 0, sizeof(callbacks));
531 callbacks.SampledObjectAlloc = &SampledObjectAlloc;
532 callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
533
534 jvmtiCapabilities caps;
535 memset(&caps, 0, sizeof(caps));
536 // Get line numbers, sample heap, sample events, and filename for the test.
537 caps.can_get_line_numbers = 1;
538 caps.can_sample_heap = 1;
539 caps.can_get_source_file_name = 1;
540 caps.can_generate_garbage_collection_events = 1;
541 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){
542 return JNI_ERR;
543 }
544
545 if (enable_notifications()) {
546 return JNI_ERR;
547 }
548
549 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
550 sizeof(jvmtiEventCallbacks)),
551 " Set Event Callbacks")) {
552 return JNI_ERR;
553 }
554 return JNI_OK;
555 }
556
557 JNIEXPORT void JNICALL
558 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
559 (*jvmti)->SetHeapSamplingRate(jvmti, value);
560 }
561
562 JNIEXPORT void JNICALL
563 Java_MyPackage_HeapMonitor_setGarbageHistory(JNIEnv* env, jclass cls, jint value) {
564 event_storage_set_garbage_history(&global_event_storage, value);
565 }
566
567 JNIEXPORT jboolean JNICALL
568 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
605 fill_native_frames(env, frames, native_frames, size);
606 return event_storage_garbage_contains(env, &global_event_storage, native_frames, size);
607 }
608
609 JNIEXPORT void JNICALL
610 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
611 check_error((*jvmti)->ForceGarbageCollection(jvmti),
612 "Forced Garbage Collection");
613 }
614
615 JNIEXPORT void JNICALL
616 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
617 return event_storage_reset(&global_event_storage);
618 }
619
620 JNIEXPORT jboolean JNICALL
621 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
622 jclass cls) {
623 jvmtiCapabilities caps;
624 memset(&caps, 0, sizeof(caps));
625 caps.can_sample_heap= 1;
626 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
627 "Add capabilities\n")){
628 return FALSE;
629 }
630
631 if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19),
632 "Set Heap Sampling Rate")) {
633 return FALSE;
634 }
635 return TRUE;
636 }
637
638 JNIEXPORT jdouble JNICALL
639 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
640 return event_storage_get_average_rate(&global_event_storage);
641 }
642
643 typedef struct sThreadsFound {
644 jthread* threads;
645 int num_threads;
679 int found = 0;
680 int j;
681 for (j = 0; j < num_threads; j++) {
682 if (thread == threads[j]) {
683 found = 1;
684 break;
685 }
686 }
687
688 if (!found) {
689 threads[num_threads] = thread;
690 num_threads++;
691 }
692 }
693 thread_data->num_threads = num_threads;
694 }
695
696 JNIEXPORT jboolean JNICALL
697 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
698 jint num_threads) {
699 pthread_mutex_lock(&global_event_storage.mutex);
700 jint trace_counter;
701
702 ThreadsFound thread_data;
703 thread_data.num_threads = 0;
704 thread_data.threads = malloc(sizeof(jthread) * num_threads);
705 memset(thread_data.threads, 0, sizeof(jthread) * num_threads);
706
707 find_threads_in_array(&thread_data, global_event_storage.live_objects,
708 global_event_storage.live_object_count);
709 find_threads_in_array(&thread_data,
710 global_event_storage.garbage_collected_objects,
711 global_event_storage.garbage_history_size);
712
713 free(thread_data.threads);
714 pthread_mutex_unlock(&global_event_storage.mutex);
715 return thread_data.num_threads == num_threads;
716 }
717
718 #ifdef __cplusplus
719 }
720 #endif
|
43 #endif
44
45 #endif
46
47 #define TRUE 1
48 #define FALSE 0
49 #define PRINT_OUT 1
50 #define MAX_TRACES 400
51
52 static jvmtiEnv *jvmti = NULL;
53
54 typedef struct _ObjectTrace{
55 jweak object;
56 size_t size;
57 jvmtiFrameInfo* frames;
58 size_t frame_count;
59 jthread thread;
60 } ObjectTrace;
61
62 typedef struct _EventStorage {
63 int live_object_size;
64 int live_object_count;
65 ObjectTrace** live_objects;
66
67 int garbage_history_size;
68 int garbage_history_index;
69 ObjectTrace** garbage_collected_objects;
70
71 // Two separate mutexes to separate storage data race and the compaction field
72 // data race.
73 pthread_mutex_t storage_mutex;
74
75 int compaction_required;
76 pthread_mutex_t compaction_mutex;
77 } EventStorage;
78
79 typedef struct _ExpectedContentFrame {
80 const char *name;
81 const char *signature;
82 const char *file_name;
83 int line_number;
84 } ExpectedContentFrame;
85
86 // Given a method and a location, this method gets the line number.
87 static
88 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
89 jlocation location) {
90 // Read the line number table.
91 jvmtiLineNumberEntry *table_ptr = 0;
92 jint line_number_table_entries;
93 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
94 &line_number_table_entries,
95 &table_ptr);
96
221 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
222 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
223
224 string_id = (*env)->GetFieldID(env, frame_class, "signature",
225 "Ljava/lang/String;");
226 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
227 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
228
229 native_frames[i].name = method;
230 native_frames[i].file_name = file_name;
231 native_frames[i].signature = signature;
232 native_frames[i].line_number = line_number;
233 }
234 }
235
236 // Internal storage system implementation.
237
238 static EventStorage global_event_storage;
239
240 static void event_storage_set_compaction_required(EventStorage* storage) {
241 pthread_mutex_lock(&storage->compaction_mutex);
242 storage->compaction_required = 1;
243 pthread_mutex_unlock(&storage->compaction_mutex);
244 }
245
246 static int event_storage_get_compaction_required(EventStorage* storage) {
247 pthread_mutex_lock(&storage->compaction_mutex);
248 int result = storage->compaction_required;
249 pthread_mutex_unlock(&storage->compaction_mutex);
250 return result;
251 }
252
253 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
254 pthread_mutex_lock(&storage->storage_mutex);
255 global_event_storage.garbage_history_size = value;
256 free(global_event_storage.garbage_collected_objects);
257 size_t size =
258 sizeof(*global_event_storage.garbage_collected_objects) * value;
259 global_event_storage.garbage_collected_objects = malloc(size);
260 memset(global_event_storage.garbage_collected_objects, 0, size);
261 pthread_mutex_unlock(&storage->storage_mutex);
262 }
263
264 // No mutex here, it is handled by the caller.
265 static void event_storage_add_garbage_collected_object(EventStorage* storage,
266 ObjectTrace* object) {
267 int idx = storage->garbage_history_index;
268 free(storage->garbage_collected_objects[idx]);
269 storage->garbage_collected_objects[idx] = object;
270 storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
271 }
272
273 static int event_storage_get_count(EventStorage* storage) {
274 pthread_mutex_lock(&storage->storage_mutex);
275 int result = storage->live_object_count;
276 pthread_mutex_unlock(&storage->storage_mutex);
277 return result;
278 }
279
280 static double event_storage_get_average_rate(EventStorage* storage) {
281 double accumulation = 0;
282
283 pthread_mutex_lock(&storage->storage_mutex);
284 int max_size = storage->live_object_count;
285
286 int i;
287 for (i = 0; i < max_size; i++) {
288 accumulation += storage->live_objects[i]->size;
289 }
290 pthread_mutex_unlock(&storage->storage_mutex);
291 return accumulation / max_size;
292 }
293
294 static jboolean event_storage_contains(JNIEnv* env,
295 EventStorage* storage,
296 ExpectedContentFrame* frames,
297 size_t size) {
298 pthread_mutex_lock(&storage->storage_mutex);
299 fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
300 int i;
301 for (i = 0; i < storage->live_object_count; i++) {
302 ObjectTrace* trace = storage->live_objects[i];
303
304 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
305 pthread_mutex_unlock(&storage->storage_mutex);
306 return TRUE;
307 }
308 }
309 pthread_mutex_unlock(&storage->storage_mutex);
310 return FALSE;
311 }
312
313 static jboolean event_storage_garbage_contains(JNIEnv* env,
314 EventStorage* storage,
315 ExpectedContentFrame* frames,
316 size_t size) {
317 pthread_mutex_lock(&storage->storage_mutex);
318 fprintf(stderr, "Checking garbage storage count %d\n",
319 storage->garbage_history_size);
320 int i;
321 for (i = 0; i < storage->garbage_history_size; i++) {
322 ObjectTrace* trace = storage->garbage_collected_objects[i];
323
324 if (trace == NULL) {
325 continue;
326 }
327
328 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
329 pthread_mutex_unlock(&storage->storage_mutex);
330 return TRUE;
331 }
332 }
333 pthread_mutex_unlock(&storage->storage_mutex);
334 return FALSE;
335 }
336
337 // No mutex here, handled by the caller.
338 static void event_storage_augment_storage(EventStorage* storage) {
339 int new_max = (storage->live_object_size * 2) + 1;
340 ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
341
342 int current_count = storage->live_object_count;
343 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
344 free(storage->live_objects);
345 storage->live_objects = new_objects;
346
347 storage->live_object_size = new_max;
348 }
349
350 static void event_storage_add(EventStorage* storage,
351 JNIEnv* jni,
352 jthread thread,
353 jobject object,
354 jclass klass,
355 jlong size) {
356 jvmtiFrameInfo frames[64];
357 jint count;
358 jvmtiError err;
359
360 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
361 if (err == JVMTI_ERROR_NONE && count >= 1) {
362 jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
363 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
364
365 ObjectTrace* live_object = (ObjectTrace*) malloc(sizeof(*live_object));
366 live_object->frames = allocated_frames;
367 live_object->frame_count = count;
368 live_object->size = size;
369 live_object->thread = thread;
370 live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
371
372 // Only now lock and get things done quickly.
373 pthread_mutex_lock(&storage->storage_mutex);
374
375 if (storage->live_object_count >= storage->live_object_size) {
376 event_storage_augment_storage(storage);
377 }
378 assert(storage->live_object_count < storage->live_object_size);
379
380 storage->live_objects[storage->live_object_count] = live_object;
381 storage->live_object_count++;
382
383 pthread_mutex_unlock(&storage->storage_mutex);
384 }
385 }
386
387 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
388 pthread_mutex_lock(&storage->compaction_mutex);
389 storage->compaction_required = 0;
390 pthread_mutex_unlock(&storage->compaction_mutex);
391
392 pthread_mutex_lock(&storage->storage_mutex);
393
394 int max = storage->live_object_count;
395 int i, dest;
396 ObjectTrace** live_objects = storage->live_objects;
397
398 for (i = 0, dest = 0; i < max; i++) {
399 ObjectTrace* live_object = live_objects[i];
400 jweak object = live_object->object;
401
402 if (!(*jni)->IsSameObject(jni, object, NULL)) {
403 if (dest != i) {
404 live_objects[dest] = live_object;
405 dest++;
406 }
407 } else {
408 event_storage_add_garbage_collected_object(storage, live_object);
409 }
410 }
411
412 storage->live_object_count = dest;
413 pthread_mutex_unlock(&storage->storage_mutex);
414 }
415
416 static void event_storage_free_objects(ObjectTrace** array, int max) {
417 int i;
418 for (i = 0; i < max; i++) {
419 free(array[i]), array[i] = NULL;
420 }
421 }
422
423 static void event_storage_reset(EventStorage* storage) {
424 pthread_mutex_lock(&storage->storage_mutex);
425
426 // Reset everything except the mutex and the garbage collection.
427 event_storage_free_objects(storage->live_objects,
428 storage->live_object_count);
429 storage->live_object_size = 0;
430 storage->live_object_count = 0;
431 free(storage->live_objects), storage->live_objects = NULL;
432
433 event_storage_free_objects(storage->garbage_collected_objects,
434 storage->garbage_history_size);
435
436 storage->compaction_required = 0;
437 storage->garbage_history_index = 0;
438
439 pthread_mutex_unlock(&storage->storage_mutex);
440 }
441
442 // Start of the JVMTI agent code.
443
444 static const char *EXC_CNAME = "java/lang/Exception";
445
446 static int check_error(jvmtiError err, const char *s) {
447 if (err != JVMTI_ERROR_NONE) {
448 printf(" ## %s error: %d\n", s, err);
449 return 1;
450 }
451 return 0;
452 }
453
454 static int check_capability_error(jvmtiError err, const char *s) {
455 if (err != JVMTI_ERROR_NONE) {
456 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
457 return 0;
458 }
459 printf(" ## %s error: %d\n", s, err);
516 "Set event notifications")) {
517 return 1;
518 }
519
520 return check_error((*jvmti)->SetEventNotificationMode(
521 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
522 "Set event notifications");
523 }
524
525 static
526 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
527 jint res;
528
529 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
530 JVMTI_VERSION_9);
531 if (res != JNI_OK || jvmti == NULL) {
532 printf(" Error: wrong result of a valid call to GetEnv!\n");
533 return JNI_ERR;
534 }
535
536 pthread_mutex_init(&global_event_storage.storage_mutex, 0);
537 pthread_mutex_init(&global_event_storage.compaction_mutex, 0);
538 event_storage_set_garbage_history(&global_event_storage, 200);
539
540 jvmtiEventCallbacks callbacks;
541 memset(&callbacks, 0, sizeof(callbacks));
542 callbacks.SampledObjectAlloc = &SampledObjectAlloc;
543 callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
544
545 jvmtiCapabilities caps;
546 memset(&caps, 0, sizeof(caps));
547 // Get line numbers, sample heap, sample events, and filename for the test.
548 caps.can_get_line_numbers = 1;
549 caps.can_generate_sampled_alloc_events = 1;
550 caps.can_get_source_file_name = 1;
551 caps.can_generate_garbage_collection_events = 1;
552 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){
553 return JNI_ERR;
554 }
555
556 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
557 sizeof(jvmtiEventCallbacks)),
558 " Set Event Callbacks")) {
559 return JNI_ERR;
560 }
561 return JNI_OK;
562 }
563
564 JNIEXPORT void JNICALL
565 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
566 (*jvmti)->SetHeapSamplingRate(jvmti, value);
567 }
568
569 JNIEXPORT void JNICALL
570 Java_MyPackage_HeapMonitor_setGarbageHistory(JNIEnv* env, jclass cls, jint value) {
571 event_storage_set_garbage_history(&global_event_storage, value);
572 }
573
574 JNIEXPORT jboolean JNICALL
575 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
612 fill_native_frames(env, frames, native_frames, size);
613 return event_storage_garbage_contains(env, &global_event_storage, native_frames, size);
614 }
615
616 JNIEXPORT void JNICALL
617 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
618 check_error((*jvmti)->ForceGarbageCollection(jvmti),
619 "Forced Garbage Collection");
620 }
621
622 JNIEXPORT void JNICALL
623 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
624 return event_storage_reset(&global_event_storage);
625 }
626
627 JNIEXPORT jboolean JNICALL
628 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
629 jclass cls) {
630 jvmtiCapabilities caps;
631 memset(&caps, 0, sizeof(caps));
632 caps.can_generate_sampled_alloc_events = 1;
633 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
634 "Add capabilities\n")){
635 return FALSE;
636 }
637
638 if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19),
639 "Set Heap Sampling Rate")) {
640 return FALSE;
641 }
642 return TRUE;
643 }
644
645 JNIEXPORT jdouble JNICALL
646 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
647 return event_storage_get_average_rate(&global_event_storage);
648 }
649
650 typedef struct sThreadsFound {
651 jthread* threads;
652 int num_threads;
686 int found = 0;
687 int j;
688 for (j = 0; j < num_threads; j++) {
689 if (thread == threads[j]) {
690 found = 1;
691 break;
692 }
693 }
694
695 if (!found) {
696 threads[num_threads] = thread;
697 num_threads++;
698 }
699 }
700 thread_data->num_threads = num_threads;
701 }
702
703 JNIEXPORT jboolean JNICALL
704 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
705 jint num_threads) {
706 pthread_mutex_lock(&global_event_storage.storage_mutex);
707 jint trace_counter;
708
709 ThreadsFound thread_data;
710 thread_data.num_threads = 0;
711 thread_data.threads = malloc(sizeof(jthread) * num_threads);
712 memset(thread_data.threads, 0, sizeof(jthread) * num_threads);
713
714 find_threads_in_array(&thread_data, global_event_storage.live_objects,
715 global_event_storage.live_object_count);
716 find_threads_in_array(&thread_data,
717 global_event_storage.garbage_collected_objects,
718 global_event_storage.garbage_history_size);
719
720 free(thread_data.threads);
721 pthread_mutex_unlock(&global_event_storage.storage_mutex);
722 return thread_data.num_threads == num_threads;
723 }
724
725 #ifdef __cplusplus
726 }
727 #endif
|