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 <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include "jvmti.h" 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #ifndef JNI_ENV_ARG 35 36 #ifdef __cplusplus 37 #define JNI_ENV_ARG(x, y) y 38 #define JNI_ENV_PTR(x) x 39 #else 40 #define JNI_ENV_ARG(x,y) x, y 41 #define JNI_ENV_PTR(x) (*x) 42 #endif 43 44 #endif 45 46 #define TRUE 1 47 #define FALSE 0 48 #define PRINT_OUT 0 49 50 static jvmtiEnv *jvmti = NULL; 51 static jvmtiEnv *second_jvmti = NULL; 52 53 typedef struct _ObjectTrace{ 54 jweak object; 55 size_t size; 56 jvmtiFrameInfo* frames; 57 size_t frame_count; 58 jthread thread; 59 } ObjectTrace; 60 61 typedef struct _EventStorage { 62 int live_object_additions; 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 monitors to separate storage data race and the compaction field 72 // data race. 73 jrawMonitorID storage_monitor; 74 75 int compaction_required; 76 jrawMonitorID compaction_monitor; 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 static 87 void event_storage_lock(EventStorage* storage) { 88 (*jvmti)->RawMonitorEnter(jvmti, storage->storage_monitor); 89 } 90 91 static 92 void event_storage_unlock(EventStorage* storage) { 93 (*jvmti)->RawMonitorExit(jvmti, storage->storage_monitor); 94 } 95 96 static 97 void event_storage_lock_compaction(EventStorage* storage) { 98 (*jvmti)->RawMonitorEnter(jvmti, storage->compaction_monitor); 99 } 100 101 static 102 void event_storage_unlock_compaction(EventStorage* storage) { 103 (*jvmti)->RawMonitorExit(jvmti, storage->compaction_monitor); 104 } 105 106 // Given a method and a location, this method gets the line number. 107 static 108 jint get_line_number(jvmtiEnv* jvmti, jmethodID method, 109 jlocation location) { 110 // Read the line number table. 111 jvmtiLineNumberEntry *table_ptr = 0; 112 jint line_number_table_entries; 113 int l; 114 jlocation last_location; 115 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 116 &line_number_table_entries, 117 &table_ptr); 118 119 if (JVMTI_ERROR_NONE != jvmti_error) { 120 return -1; 121 } 122 if (line_number_table_entries <= 0) { 123 return -1; 124 } 125 if (line_number_table_entries == 1) { 126 return table_ptr[0].line_number; 127 } 128 129 // Go through all the line numbers... 130 last_location = table_ptr[0].start_location; 131 for (l = 1; l < line_number_table_entries; l++) { 132 // ... and if you see one that is in the right place for your 133 // location, you've found the line number! 134 if ((location < table_ptr[l].start_location) && 135 (location >= last_location)) { 136 return table_ptr[l - 1].line_number; 137 } 138 last_location = table_ptr[l].start_location; 139 } 140 141 if (location >= last_location) { 142 return table_ptr[line_number_table_entries - 1].line_number; 143 } else { 144 return -1; 145 } 146 } 147 148 static void print_out_frames(JNIEnv* env, ObjectTrace* trace) { 149 jvmtiFrameInfo* frames = trace->frames; 150 size_t i; 151 for (i = 0; i < trace->frame_count; i++) { 152 // Get basic information out of the trace. 153 jlocation bci = frames[i].location; 154 jmethodID methodid = frames[i].method; 155 char *name = NULL, *signature = NULL, *file_name = NULL; 156 jclass declaring_class; 157 int line_number; 158 jvmtiError err; 159 160 if (bci < 0) { 161 fprintf(stderr, "\tNative frame\n"); 162 continue; 163 } 164 165 // Transform into usable information. 166 line_number = get_line_number(jvmti, methodid, bci); 167 if (JVMTI_ERROR_NONE != 168 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0)) { 169 fprintf(stderr, "\tUnknown method name\n"); 170 continue; 171 } 172 173 if (JVMTI_ERROR_NONE != 174 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 175 fprintf(stderr, "\tUnknown class\n"); 176 continue; 177 } 178 179 err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 180 &file_name); 181 if (err != JVMTI_ERROR_NONE) { 182 fprintf(stderr, "\tUnknown file\n"); 183 continue; 184 } 185 186 // Compare now, none should be NULL. 187 if (name == NULL) { 188 fprintf(stderr, "\tUnknown name\n"); 189 continue; 190 } 191 192 if (file_name == NULL) { 193 fprintf(stderr, "\tUnknown file\n"); 194 continue; 195 } 196 197 if (signature == NULL) { 198 fprintf(stderr, "\tUnknown signature\n"); 199 continue; 200 } 201 202 fprintf(stderr, "\t%s%s (%s: %d)\n", 203 name, signature, file_name, line_number); 204 } 205 } 206 207 static jboolean check_sample_content(JNIEnv* env, 208 ObjectTrace* trace, 209 ExpectedContentFrame *expected, 210 size_t expected_count, 211 int print_out_comparisons) { 212 jvmtiFrameInfo* frames; 213 size_t i; 214 215 if (expected_count > trace->frame_count) { 216 return FALSE; 217 } 218 219 frames = trace->frames; 220 for (i = 0; i < expected_count; i++) { 221 // Get basic information out of the trace. 222 jlocation bci = frames[i].location; 223 jmethodID methodid = frames[i].method; 224 char *name = NULL, *signature = NULL, *file_name = NULL; 225 jclass declaring_class; 226 int line_number; 227 jvmtiError err; 228 229 if (bci < 0 && expected[i].line_number != -1) { 230 return FALSE; 231 } 232 233 // Transform into usable information. 234 line_number = get_line_number(jvmti, methodid, bci); 235 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 236 237 if (JVMTI_ERROR_NONE != 238 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 239 return FALSE; 240 } 241 242 err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 243 &file_name); 244 if (err != JVMTI_ERROR_NONE) { 245 return FALSE; 246 } 247 248 // Compare now, none should be NULL. 249 if (name == NULL) { 250 return FALSE; 251 } 252 253 if (file_name == NULL) { 254 return FALSE; 255 } 256 257 if (signature == NULL) { 258 return FALSE; 259 } 260 261 if (print_out_comparisons) { 262 fprintf(stderr, "\tComparing:\n"); 263 fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name); 264 fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature); 265 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name); 266 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number); 267 fprintf(stderr, "\t\tResult is %d\n", 268 (strcmp(name, expected[i].name) || 269 strcmp(signature, expected[i].signature) || 270 strcmp(file_name, expected[i].file_name) || 271 line_number != expected[i].line_number)); 272 } 273 274 if (strcmp(name, expected[i].name) || 275 strcmp(signature, expected[i].signature) || 276 strcmp(file_name, expected[i].file_name) || 277 line_number != expected[i].line_number) { 278 return FALSE; 279 } 280 } 281 282 return TRUE; 283 } 284 285 // Static native API for various tests. 286 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 287 ExpectedContentFrame* native_frames, size_t size) { 288 size_t i; 289 for (i = 0; i < size; i++) { 290 jobject obj = (*env)->GetObjectArrayElement(env, frames, (jsize) i); 291 jclass frame_class = (*env)->GetObjectClass(env, obj); 292 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, 293 "lineNumber", "I"); 294 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 295 296 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", 297 "Ljava/lang/String;"); 298 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, 299 string_id); 300 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 301 const char* file_name; 302 const char* signature; 303 304 string_id = (*env)->GetFieldID(env, frame_class, "fileName", 305 "Ljava/lang/String;"); 306 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 307 file_name = (*env)->GetStringUTFChars(env, string_object, 0); 308 309 string_id = (*env)->GetFieldID(env, frame_class, "signature", 310 "Ljava/lang/String;"); 311 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 312 signature= (*env)->GetStringUTFChars(env, string_object, 0); 313 314 native_frames[i].name = method; 315 native_frames[i].file_name = file_name; 316 native_frames[i].signature = signature; 317 native_frames[i].line_number = line_number; 318 } 319 } 320 321 // Internal storage system implementation. 322 static EventStorage global_event_storage; 323 static EventStorage second_global_event_storage; 324 325 static void event_storage_set_compaction_required(EventStorage* storage) { 326 event_storage_lock_compaction(storage); 327 storage->compaction_required = 1; 328 event_storage_unlock_compaction(storage); 329 } 330 331 static int event_storage_get_compaction_required(EventStorage* storage) { 332 int result; 333 event_storage_lock_compaction(storage); 334 result = storage->compaction_required; 335 event_storage_unlock_compaction(storage); 336 return result; 337 } 338 339 static void event_storage_set_garbage_history(EventStorage* storage, int value) { 340 size_t size; 341 event_storage_lock(storage); 342 global_event_storage.garbage_history_size = value; 343 free(global_event_storage.garbage_collected_objects); 344 size = sizeof(*global_event_storage.garbage_collected_objects) * value; 345 global_event_storage.garbage_collected_objects = malloc(size); 346 memset(global_event_storage.garbage_collected_objects, 0, size); 347 event_storage_unlock(storage); 348 } 349 350 // No mutex here, it is handled by the caller. 351 static void event_storage_add_garbage_collected_object(EventStorage* storage, 352 ObjectTrace* object) { 353 int idx = storage->garbage_history_index; 354 ObjectTrace* old_object = storage->garbage_collected_objects[idx]; 355 if (old_object != NULL) { 356 free(old_object->frames); 357 free(storage->garbage_collected_objects[idx]); 358 } 359 360 storage->garbage_collected_objects[idx] = object; 361 storage->garbage_history_index = (idx + 1) % storage->garbage_history_size; 362 } 363 364 static int event_storage_get_count(EventStorage* storage) { 365 int result; 366 event_storage_lock(storage); 367 result = storage->live_object_count; 368 event_storage_unlock(storage); 369 return result; 370 } 371 372 static double event_storage_get_average_rate(EventStorage* storage) { 373 double accumulation = 0; 374 int max_size; 375 int i; 376 377 event_storage_lock(storage); 378 max_size = storage->live_object_count; 379 380 for (i = 0; i < max_size; i++) { 381 accumulation += storage->live_objects[i]->size; 382 } 383 384 event_storage_unlock(storage); 385 return accumulation / max_size; 386 } 387 388 static jboolean event_storage_contains(JNIEnv* env, 389 EventStorage* storage, 390 ExpectedContentFrame* frames, 391 size_t size) { 392 int i; 393 event_storage_lock(storage); 394 fprintf(stderr, "Checking storage count %d\n", storage->live_object_count); 395 for (i = 0; i < storage->live_object_count; i++) { 396 ObjectTrace* trace = storage->live_objects[i]; 397 398 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { 399 event_storage_unlock(storage); 400 return TRUE; 401 } 402 } 403 event_storage_unlock(storage); 404 return FALSE; 405 } 406 407 static jboolean event_storage_garbage_contains(JNIEnv* env, 408 EventStorage* storage, 409 ExpectedContentFrame* frames, 410 size_t size) { 411 int i; 412 event_storage_lock(storage); 413 fprintf(stderr, "Checking garbage storage count %d\n", 414 storage->garbage_history_size); 415 for (i = 0; i < storage->garbage_history_size; i++) { 416 ObjectTrace* trace = storage->garbage_collected_objects[i]; 417 418 if (trace == NULL) { 419 continue; 420 } 421 422 if (check_sample_content(env, trace, frames, size, PRINT_OUT)) { 423 event_storage_unlock(storage); 424 return TRUE; 425 } 426 } 427 event_storage_unlock(storage); 428 return FALSE; 429 } 430 431 // No mutex here, handled by the caller. 432 static void event_storage_augment_storage(EventStorage* storage) { 433 int new_max = (storage->live_object_size * 2) + 1; 434 ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); 435 436 int current_count = storage->live_object_count; 437 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); 438 free(storage->live_objects); 439 storage->live_objects = new_objects; 440 storage->live_object_size = new_max; 441 } 442 443 static void event_storage_add(EventStorage* storage, 444 JNIEnv* jni, 445 jthread thread, 446 jobject object, 447 jclass klass, 448 jlong size) { 449 jvmtiFrameInfo frames[64]; 450 jint count; 451 jvmtiError err; 452 453 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); 454 if (err == JVMTI_ERROR_NONE && count >= 1) { 455 ObjectTrace* live_object; 456 jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames)); 457 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); 458 459 live_object = (ObjectTrace*) malloc(sizeof(*live_object)); 460 live_object->frames = allocated_frames; 461 live_object->frame_count = count; 462 live_object->size = size; 463 live_object->thread = thread; 464 live_object->object = (*jni)->NewWeakGlobalRef(jni, object); 465 466 // Only now lock and get things done quickly. 467 event_storage_lock(storage); 468 469 storage->live_object_additions++; 470 471 if (storage->live_object_count >= storage->live_object_size) { 472 event_storage_augment_storage(storage); 473 } 474 assert(storage->live_object_count < storage->live_object_size); 475 476 if (PRINT_OUT) { 477 fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n", 478 thread, count, storage); 479 print_out_frames(jni, live_object); 480 } 481 storage->live_objects[storage->live_object_count] = live_object; 482 storage->live_object_count++; 483 484 event_storage_unlock(storage); 485 } 486 } 487 488 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) { 489 int max, i, dest; 490 ObjectTrace** live_objects; 491 492 event_storage_lock_compaction(storage); 493 storage->compaction_required = 0; 494 event_storage_unlock_compaction(storage); 495 496 event_storage_lock(storage); 497 498 max = storage->live_object_count; 499 live_objects = storage->live_objects; 500 501 for (i = 0, dest = 0; i < max; i++) { 502 ObjectTrace* live_object = live_objects[i]; 503 jweak object = live_object->object; 504 505 if (!(*jni)->IsSameObject(jni, object, NULL)) { 506 if (dest != i) { 507 live_objects[dest] = live_object; 508 dest++; 509 } 510 } else { 511 (*jni)->DeleteWeakGlobalRef(jni, object); 512 live_object->object = NULL; 513 514 event_storage_add_garbage_collected_object(storage, live_object); 515 } 516 } 517 518 storage->live_object_count = dest; 519 event_storage_unlock(storage); 520 } 521 522 static void event_storage_free_objects(ObjectTrace** array, int max) { 523 int i; 524 for (i = 0; i < max; i++) { 525 free(array[i]), array[i] = NULL; 526 } 527 } 528 529 static void event_storage_reset(EventStorage* storage) { 530 event_storage_lock(storage); 531 532 // Reset everything except the mutex and the garbage collection. 533 event_storage_free_objects(storage->live_objects, 534 storage->live_object_count); 535 storage->live_object_additions = 0; 536 storage->live_object_size = 0; 537 storage->live_object_count = 0; 538 free(storage->live_objects), storage->live_objects = NULL; 539 540 event_storage_free_objects(storage->garbage_collected_objects, 541 storage->garbage_history_size); 542 543 storage->compaction_required = 0; 544 storage->garbage_history_index = 0; 545 546 event_storage_unlock(storage); 547 } 548 549 static int event_storage_number_additions(EventStorage* storage) { 550 int result; 551 event_storage_lock(storage); 552 result = storage->live_object_additions; 553 event_storage_unlock(storage); 554 return result; 555 } 556 557 // Start of the JVMTI agent code. 558 static const char *EXC_CNAME = "java/lang/Exception"; 559 560 static int check_error(jvmtiError err, const char *s) { 561 if (err != JVMTI_ERROR_NONE) { 562 printf(" ## %s error: %d\n", s, err); 563 return 1; 564 } 565 return 0; 566 } 567 568 static int check_capability_error(jvmtiError err, const char *s) { 569 if (err != JVMTI_ERROR_NONE) { 570 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 571 return 0; 572 } 573 fprintf(stderr, " ## %s error: %d\n", s, err); 574 } 575 return 1; 576 } 577 578 static jint throw_exception(JNIEnv *env, char *msg) { 579 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 580 581 if (exc_class == NULL) { 582 fprintf(stderr, "throw_exception: Error in FindClass(env, %s)\n", 583 EXC_CNAME); 584 return -1; 585 } 586 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 587 } 588 589 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 590 591 JNIEXPORT 592 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 593 return Agent_Initialize(jvm, options, reserved); 594 } 595 596 JNIEXPORT 597 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 598 return Agent_Initialize(jvm, options, reserved); 599 } 600 601 JNIEXPORT 602 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 603 return JNI_VERSION_1_8; 604 } 605 606 #define MAX_THREADS 500 607 608 typedef struct ThreadStats { 609 int number_threads; 610 int counts[MAX_THREADS]; 611 int not_helper_counts[MAX_THREADS]; 612 int index[MAX_THREADS]; 613 jthread threads[MAX_THREADS]; 614 615 int method_resolution_problem; 616 } ThreadStats; 617 618 static ThreadStats thread_stats; 619 620 static void add_thread_count(jthread thread, int lock, int helper) { 621 int i; 622 jvmtiThreadInfo info; 623 const char* name; 624 char* end; 625 int idx; 626 int err; 627 628 if (lock) { 629 event_storage_lock(&global_event_storage); 630 } 631 632 for (i = 0; i < thread_stats.number_threads; i++) { 633 if (thread_stats.threads[i] == thread) { 634 if (helper) { 635 thread_stats.counts[i]++; 636 } else { 637 thread_stats.not_helper_counts[i]++; 638 } 639 640 if (lock) { 641 event_storage_unlock(&global_event_storage); 642 } 643 return; 644 } 645 } 646 647 thread_stats.threads[thread_stats.number_threads] = thread; 648 649 err = (*jvmti)->GetThreadInfo(jvmti, thread, &info); 650 if (err != JVMTI_ERROR_NONE) { 651 if (lock) { 652 event_storage_unlock(&global_event_storage); 653 } 654 655 // Just to have it accounted as an error... 656 info.name = "Allocator99"; 657 } 658 659 if (!strstr(info.name, "Allocator")) { 660 if (lock) { 661 event_storage_unlock(&global_event_storage); 662 } 663 664 // Just to have it accounted as an error... 665 info.name = "Allocator98"; 666 } 667 668 name = info.name + 9; 669 end = NULL; 670 idx = strtol(name, &end, 0); 671 672 if (*end == '\0') { 673 if (helper) { 674 thread_stats.counts[thread_stats.number_threads]++; 675 } else { 676 thread_stats.not_helper_counts[thread_stats.number_threads]++; 677 } 678 679 thread_stats.index[thread_stats.number_threads] = idx; 680 thread_stats.number_threads++; 681 } else { 682 fprintf(stderr, "Problem with thread name...: %p %s\n", thread, name); 683 } 684 685 if (PRINT_OUT) { 686 fprintf(stderr, "Added %s - %p - %d - lock: %d\n", info.name, thread, idx, lock); 687 } 688 689 if (lock) { 690 event_storage_unlock(&global_event_storage); 691 } 692 } 693 694 static void print_thread_stats() { 695 int i; 696 event_storage_lock(&global_event_storage); 697 fprintf(stderr, "Method resolution problem: %d\n", thread_stats.method_resolution_problem); 698 fprintf(stderr, "Thread count:\n"); 699 for (i = 0; i < thread_stats.number_threads; i++) { 700 fprintf(stderr, "\t%p: %d: %d - %d\n", thread_stats.threads[i], 701 thread_stats.index[i], 702 thread_stats.counts[i], 703 thread_stats.not_helper_counts[i]); 704 } 705 event_storage_unlock(&global_event_storage); 706 } 707 708 JNIEXPORT 709 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env, 710 JNIEnv* jni_env, 711 jthread thread, 712 jobject object, 713 jclass object_klass, 714 jlong size) { 715 add_thread_count(thread, 1, 1); 716 717 if (event_storage_get_compaction_required(&global_event_storage)) { 718 event_storage_compact(&global_event_storage, jni_env); 719 } 720 721 event_storage_add(&global_event_storage, jni_env, thread, object, 722 object_klass, size); 723 } 724 725 JNIEXPORT 726 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env, 727 JNIEnv* jni_env, 728 jthread thread, 729 jobject object, 730 jclass object_klass, 731 jlong size) { 732 event_storage_add(&second_global_event_storage, jni_env, thread, object, 733 object_klass, size); 734 } 735 736 JNIEXPORT 737 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) { 738 event_storage_set_compaction_required(&global_event_storage); 739 } 740 741 static int enable_notifications() { 742 if (check_error((*jvmti)->SetEventNotificationMode( 743 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 744 "Set event notifications")) { 745 return 1; 746 } 747 748 return check_error((*jvmti)->SetEventNotificationMode( 749 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 750 "Set event notifications"); 751 } 752 753 static int enable_notifications_for_two_threads(jthread first, jthread second) { 754 if (check_error((*jvmti)->SetEventNotificationMode( 755 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 756 "Set event notifications")) { 757 return 0; 758 } 759 760 if (check_error((*jvmti)->SetEventNotificationMode( 761 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, first), 762 "Set event notifications")) { 763 return 0; 764 } 765 766 // Second thread should fail. 767 if (check_error((*jvmti)->SetEventNotificationMode( 768 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, second), 769 "Set event notifications")) { 770 return 0; 771 } 772 773 return 1; 774 } 775 776 static 777 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 778 jint res; 779 jvmtiEventCallbacks callbacks; 780 jvmtiCapabilities caps; 781 782 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 783 JVMTI_VERSION_9); 784 if (res != JNI_OK || jvmti == NULL) { 785 fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n"); 786 return JNI_ERR; 787 } 788 789 // Get second jvmti environment. 790 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &second_jvmti), 791 JVMTI_VERSION_9); 792 if (res != JNI_OK || second_jvmti == NULL) { 793 fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n"); 794 return JNI_ERR; 795 } 796 797 if (PRINT_OUT) { 798 fprintf(stderr, "Storage is at %p, secondary is at %p\n", 799 &global_event_storage, &second_global_event_storage); 800 } 801 802 (*jvmti)->CreateRawMonitor(jvmti, "storage_monitor", 803 &global_event_storage.storage_monitor); 804 (*jvmti)->CreateRawMonitor(jvmti, "second_storage_monitor", 805 &second_global_event_storage.storage_monitor); 806 807 (*jvmti)->CreateRawMonitor(jvmti, "compaction_monitor", 808 &global_event_storage.compaction_monitor); 809 (*jvmti)->CreateRawMonitor(jvmti, "second_compaction_monitor", 810 &second_global_event_storage.compaction_monitor); 811 812 event_storage_set_garbage_history(&global_event_storage, 200); 813 event_storage_set_garbage_history(&second_global_event_storage, 200); 814 815 memset(&callbacks, 0, sizeof(callbacks)); 816 callbacks.SampledObjectAlloc = &SampledObjectAlloc; 817 callbacks.VMObjectAlloc = &VMObjectAlloc; 818 callbacks.GarbageCollectionFinish = &GarbageCollectionFinish; 819 820 memset(&caps, 0, sizeof(caps)); 821 // Get line numbers, sample events, filename, and gc events for the tests. 822 caps.can_get_line_numbers = 1; 823 caps.can_get_source_file_name = 1; 824 caps.can_generate_garbage_collection_events = 1; 825 caps.can_generate_sampled_object_alloc_events = 1; 826 caps.can_generate_vm_object_alloc_events = 1; 827 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")) { 828 return JNI_ERR; 829 } 830 831 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 832 sizeof(jvmtiEventCallbacks)), 833 " Set Event Callbacks")) { 834 return JNI_ERR; 835 } 836 return JNI_OK; 837 } 838 839 JNIEXPORT void JNICALL 840 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) { 841 (*jvmti)->SetHeapSamplingRate(jvmti, value); 842 } 843 844 JNIEXPORT jboolean JNICALL 845 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { 846 return event_storage_get_count(&global_event_storage) == 0; 847 } 848 849 JNIEXPORT jint JNICALL 850 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) { 851 return event_storage_get_count(&global_event_storage); 852 } 853 854 JNIEXPORT void JNICALL 855 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) { 856 enable_notifications(); 857 } 858 859 JNIEXPORT jboolean JNICALL 860 Java_MyPackage_HeapMonitor_enableSamplingEventsForTwoThreads(JNIEnv* env, 861 jclass cls, 862 jthread first, 863 jthread second) { 864 return enable_notifications_for_two_threads(first, second); 865 } 866 867 JNIEXPORT void JNICALL 868 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) { 869 check_error((*jvmti)->SetEventNotificationMode( 870 jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 871 "Set event notifications"); 872 873 check_error((*jvmti)->SetEventNotificationMode( 874 jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL), 875 "Garbage Collection Finish"); 876 } 877 878 JNIEXPORT jboolean JNICALL 879 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { 880 jboolean result; 881 jsize size = (*env)->GetArrayLength(env, frames); 882 ExpectedContentFrame *native_frames = malloc(size * sizeof(*native_frames)); 883 884 if (native_frames == NULL) { 885 return 0; 886 } 887 888 fill_native_frames(env, frames, native_frames, size); 889 result = event_storage_contains(env, &global_event_storage, native_frames, size); 890 891 free(native_frames), native_frames = NULL; 892 return result; 893 } 894 895 JNIEXPORT jboolean JNICALL 896 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) { 897 jboolean result; 898 jsize size = (*env)->GetArrayLength(env, frames); 899 ExpectedContentFrame *native_frames = malloc(size * sizeof(*native_frames)); 900 901 if (native_frames == NULL) { 902 return 0; 903 } 904 905 fill_native_frames(env, frames, native_frames, size); 906 result = event_storage_garbage_contains(env, &global_event_storage, native_frames, size); 907 908 free(native_frames), native_frames = NULL; 909 return result; 910 } 911 912 JNIEXPORT void JNICALL 913 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) { 914 check_error((*jvmti)->ForceGarbageCollection(jvmti), 915 "Forced Garbage Collection"); 916 } 917 918 JNIEXPORT void JNICALL 919 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { 920 event_storage_reset(&global_event_storage); 921 event_storage_reset(&second_global_event_storage); 922 } 923 924 JNIEXPORT jboolean JNICALL 925 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 926 jclass cls) { 927 jvmtiCapabilities caps; 928 memset(&caps, 0, sizeof(caps)); 929 caps.can_generate_sampled_object_alloc_events = 1; 930 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 931 "Add capabilities\n")){ 932 return FALSE; 933 } 934 935 if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19), 936 "Set Heap Sampling Rate")) { 937 return FALSE; 938 } 939 return TRUE; 940 } 941 942 JNIEXPORT jboolean JNICALL 943 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env, 944 jclass cls) { 945 if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 0), 946 "Sampling rate 0 failed\n")){ 947 return FALSE; 948 } 949 950 if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 1024), 951 "Sampling rate 1024 failed\n")){ 952 return FALSE; 953 } 954 955 if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1), 956 "Sampling rate -1 passed\n")){ 957 return FALSE; 958 } 959 960 if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1024), 961 "Sampling rate -1024 passed\n")){ 962 return FALSE; 963 } 964 965 return TRUE; 966 } 967 968 JNIEXPORT jdouble JNICALL 969 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { 970 return event_storage_get_average_rate(&global_event_storage); 971 } 972 973 typedef struct sThreadsFound { 974 jthread* threads; 975 int num_threads; 976 } ThreadsFound; 977 978 JNIEXPORT jboolean JNICALL 979 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, 980 jint num_threads) { 981 982 print_thread_stats(); 983 // Ensure we got stacks from at least num_threads. 984 return thread_stats.number_threads >= num_threads; 985 } 986 987 JNIEXPORT 988 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env, 989 JNIEnv* jni_env, 990 jthread thread, 991 jobject object, 992 jclass object_klass, 993 jlong size) { 994 // Nop for now, two agents are not yet implemented. 995 assert(0); 996 } 997 998 JNIEXPORT jboolean JNICALL 999 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent( 1000 JNIEnv* env, jclass cls) { 1001 // Currently this method should be failing directly at the AddCapability step 1002 // but the implementation is correct for when multi-agent support is enabled. 1003 jvmtiCapabilities caps; 1004 jvmtiEventCallbacks callbacks; 1005 1006 memset(&caps, 0, sizeof(caps)); 1007 caps.can_generate_sampled_object_alloc_events = 1; 1008 if (check_error((*second_jvmti)->AddCapabilities(second_jvmti, &caps), 1009 "Set the capability for second agent")) { 1010 return FALSE; 1011 } 1012 1013 memset(&callbacks, 0, sizeof(callbacks)); 1014 callbacks.SampledObjectAlloc = &SampledObjectAlloc2; 1015 1016 if (check_error((*second_jvmti)->SetEventCallbacks(second_jvmti, &callbacks, 1017 sizeof(jvmtiEventCallbacks)), 1018 " Set Event Callbacks for second agent")) { 1019 return FALSE; 1020 } 1021 1022 return TRUE; 1023 } 1024 1025 JNIEXPORT void JNICALL 1026 Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) { 1027 check_error((*jvmti)->SetEventNotificationMode( 1028 jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL), 1029 "Set vm event notifications"); 1030 } 1031 1032 JNIEXPORT jint JNICALL 1033 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) { 1034 return event_storage_number_additions(&second_global_event_storage); 1035 } 1036 1037 JNIEXPORT jint JNICALL 1038 Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) { 1039 return event_storage_number_additions(&global_event_storage); 1040 } 1041 1042 static void allocate_object(JNIEnv* env) { 1043 // Construct an Object. 1044 jclass cls = (*env)->FindClass(env, "java/lang/Object"); 1045 jmethodID constructor; 1046 1047 if (cls == NULL) { 1048 throw_exception(env, "Cannot find Object class."); 1049 return; 1050 } 1051 1052 constructor = (*env)->GetMethodID(env, cls, "<init>", "()V"); 1053 1054 if (constructor == NULL) { 1055 throw_exception(env, "Cannot find Object class constructor."); 1056 return; 1057 } 1058 1059 // Call back constructor to allocate a new instance, with an int argument 1060 (*env)->NewObject(env, cls, constructor); 1061 } 1062 1063 // Ensure we got a callback for the test. 1064 static int did_recursive_callback_test; 1065 1066 JNIEXPORT 1067 void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env, 1068 JNIEnv* jni_env, 1069 jthread thread, 1070 jobject object, 1071 jclass object_klass, 1072 jlong size) { 1073 // Basically ensure that if we were to allocate objects, we would not have an 1074 // infinite recursion here. 1075 int i; 1076 for (i = 0; i < 1000; i++) { 1077 allocate_object(jni_env); 1078 } 1079 1080 did_recursive_callback_test = 1; 1081 } 1082 1083 JNIEXPORT jboolean JNICALL 1084 Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) { 1085 return did_recursive_callback_test != 0; 1086 } 1087 1088 JNIEXPORT void JNICALL 1089 Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) { 1090 jvmtiEventCallbacks callbacks; 1091 1092 memset(&callbacks, 0, sizeof(callbacks)); 1093 callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc; 1094 1095 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 1096 sizeof(jvmtiEventCallbacks)), 1097 " Set Event Callbacks")) { 1098 throw_exception(env, "Cannot reset the callback."); 1099 return; 1100 } 1101 } 1102 1103 #ifdef __cplusplus 1104 } 1105 #endif