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