1 /* 2 * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include <assert.h> 25 #include <pthread.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include "jvmti.h" 30 31 #ifdef __cplusplus 32 extern "C" { 33 #endif 34 35 #ifndef JNI_ENV_ARG 36 37 #ifdef __cplusplus 38 #define JNI_ENV_ARG(x, y) y 39 #define JNI_ENV_PTR(x) x 40 #else 41 #define JNI_ENV_ARG(x,y) x, y 42 #define JNI_ENV_PTR(x) (*x) 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 static jvmtiEnv *second_jvmti = NULL; 54 55 typedef struct _ObjectTrace{ 56 jweak object; 57 size_t size; 58 jvmtiFrameInfo* frames; 59 size_t frame_count; 60 jthread thread; 61 } ObjectTrace; 62 63 typedef struct _EventStorage { 64 int live_object_additions; 65 int live_object_size; 66 int live_object_count; 67 ObjectTrace** live_objects; 68 69 int garbage_history_size; 70 int garbage_history_index; 71 ObjectTrace** garbage_collected_objects; 72 73 // Two separate mutexes to separate storage data race and the compaction field 74 // data race. 75 pthread_mutex_t storage_mutex; 76 77 int compaction_required; 78 pthread_mutex_t compaction_mutex; 79 } EventStorage; 80 81 typedef struct _ExpectedContentFrame { 82 const char *name; 83 const char *signature; 84 const char *file_name; 85 int line_number; 86 } ExpectedContentFrame; 87 88 // Given a method and a location, this method gets the line number. 89 static 90 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, 91 jlocation location) { 92 // Read the line number table. 93 jvmtiLineNumberEntry *table_ptr = 0; 94 jint line_number_table_entries; 95 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 96 &line_number_table_entries, 97 &table_ptr); 98 99 if (JVMTI_ERROR_NONE != jvmti_error) { 100 return -1; 101 } 102 if (line_number_table_entries <= 0) { 103 return -1; 104 } 105 if (line_number_table_entries == 1) { 106 return table_ptr[0].line_number; 107 } 108 109 // Go through all the line numbers... 110 jint last_location = table_ptr[0].start_location; 111 int l; 112 for (l = 1; l < line_number_table_entries; l++) { 113 // ... and if you see one that is in the right place for your 114 // location, you've found the line number! 115 if ((location < table_ptr[l].start_location) && 116 (location >= last_location)) { 117 return table_ptr[l - 1].line_number; 118 } 119 last_location = table_ptr[l].start_location; 120 } 121 122 if (location >= last_location) { 123 return table_ptr[line_number_table_entries - 1].line_number; 124 } else { 125 return -1; 126 } 127 } 128 129 static jboolean check_sample_content(JNIEnv *env, 130 ObjectTrace* trace, 131 ExpectedContentFrame *expected, 132 size_t expected_count, 133 int print_out_comparisons) { 134 if (expected_count > trace->frame_count) { 135 return FALSE; 136 } 137 138 jvmtiFrameInfo* frames = trace->frames; 139 140 size_t i; 141 for (i = 0; i < expected_count; i++) { 142 // Get basic information out of the trace. 143 int bci = frames[i].location; 144 jmethodID methodid = frames[i].method; 145 char *name = NULL, *signature = NULL, *file_name = NULL; 146 147 if (bci < 0 && expected[i].line_number != -1) { 148 return FALSE; 149 } 150 151 // Transform into usable information. 152 int line_number = get_line_number(jvmti, methodid, bci); 153 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 154 155 jclass declaring_class; 156 if (JVMTI_ERROR_NONE != 157 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 158 return FALSE; 159 } 160 161 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 162 &file_name); 163 if (err != JVMTI_ERROR_NONE) { 164 return FALSE; 165 } 166 167 // Compare now, none should be NULL. 168 if (name == NULL) { 169 return FALSE; 170 } 171 172 if (file_name == NULL) { 173 return FALSE; 174 } 175 176 if (signature == NULL) { 177 return FALSE; 178 } 179 180 if (print_out_comparisons) { 181 fprintf(stderr, "\tComparing:\n"); 182 fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name); 183 fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature); 184 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name); 185 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number); 186 fprintf(stderr, "\t\tResult is %d\n", 187 (strcmp(name, expected[i].name) || 188 strcmp(signature, expected[i].signature) || 189 strcmp(file_name, expected[i].file_name) || 190 line_number != expected[i].line_number)); 191 } 192 193 if (strcmp(name, expected[i].name) || 194 strcmp(signature, expected[i].signature) || 195 strcmp(file_name, expected[i].file_name) || 196 line_number != expected[i].line_number) { 197 return FALSE; 198 } 199 } 200 201 return TRUE; 202 } 203 204 // Static native API for various tests. 205 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 206 ExpectedContentFrame* native_frames, size_t size) { 207 size_t i; 208 for (i = 0; i < size; i++) { 209 jobject obj = (*env)->GetObjectArrayElement(env, frames, i); 210 jclass frame_class = (*env)->GetObjectClass(env, obj); 211 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, 212 "lineNumber", "I"); 213 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 214 215 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", 216 "Ljava/lang/String;"); 217 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, 218 string_id); 219 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 220 221 string_id = (*env)->GetFieldID(env, frame_class, "fileName", 222 "Ljava/lang/String;"); 223 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 224 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0); 225 226 string_id = (*env)->GetFieldID(env, frame_class, "signature", 227 "Ljava/lang/String;"); 228 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 229 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0); 230 231 native_frames[i].name = method; 232 native_frames[i].file_name = file_name; 233 native_frames[i].signature = signature; 234 native_frames[i].line_number = line_number; 235 } 236 } 237 238 // Internal storage system implementation. 239 240 static EventStorage global_event_storage; 241 static EventStorage second_global_event_storage; 242 243 static void event_storage_set_compaction_required(EventStorage* storage) { 244 pthread_mutex_lock(&storage->compaction_mutex); 245 storage->compaction_required = 1; 246 pthread_mutex_unlock(&storage->compaction_mutex); 247 } 248 249 static int event_storage_get_compaction_required(EventStorage* storage) { 250 pthread_mutex_lock(&storage->compaction_mutex); 251 int result = storage->compaction_required; 252 pthread_mutex_unlock(&storage->compaction_mutex); 253 return result; 254 } 255 256 static void event_storage_set_garbage_history(EventStorage* storage, int value) { 257 pthread_mutex_lock(&storage->storage_mutex); 258 global_event_storage.garbage_history_size = value; 259 free(global_event_storage.garbage_collected_objects); 260 size_t size = 261 sizeof(*global_event_storage.garbage_collected_objects) * value; 262 global_event_storage.garbage_collected_objects = malloc(size); 263 memset(global_event_storage.garbage_collected_objects, 0, size); 264 pthread_mutex_unlock(&storage->storage_mutex); 265 } 266 267 // No mutex here, it is handled by the caller. 268 static void event_storage_add_garbage_collected_object(EventStorage* storage, 269 ObjectTrace* object) { 270 int idx = storage->garbage_history_index; 271 free(storage->garbage_collected_objects[idx]); 272 storage->garbage_collected_objects[idx] = object; 273 storage->garbage_history_index = (idx + 1) % storage->garbage_history_size; 274 } 275 276 static int event_storage_get_count(EventStorage* storage) { 277 pthread_mutex_lock(&storage->storage_mutex); 278 int result = storage->live_object_count; 279 pthread_mutex_unlock(&storage->storage_mutex); 280 return result; 281 } 282 283 static double event_storage_get_average_rate(EventStorage* storage) { 284 double accumulation = 0; 285 286 pthread_mutex_lock(&storage->storage_mutex); 287 int max_size = storage->live_object_count; 288 289 int i; 290 for (i = 0; i < max_size; i++) { 291 accumulation += storage->live_objects[i]->size; 292 } 293 pthread_mutex_unlock(&storage->storage_mutex); 294 return accumulation / max_size; 295 } 296 297 static jboolean event_storage_contains(JNIEnv* env, 298 EventStorage* storage, 299 ExpectedContentFrame* frames, 300 size_t size) { 301 pthread_mutex_lock(&storage->storage_mutex); 302 fprintf(stderr, "Checking storage count %d\n", storage->live_object_count); 303 int i; 304 for (i = 0; i < storage->live_object_count; i++) { 305 ObjectTrace* trace = storage->live_objects[i]; 306 307 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { 308 pthread_mutex_unlock(&storage->storage_mutex); 309 return TRUE; 310 } 311 } 312 pthread_mutex_unlock(&storage->storage_mutex); 313 return FALSE; 314 } 315 316 static jboolean event_storage_garbage_contains(JNIEnv* env, 317 EventStorage* storage, 318 ExpectedContentFrame* frames, 319 size_t size) { 320 pthread_mutex_lock(&storage->storage_mutex); 321 fprintf(stderr, "Checking garbage storage count %d\n", 322 storage->garbage_history_size); 323 int i; 324 for (i = 0; i < storage->garbage_history_size; i++) { 325 ObjectTrace* trace = storage->garbage_collected_objects[i]; 326 327 if (trace == NULL) { 328 continue; 329 } 330 331 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { 332 pthread_mutex_unlock(&storage->storage_mutex); 333 return TRUE; 334 } 335 } 336 pthread_mutex_unlock(&storage->storage_mutex); 337 return FALSE; 338 } 339 340 // No mutex here, handled by the caller. 341 static void event_storage_augment_storage(EventStorage* storage) { 342 int new_max = (storage->live_object_size * 2) + 1; 343 ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); 344 345 int current_count = storage->live_object_count; 346 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); 347 free(storage->live_objects); 348 storage->live_objects = new_objects; 349 350 storage->live_object_size = new_max; 351 } 352 353 static void event_storage_add(EventStorage* storage, 354 JNIEnv* jni, 355 jthread thread, 356 jobject object, 357 jclass klass, 358 jlong size) { 359 jvmtiFrameInfo frames[64]; 360 jint count; 361 jvmtiError err; 362 363 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); 364 if (err == JVMTI_ERROR_NONE && count >= 1) { 365 jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames)); 366 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); 367 368 ObjectTrace* live_object = (ObjectTrace*) malloc(sizeof(*live_object)); 369 live_object->frames = allocated_frames; 370 live_object->frame_count = count; 371 live_object->size = size; 372 live_object->thread = thread; 373 live_object->object = (*jni)->NewWeakGlobalRef(jni, object); 374 375 // Only now lock and get things done quickly. 376 pthread_mutex_lock(&storage->storage_mutex); 377 378 storage->live_object_additions++; 379 380 if (storage->live_object_count >= storage->live_object_size) { 381 event_storage_augment_storage(storage); 382 } 383 assert(storage->live_object_count < storage->live_object_size); 384 385 storage->live_objects[storage->live_object_count] = live_object; 386 storage->live_object_count++; 387 388 pthread_mutex_unlock(&storage->storage_mutex); 389 } 390 } 391 392 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) { 393 pthread_mutex_lock(&storage->compaction_mutex); 394 storage->compaction_required = 0; 395 pthread_mutex_unlock(&storage->compaction_mutex); 396 397 pthread_mutex_lock(&storage->storage_mutex); 398 399 int max = storage->live_object_count; 400 int i, dest; 401 ObjectTrace** live_objects = storage->live_objects; 402 403 for (i = 0, dest = 0; i < max; i++) { 404 ObjectTrace* live_object = live_objects[i]; 405 jweak object = live_object->object; 406 407 if (!(*jni)->IsSameObject(jni, object, NULL)) { 408 if (dest != i) { 409 live_objects[dest] = live_object; 410 dest++; 411 } 412 } else { 413 event_storage_add_garbage_collected_object(storage, live_object); 414 } 415 } 416 417 storage->live_object_count = dest; 418 pthread_mutex_unlock(&storage->storage_mutex); 419 } 420 421 static void event_storage_free_objects(ObjectTrace** array, int max) { 422 int i; 423 for (i = 0; i < max; i++) { 424 free(array[i]), array[i] = NULL; 425 } 426 } 427 428 static void event_storage_reset(EventStorage* storage) { 429 pthread_mutex_lock(&storage->storage_mutex); 430 431 // Reset everything except the mutex and the garbage collection. 432 event_storage_free_objects(storage->live_objects, 433 storage->live_object_count); 434 storage->live_object_additions = 0; 435 storage->live_object_size = 0; 436 storage->live_object_count = 0; 437 free(storage->live_objects), storage->live_objects = NULL; 438 439 event_storage_free_objects(storage->garbage_collected_objects, 440 storage->garbage_history_size); 441 442 storage->compaction_required = 0; 443 storage->garbage_history_index = 0; 444 445 pthread_mutex_unlock(&storage->storage_mutex); 446 } 447 448 static int event_storage_number_additions(EventStorage* storage) { 449 pthread_mutex_lock(&storage->storage_mutex); 450 int result = storage->live_object_additions; 451 pthread_mutex_unlock(&storage->storage_mutex); 452 return result; 453 } 454 455 // Start of the JVMTI agent code. 456 457 static const char *EXC_CNAME = "java/lang/Exception"; 458 459 static int check_error(jvmtiError err, const char *s) { 460 if (err != JVMTI_ERROR_NONE) { 461 printf(" ## %s error: %d\n", s, err); 462 return 1; 463 } 464 return 0; 465 } 466 467 static int check_capability_error(jvmtiError err, const char *s) { 468 if (err != JVMTI_ERROR_NONE) { 469 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 470 return 0; 471 } 472 printf(" ## %s error: %d\n", s, err); 473 return 1; 474 } 475 return 1; 476 } 477 478 static 479 jint throw_exc(JNIEnv *env, char *msg) { 480 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 481 482 if (exc_class == NULL) { 483 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 484 return -1; 485 } 486 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 487 } 488 489 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 490 491 JNIEXPORT 492 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 493 return Agent_Initialize(jvm, options, reserved); 494 } 495 496 JNIEXPORT 497 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 498 return Agent_Initialize(jvm, options, reserved); 499 } 500 501 JNIEXPORT 502 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 503 return JNI_VERSION_1_8; 504 } 505 506 JNIEXPORT 507 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env, 508 JNIEnv* jni_env, 509 jthread thread, 510 jobject object, 511 jclass object_klass, 512 jlong size) { 513 if (event_storage_get_compaction_required(&global_event_storage)) { 514 event_storage_compact(&global_event_storage, jni_env); 515 } 516 517 jvmtiThreadInfo first_info; 518 event_storage_add(&global_event_storage, jni_env, thread, object, 519 object_klass, size); 520 } 521 522 JNIEXPORT 523 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env, 524 JNIEnv* jni_env, 525 jthread thread, 526 jobject object, 527 jclass object_klass, 528 jlong size) { 529 event_storage_add(&second_global_event_storage, jni_env, thread, object, 530 object_klass, size); 531 } 532 533 JNIEXPORT 534 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) { 535 event_storage_set_compaction_required(&global_event_storage); 536 } 537 538 static int enable_notifications() { 539 if (check_error((*jvmti)->SetEventNotificationMode( 540 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 541 "Set event notifications")) { 542 return 1; 543 } 544 545 return check_error((*jvmti)->SetEventNotificationMode( 546 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 547 "Set event notifications"); 548 } 549 550 static int enable_notifications_for_two_threads(jthread first, jthread second) { 551 if (check_error((*jvmti)->SetEventNotificationMode( 552 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 553 "Set event notifications")) { 554 return 0; 555 } 556 557 if (check_error((*jvmti)->SetEventNotificationMode( 558 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, first), 559 "Set event notifications")) { 560 return 0; 561 } 562 563 // Second thread should fail. 564 if (check_error((*jvmti)->SetEventNotificationMode( 565 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, second), 566 "Set event notifications")) { 567 return 0; 568 } 569 570 return 1; 571 } 572 573 static 574 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 575 jint res; 576 577 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 578 JVMTI_VERSION_9); 579 if (res != JNI_OK || jvmti == NULL) { 580 fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n"); 581 return JNI_ERR; 582 } 583 584 // Get second jvmti environment. 585 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &second_jvmti), 586 JVMTI_VERSION_9); 587 if (res != JNI_OK || second_jvmti == NULL) { 588 fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n"); 589 return JNI_ERR; 590 } 591 592 pthread_mutex_init(&global_event_storage.storage_mutex, 0); 593 pthread_mutex_init(&global_event_storage.compaction_mutex, 0); 594 event_storage_set_garbage_history(&global_event_storage, 200); 595 596 pthread_mutex_init(&second_global_event_storage.storage_mutex, 0); 597 pthread_mutex_init(&second_global_event_storage.compaction_mutex, 0); 598 event_storage_set_garbage_history(&second_global_event_storage, 200); 599 600 jvmtiEventCallbacks callbacks; 601 memset(&callbacks, 0, sizeof(callbacks)); 602 callbacks.SampledObjectAlloc = &SampledObjectAlloc; 603 callbacks.VMObjectAlloc = &VMObjectAlloc; 604 callbacks.GarbageCollectionFinish = &GarbageCollectionFinish; 605 606 jvmtiCapabilities caps; 607 memset(&caps, 0, sizeof(caps)); 608 // Get line numbers, sample events, filename, and gc events for the tests. 609 caps.can_get_line_numbers = 1; 610 caps.can_generate_sampled_alloc_events = 1; 611 caps.can_generate_vm_object_alloc_events = 1; 612 caps.can_get_source_file_name = 1; 613 caps.can_generate_garbage_collection_events = 1; 614 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")) { 615 return JNI_ERR; 616 } 617 618 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 619 sizeof(jvmtiEventCallbacks)), 620 " Set Event Callbacks")) { 621 return JNI_ERR; 622 } 623 return JNI_OK; 624 } 625 626 JNIEXPORT void JNICALL 627 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) { 628 (*jvmti)->SetHeapSamplingRate(jvmti, value); 629 } 630 631 JNIEXPORT jboolean JNICALL 632 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { 633 return event_storage_get_count(&global_event_storage) == 0; 634 } 635 636 JNIEXPORT jint JNICALL 637 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) { 638 return event_storage_get_count(&global_event_storage); 639 } 640 641 JNIEXPORT void JNICALL 642 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) { 643 enable_notifications(); 644 } 645 646 JNIEXPORT jboolean JNICALL 647 Java_MyPackage_HeapMonitor_enableSamplingEventsForTwoThreads(JNIEnv* env, 648 jclass cls, 649 jthread first, 650 jthread second) { 651 return enable_notifications_for_two_threads(first, second); 652 } 653 654 JNIEXPORT void JNICALL 655 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { 656 check_error((*jvmti)->SetEventNotificationMode( 657 jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 658 "Set event notifications"); 659 660 check_error((*jvmti)->SetEventNotificationMode( 661 jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 662 "Garbage Collection Finish"); 663 } 664 665 JNIEXPORT jboolean JNICALL 666 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { 667 jsize size = (*env)->GetArrayLength(env, frames); 668 ExpectedContentFrame native_frames[size]; 669 fill_native_frames(env, frames, native_frames, size); 670 return event_storage_contains(env, &global_event_storage, native_frames, size); 671 } 672 673 JNIEXPORT jboolean JNICALL 674 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) { 675 jsize size = (*env)->GetArrayLength(env, frames); 676 ExpectedContentFrame native_frames[size]; 677 fill_native_frames(env, frames, native_frames, size); 678 return event_storage_garbage_contains(env, &global_event_storage, native_frames, size); 679 } 680 681 JNIEXPORT void JNICALL 682 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) { 683 check_error((*jvmti)->ForceGarbageCollection(jvmti), 684 "Forced Garbage Collection"); 685 } 686 687 JNIEXPORT void JNICALL 688 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { 689 event_storage_reset(&global_event_storage); 690 event_storage_reset(&second_global_event_storage); 691 } 692 693 JNIEXPORT jboolean JNICALL 694 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 695 jclass cls) { 696 jvmtiCapabilities caps; 697 memset(&caps, 0, sizeof(caps)); 698 caps.can_generate_sampled_alloc_events = 1; 699 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 700 "Add capabilities\n")){ 701 return FALSE; 702 } 703 704 if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19), 705 "Set Heap Sampling Rate")) { 706 return FALSE; 707 } 708 return TRUE; 709 } 710 711 JNIEXPORT jboolean JNICALL 712 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env, 713 jclass cls) { 714 if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 0), 715 "Sampling rate 0 failed\n")){ 716 return FALSE; 717 } 718 719 if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 1024), 720 "Sampling rate 1024 failed\n")){ 721 return FALSE; 722 } 723 724 if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1), 725 "Sampling rate -1 passed\n")){ 726 return FALSE; 727 } 728 729 if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1024), 730 "Sampling rate -1024 passed\n")){ 731 return FALSE; 732 } 733 734 return TRUE; 735 } 736 737 JNIEXPORT jdouble JNICALL 738 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { 739 return event_storage_get_average_rate(&global_event_storage); 740 } 741 742 typedef struct sThreadsFound { 743 jthread* threads; 744 int num_threads; 745 } ThreadsFound; 746 747 static void find_threads_in_array(ThreadsFound* thread_data, 748 ObjectTrace** array, 749 int array_size) { 750 int i; 751 jthread* threads = thread_data->threads; 752 int num_threads = thread_data->num_threads; 753 754 for (i = 0; i < array_size; i++) { 755 ObjectTrace* object = array[i]; 756 757 if (object == NULL) { 758 continue; 759 } 760 761 // Check it is the right frame: only accept helper top framed traces. 762 if (object->frame_count == 0) { 763 continue; 764 } 765 766 jvmtiFrameInfo* frames = object->frames; 767 jthread thread = object->thread; 768 769 jmethodID methodid = frames[0].method; 770 char *name = NULL, *signature = NULL, *file_name = NULL; 771 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 772 773 if (strcmp(name, "helper")) { 774 continue; 775 } 776 777 // Really not efficient look-up but it's for a test... 778 int found = 0; 779 int j; 780 for (j = 0; j < num_threads; j++) { 781 if (thread == threads[j]) { 782 found = 1; 783 break; 784 } 785 } 786 787 if (!found) { 788 threads[num_threads] = thread; 789 num_threads++; 790 } 791 } 792 thread_data->num_threads = num_threads; 793 } 794 795 JNIEXPORT jboolean JNICALL 796 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, 797 jint num_threads) { 798 pthread_mutex_lock(&global_event_storage.storage_mutex); 799 jint trace_counter; 800 801 ThreadsFound thread_data; 802 thread_data.num_threads = 0; 803 thread_data.threads = malloc(sizeof(jthread) * num_threads); 804 memset(thread_data.threads, 0, sizeof(jthread) * num_threads); 805 806 find_threads_in_array(&thread_data, global_event_storage.live_objects, 807 global_event_storage.live_object_count); 808 809 free(thread_data.threads); 810 pthread_mutex_unlock(&global_event_storage.storage_mutex); 811 fprintf(stderr, "Obtained %d - %d\n", 812 thread_data.num_threads, 813 num_threads); 814 return thread_data.num_threads == num_threads; 815 } 816 817 818 static void release_data(JNIEnv* env, jstring first, const char* first_str, 819 jstring second, const char* second_str, 820 jthread* threads) { 821 (*env)->ReleaseStringUTFChars(env, first, first_str); 822 (*env)->ReleaseStringUTFChars(env, second, second_str); 823 free(threads); 824 } 825 826 JNIEXPORT jboolean JNICALL 827 Java_MyPackage_HeapMonitorEventsForTwoThreadsTest_checkSamples(JNIEnv* env, 828 jclass cls) { 829 pthread_mutex_lock(&global_event_storage.storage_mutex); 830 jint trace_counter; 831 832 const int expected_num_threads = 2; 833 ThreadsFound thread_data; 834 thread_data.num_threads = 0; 835 thread_data.threads = malloc(sizeof(jthread) * expected_num_threads); 836 memset(thread_data.threads, 0, sizeof(jthread) * expected_num_threads); 837 838 find_threads_in_array(&thread_data, global_event_storage.live_objects, 839 global_event_storage.live_object_count); 840 841 pthread_mutex_unlock(&global_event_storage.storage_mutex); 842 843 int obtained_threads = thread_data.num_threads; 844 return obtained_threads == expected_num_threads; 845 } 846 847 JNIEXPORT 848 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env, 849 JNIEnv* jni_env, 850 jthread thread, 851 jobject object, 852 jclass object_klass, 853 jlong size) { 854 event_storage_add(&second_global_event_storage, jni_env, thread, object, 855 object_klass, size); 856 } 857 858 JNIEXPORT jboolean JNICALL 859 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent( 860 JNIEnv* env, jclass cls) { 861 jvmtiCapabilities caps; 862 memset(&caps, 0, sizeof(caps)); 863 caps.can_generate_sampled_alloc_events = 1; 864 if (check_error((*second_jvmti)->AddCapabilities(second_jvmti, &caps), 865 "Set the capability for second agent")) { 866 return FALSE; 867 } 868 869 jvmtiEventCallbacks callbacks; 870 memset(&callbacks, 0, sizeof(callbacks)); 871 callbacks.SampledObjectAlloc = &SampledObjectAlloc2; 872 873 if (check_error((*second_jvmti)->SetEventCallbacks(second_jvmti, &callbacks, 874 sizeof(jvmtiEventCallbacks)), 875 " Set Event Callbacks for second agent")) { 876 return FALSE; 877 } 878 879 return TRUE; 880 } 881 882 JNIEXPORT jboolean JNICALL 883 Java_MyPackage_HeapMonitorTwoAgentsTest_obtainedEventsForBothAgents( 884 JNIEnv* env, jclass cls, jobjectArray frames) { 885 jsize size = (*env)->GetArrayLength(env, frames); 886 ExpectedContentFrame native_frames[size]; 887 fill_native_frames(env, frames, native_frames, size); 888 889 int first_storage_contained_events = 890 event_storage_contains(env, &global_event_storage, native_frames, size); 891 892 int second_storage_contained_events = 893 event_storage_contains(env, &second_global_event_storage, native_frames, size); 894 895 return first_storage_contained_events && second_storage_contained_events; 896 } 897 898 JNIEXPORT void JNICALL 899 Java_MyPackage_HeapMonitorVMEventsTest_enableVMEvents(JNIEnv* env, jclass cls) { 900 check_error((*jvmti)->SetEventNotificationMode( 901 jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL), 902 "Set vm event notifications"); 903 } 904 905 JNIEXPORT jboolean JNICALL 906 Java_MyPackage_HeapMonitorVMEventsTest_vmStorageContained( 907 JNIEnv* env, jclass cls, jobjectArray frames) { 908 jsize size = (*env)->GetArrayLength(env, frames); 909 ExpectedContentFrame native_frames[size]; 910 fill_native_frames(env, frames, native_frames, size); 911 912 return event_storage_contains(env, &second_global_event_storage, native_frames, size); 913 } 914 915 JNIEXPORT jint JNICALL 916 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) { 917 return event_storage_number_additions(&second_global_event_storage); 918 } 919 920 JNIEXPORT jint JNICALL 921 Java_MyPackage_HeapMonitorVMEventsTest_sampledEvents(JNIEnv* env, jclass cls) { 922 return event_storage_number_additions(&global_event_storage); 923 } 924 925 #ifdef __cplusplus 926 } 927 #endif