1 /* 2 * Copyright (c) 2017, 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 const char *EXC_CNAME = "java/lang/Exception"; 53 static jvmtiEnv *jvmti = NULL; 54 static pthread_mutex_t event_data_lock; 55 56 // Event storage code. 57 58 typedef struct _LiveObjectTrace{ 59 jvmtiFrameInfo* frames; 60 size_t frame_count; 61 } LiveObjectTrace; 62 63 typedef struct _EventStorage { 64 int live_object_size; 65 int live_object_count; 66 LiveObjectTrace** live_objects; 67 } EventStorage; 68 69 typedef struct _ExpectedContentFrame { 70 const char *name; 71 const char *signature; 72 const char *file_name; 73 int line_number; 74 } ExpectedContentFrame; 75 76 static jboolean check_live_object_trace_content( 77 JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected, 78 size_t expected_count, int print_out_comparisons); 79 80 static EventStorage global_event_storage; 81 82 static int event_storage_get_count(EventStorage* storage) { 83 return storage->live_object_count; 84 } 85 86 static jboolean event_storage_contains(JNIEnv* env, 87 EventStorage* storage, 88 ExpectedContentFrame* frames, 89 size_t size) { 90 int i; 91 fprintf(stderr, "Event storage contains: %d\n", storage->live_object_count); 92 for (i = 0; i < storage->live_object_count; i++) { 93 LiveObjectTrace* trace = storage->live_objects[i]; 94 95 if (check_live_object_trace_content(env, trace, frames, size, PRINT_OUT)) { 96 return TRUE; 97 } 98 } 99 return FALSE; 100 } 101 102 static void event_storage_augment_storage(EventStorage* storage) { 103 int new_max = (storage->live_object_size * 2) + 1; 104 LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects)); 105 106 int current_count = storage->live_object_count; 107 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); 108 free(storage->live_objects); 109 storage->live_objects = new_objects; 110 111 storage->live_object_size = new_max; 112 } 113 114 static void event_storage_add(EventStorage* storage, 115 jthread thread, 116 jobject object, 117 jclass klass, 118 jlong size) { 119 pthread_mutex_lock(&event_data_lock); 120 jvmtiFrameInfo frames[64]; 121 jint count; 122 jvmtiError err; 123 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count); 124 if (err == JVMTI_ERROR_NONE && count >= 1) { 125 if (storage->live_object_count >= storage->live_object_size) { 126 event_storage_augment_storage(storage); 127 } 128 assert(storage->live_object_count < storage->live_object_size); 129 130 jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames)); 131 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames)); 132 133 LiveObjectTrace* live_object = malloc(sizeof(*live_object)); 134 live_object->frames = allocated_frames; 135 live_object->frame_count = count; 136 storage->live_objects[storage->live_object_count] = live_object; 137 storage->live_object_count++; 138 } 139 pthread_mutex_unlock(&event_data_lock); 140 } 141 142 static void event_storage_reset(EventStorage* storage) { 143 pthread_mutex_lock(&event_data_lock); 144 int max = storage->live_object_count; 145 int i; 146 for (i = 0; i < max; i++) { 147 LiveObjectTrace* object = storage->live_objects[i]; 148 free(object); 149 } 150 free(storage->live_objects); 151 memset(storage, 0, sizeof(*storage)); 152 pthread_mutex_unlock(&event_data_lock); 153 } 154 155 // General JVMTI agent code. 156 157 static int check_error(jvmtiError err, const char *s) { 158 if (err != JVMTI_ERROR_NONE) { 159 printf(" ## %s error: %d\n", s, err); 160 return 1; 161 } 162 return 0; 163 } 164 165 static int check_capability_error(jvmtiError err, const char *s) { 166 if (err != JVMTI_ERROR_NONE) { 167 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 168 return 0; 169 } 170 printf(" ## %s error: %d\n", s, err); 171 return 1; 172 } 173 return 1; 174 } 175 176 static 177 jint throw_exc(JNIEnv *env, char *msg) { 178 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 179 180 if (exc_class == NULL) { 181 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 182 return -1; 183 } 184 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 185 } 186 187 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 188 189 JNIEXPORT 190 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 191 return Agent_Initialize(jvm, options, reserved); 192 } 193 194 JNIEXPORT 195 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 196 return Agent_Initialize(jvm, options, reserved); 197 } 198 199 JNIEXPORT 200 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 201 return JNI_VERSION_1_8; 202 } 203 204 JNIEXPORT 205 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env, 206 JNIEnv* jni_env, 207 jthread thread, 208 jobject object, 209 jclass object_klass, 210 jlong size) { 211 // Not optimal to do this at the callback but makes testing easier for now. 212 event_storage_add(&global_event_storage, thread, object, object_klass, size); 213 } 214 215 static 216 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 217 jint res; 218 219 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 220 JVMTI_VERSION_9); 221 if (res != JNI_OK || jvmti == NULL) { 222 printf(" Error: wrong result of a valid call to GetEnv!\n"); 223 return JNI_ERR; 224 } 225 226 jvmtiEventCallbacks callbacks; 227 memset(&callbacks, 0, sizeof(callbacks)); 228 callbacks.SampledObjectAlloc = &SampledObjectAlloc; 229 230 jvmtiCapabilities caps; 231 memset(&caps, 0, sizeof(caps)); 232 // Get line numbers, sample heap, and filename for the test. 233 caps.can_get_line_numbers = 1; 234 caps.can_sample_heap = 1; 235 caps.can_generate_sampled_object_alloc_events = 1; 236 caps.can_get_source_file_name = 1; 237 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), 238 "Add capabilities\n")){ 239 return JNI_ERR; 240 } 241 242 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 243 sizeof(jvmtiEventCallbacks)), 244 " Set Event Callbacks")) { 245 return JNI_ERR; 246 } 247 248 249 if (pthread_mutex_init(&event_data_lock, NULL) != 0) { 250 return JNI_ERR; 251 } 252 253 return JNI_OK; 254 } 255 256 // Given a method and a location, this method gets the line number. 257 static 258 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, 259 jlocation location) { 260 // Read the line number table. 261 jvmtiLineNumberEntry *table_ptr = 0; 262 jint line_number_table_entries; 263 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 264 &line_number_table_entries, 265 &table_ptr); 266 267 if (JVMTI_ERROR_NONE != jvmti_error) { 268 return -1; 269 } 270 if (line_number_table_entries <= 0) { 271 return -1; 272 } 273 if (line_number_table_entries == 1) { 274 return table_ptr[0].line_number; 275 } 276 277 // Go through all the line numbers... 278 jint last_location = table_ptr[0].start_location; 279 int l; 280 for (l = 1; l < line_number_table_entries; l++) { 281 // ... and if you see one that is in the right place for your 282 // location, you've found the line number! 283 if ((location < table_ptr[l].start_location) && 284 (location >= last_location)) { 285 return table_ptr[l - 1].line_number; 286 } 287 last_location = table_ptr[l].start_location; 288 } 289 290 if (location >= last_location) { 291 return table_ptr[line_number_table_entries - 1].line_number; 292 } else { 293 return -1; 294 } 295 } 296 297 static jboolean check_frame_content(JNIEnv *env, 298 jvmtiFrameInfo* frames, 299 ExpectedContentFrame *expected, 300 int expected_count, 301 int print_out_comparisons) { 302 int i; 303 for (i = 0; i < expected_count; i++) { 304 // Get basic information out of the trace. 305 int bci = frames[i].location; 306 jmethodID methodid = frames[i].method; 307 char *name = NULL, *signature = NULL, *file_name = NULL; 308 309 if (bci < 0) { 310 return FALSE; 311 } 312 313 // Transform into usable information. 314 int line_number = get_line_number(jvmti, methodid, bci); 315 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 316 317 jclass declaring_class; 318 if (JVMTI_ERROR_NONE != 319 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 320 return FALSE; 321 } 322 323 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 324 &file_name); 325 if (err != JVMTI_ERROR_NONE) { 326 return FALSE; 327 } 328 329 // Compare now, none should be NULL. 330 if (name == NULL) { 331 return FALSE; 332 } 333 334 if (file_name == NULL) { 335 return FALSE; 336 } 337 338 if (signature == NULL) { 339 return FALSE; 340 } 341 342 if (print_out_comparisons) { 343 fprintf(stderr, "\tComparing:\n"); 344 fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name); 345 fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature); 346 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name); 347 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number); 348 fprintf(stderr, "\t\tResult is %d\n", 349 (strcmp(name, expected[i].name) || 350 strcmp(signature, expected[i].signature) || 351 strcmp(file_name, expected[i].file_name) || 352 line_number != expected[i].line_number)); 353 } 354 355 if (strcmp(name, expected[i].name) || 356 strcmp(signature, expected[i].signature) || 357 strcmp(file_name, expected[i].file_name) || 358 line_number != expected[i].line_number) { 359 return FALSE; 360 } 361 } 362 363 return TRUE; 364 } 365 366 static jboolean check_live_object_trace_content( 367 JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected, 368 size_t expected_count, int print_out_comparisons) { 369 370 if (expected_count > trace->frame_count) { 371 return FALSE; 372 } 373 374 return check_frame_content(env, trace->frames, 375 expected, expected_count, print_out_comparisons); 376 } 377 378 static jboolean check_sample_content(JNIEnv *env, 379 jvmtiAllocTraceInfo* trace, 380 ExpectedContentFrame *expected, 381 int expected_count, 382 int print_out_comparisons) { 383 jvmtiStackInfo* stack_info = trace->stack_info; 384 385 if (expected_count > stack_info->frame_count) { 386 return FALSE; 387 } 388 389 return check_frame_content(env, stack_info->frame_buffer, 390 expected, expected_count, print_out_comparisons); 391 } 392 393 static jboolean compare_samples(JNIEnv* env, jvmtiAllocTraceInfo* traces, 394 int trace_count, 395 ExpectedContentFrame* expected_content, 396 size_t size, 397 int print_out_comparisons) { 398 // We expect the code to record correctly the bci, retrieve the line 399 // number, have the right method and the class name of the first frames. 400 int i; 401 if (print_out_comparisons) { 402 fprintf(stderr, "\tNumber of traces: %d\n", print_out_comparisons); 403 } 404 405 for (i = 0; i < trace_count; i++) { 406 jvmtiAllocTraceInfo* trace = traces + i; 407 if (check_sample_content(env, trace, expected_content, size, 408 print_out_comparisons)) { 409 // At least one frame matched what we were looking for. 410 return TRUE; 411 } 412 } 413 414 return FALSE; 415 } 416 417 static jboolean 418 check_samples(JNIEnv* env, 419 ExpectedContentFrame* expected, 420 size_t size, 421 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*), 422 int print_out_comparisons) { 423 jvmtiAllocTraceInfo *traces; 424 jint trace_counter; 425 jvmtiError error = get_traces(jvmti, &traces, &trace_counter); 426 427 if (error != JVMTI_ERROR_NONE) { 428 return FALSE; 429 } 430 431 int result = compare_samples(env, traces, trace_counter, 432 expected, size, print_out_comparisons); 433 434 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) { 435 return FALSE; 436 } 437 438 return result; 439 } 440 441 static jboolean frames_exist_live(JNIEnv* env, 442 ExpectedContentFrame* expected, 443 size_t size, 444 int print_out_comparisons) { 445 return check_samples(env, expected, size, 446 (*jvmti)->GetLiveObjectAllocTraces, 447 print_out_comparisons); 448 } 449 450 static jboolean frames_exist_recent(JNIEnv* env, 451 ExpectedContentFrame* expected, 452 size_t size, 453 int print_out_comparisons) { 454 return check_samples(env, expected, size, 455 (*jvmti)->GetGarbageObjectAllocTraces, 456 print_out_comparisons); 457 } 458 459 static jboolean frames_exist_frequent(JNIEnv* env, 460 ExpectedContentFrame* expected, 461 size_t size, 462 int print_out_comparisons) { 463 return check_samples(env, expected, size, 464 (*jvmti)->GetFrequentGarbageObjectAllocTraces, 465 print_out_comparisons); 466 } 467 468 // Static native API for various tests. 469 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 470 ExpectedContentFrame* native_frames, size_t size) { 471 size_t i; 472 for(i = 0; i < size; i++) { 473 jobject obj = (*env)->GetObjectArrayElement(env, frames, i); 474 jclass frame_class = (*env)->GetObjectClass(env, obj); 475 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, 476 "lineNumber", "I"); 477 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 478 479 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", 480 "Ljava/lang/String;"); 481 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, 482 string_id); 483 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 484 485 string_id = (*env)->GetFieldID(env, frame_class, "fileName", 486 "Ljava/lang/String;"); 487 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 488 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0); 489 490 string_id = (*env)->GetFieldID(env, frame_class, "signature", 491 "Ljava/lang/String;"); 492 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 493 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0); 494 495 native_frames[i].name = method; 496 native_frames[i].file_name = file_name; 497 native_frames[i].signature = signature; 498 native_frames[i].line_number = line_number; 499 } 500 } 501 502 static jboolean check_and(JNIEnv *env, jobjectArray frames, int live, 503 int recent, int frequent, int print_out) { 504 jobject loader = NULL; 505 506 if (frames == NULL) { 507 return FALSE; 508 } 509 510 // Start by transforming the frames into a C-friendly structure. 511 jsize size = (*env)->GetArrayLength(env, frames); 512 ExpectedContentFrame native_frames[size]; 513 fill_native_frames(env, frames, native_frames, size); 514 515 if (jvmti == NULL) { 516 throw_exc(env, "JVMTI client was not properly loaded!\n"); 517 return FALSE; 518 } 519 520 int result = TRUE; 521 522 if (live) { 523 result = frames_exist_live(env, native_frames, size, print_out); 524 } 525 526 if (recent) { 527 result = result && 528 frames_exist_recent(env, native_frames, size, print_out); 529 } 530 531 if (frequent) { 532 result = result && 533 frames_exist_frequent(env, native_frames, size, print_out); 534 } 535 536 return result; 537 } 538 539 static jboolean check_or(JNIEnv *env, jobjectArray frames, int live, int recent, 540 int frequent, int print_out) { 541 jobject loader = NULL; 542 543 if (frames == NULL) { 544 return FALSE; 545 } 546 547 // Start by transforming the frames into a C-friendly structure. 548 jsize size = (*env)->GetArrayLength(env, frames); 549 ExpectedContentFrame native_frames[size]; 550 fill_native_frames(env, frames, native_frames, size); 551 552 if (jvmti == NULL) { 553 throw_exc(env, "JVMTI client was not properly loaded!\n"); 554 return FALSE; 555 } 556 557 jboolean result = FALSE; 558 559 if (live) { 560 result = frames_exist_live(env, native_frames, size, print_out); 561 } 562 563 if (recent) { 564 result = result || 565 frames_exist_recent(env, native_frames, size, print_out); 566 } 567 568 if (frequent) { 569 result = result || 570 frames_exist_frequent(env, native_frames, size, print_out); 571 } 572 573 return result; 574 } 575 576 static jboolean checkAll(JNIEnv *env, jobjectArray frames, int print_out) { 577 return check_and(env, frames, 1, 1, 1, print_out); 578 } 579 580 static jboolean checkNone(JNIEnv *env, jobjectArray frames, 581 int print_out) { 582 jobject loader = NULL; 583 584 if (frames == NULL) { 585 return FALSE; 586 } 587 588 // Start by transforming the frames into a C-friendly structure. 589 jsize size = (*env)->GetArrayLength(env, frames); 590 ExpectedContentFrame native_frames[size]; 591 fill_native_frames(env, frames, native_frames, size); 592 593 if (jvmti == NULL) { 594 throw_exc(env, "JVMTI client was not properly loaded!\n"); 595 return FALSE ; 596 } 597 598 if ((!frames_exist_live(env, native_frames, size, print_out)) && 599 (!frames_exist_recent(env, native_frames, size, print_out)) && 600 (!frames_exist_frequent(env, native_frames, size, print_out))) { 601 return TRUE; 602 } 603 return FALSE; 604 } 605 606 JNIEXPORT void JNICALL 607 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate, 608 int max_traces) { 609 check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces), 610 "Start Heap Sampling"); 611 check_error( 612 (*jvmti)->SetEventNotificationMode(jvmti, 613 JVMTI_ENABLE, 614 JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, 615 NULL), 616 "Start sampling events"); 617 } 618 619 JNIEXPORT void JNICALL 620 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) { 621 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling"); 622 623 check_error( 624 (*jvmti)->SetEventNotificationMode(jvmti, 625 JVMTI_DISABLE, 626 JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, 627 NULL), 628 "Start sampling events"); 629 } 630 631 JNIEXPORT jboolean JNICALL 632 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) { 633 jvmtiHeapSamplingStats stats; 634 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 635 "Heap Sampling Statistics"); 636 637 jvmtiHeapSamplingStats zero; 638 memset(&zero, 0, sizeof(zero)); 639 return memcmp(&stats, &zero, sizeof(zero)) == 0; 640 } 641 642 JNIEXPORT jboolean JNICALL 643 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls, 644 jobjectArray frames) { 645 // We want the frames in each part. 646 return checkAll(env, frames, PRINT_OUT); 647 } 648 649 JNIEXPORT jboolean JNICALL 650 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls, 651 jobjectArray frames) { 652 // We want the frames in none of the parts. 653 return checkNone(env, frames, PRINT_OUT); 654 } 655 656 JNIEXPORT jboolean JNICALL 657 Java_MyPackage_HeapMonitor_framesExistSomewhere(JNIEnv *env, jclass cls, 658 jobjectArray frames) { 659 return check_or(env, frames, TRUE, TRUE, TRUE, PRINT_OUT); 660 } 661 662 JNIEXPORT jboolean JNICALL 663 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env, 664 jclass cls, 665 jobjectArray frames) { 666 return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT); 667 } 668 669 JNIEXPORT jboolean JNICALL 670 Java_MyPackage_HeapMonitorRecentTest_framesExistInRecent(JNIEnv *env, 671 jclass cls, 672 jobjectArray frames) { 673 return check_and(env, frames, FALSE, TRUE, FALSE, PRINT_OUT); 674 } 675 676 JNIEXPORT jboolean JNICALL 677 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env, 678 jclass cls, 679 jobjectArray frames) { 680 return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 681 } 682 683 JNIEXPORT jboolean JNICALL 684 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 685 jclass cls) { 686 jvmtiCapabilities caps; 687 memset(&caps, 0, sizeof(caps)); 688 caps.can_sample_heap= 1; 689 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 690 "Add capabilities\n")){ 691 return FALSE; 692 } 693 694 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19, 695 MAX_TRACES), 696 "Start Heap Sampling")) { 697 return FALSE; 698 } 699 700 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti), 701 "Stop Heap Sampling")) { 702 return FALSE; 703 } 704 705 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL), 706 "Get Heap Sampling Stats")) { 707 return FALSE; 708 } 709 710 if (check_capability_error((*jvmti)->GetGarbageObjectAllocTraces(jvmti, NULL, NULL), 711 "Get Garbage ObjectAllocTraces")) { 712 return FALSE; 713 } 714 715 if (check_capability_error((*jvmti)->GetFrequentGarbageObjectAllocTraces(jvmti, NULL, NULL), 716 "Get Frequent Garbage ObjectAllocTraces")) { 717 return FALSE; 718 } 719 720 if (check_capability_error((*jvmti)->GetLiveObjectAllocTraces(jvmti, NULL, NULL), 721 "Get Object Allocated ObjectAllocTraces")) { 722 return FALSE; 723 } 724 725 if (check_capability_error((*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, NULL, NULL), 726 "Get Cached Object Allocated ObjectAllocTraces")) { 727 return FALSE; 728 } 729 return TRUE; 730 } 731 732 JNIEXPORT jboolean JNICALL 733 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env, 734 jclass cls, 735 int expected, 736 int percent_error) { 737 jvmtiHeapSamplingStats stats; 738 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 739 "Heap Sampling Statistics"); 740 741 double diff_ratio = (stats.sample_count - expected); 742 diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio; 743 diff_ratio /= expected; 744 745 if (diff_ratio * 100 >= percent_error) { 746 fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n", 747 stats.sample_count, expected); 748 } 749 return diff_ratio * 100 < percent_error; 750 } 751 752 JNIEXPORT jdouble JNICALL 753 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { 754 jvmtiHeapSamplingStats stats; 755 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 756 "Heap Sampling Statistics"); 757 return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count; 758 } 759 760 static double calculate_average_stack_depth( 761 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*)) { 762 jvmtiAllocTraceInfo* traces = NULL; 763 jint trace_counter; 764 765 jvmtiError error = get_traces(jvmti, &traces, &trace_counter);; 766 767 if (error != JVMTI_ERROR_NONE) { 768 return 0; 769 } 770 771 if (trace_counter == 0) { 772 return 0; 773 } 774 775 int i; 776 double sum = 0; 777 for (i = 0; i < trace_counter; i++) { 778 jvmtiAllocTraceInfo* trace = traces + i; 779 jvmtiStackInfo* stack_info = trace->stack_info; 780 sum += stack_info->frame_count; 781 } 782 783 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) { 784 return 0; 785 } 786 787 return sum / i; 788 } 789 790 JNIEXPORT jdouble JNICALL 791 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env, 792 jclass cls) { 793 double result = 794 calculate_average_stack_depth((*jvmti)->GetLiveObjectAllocTraces); 795 796 if (result != 0) { 797 return result; 798 } 799 800 // It is possible all the live objects got collected, check the garbage traces 801 // in case. 802 return calculate_average_stack_depth((*jvmti)->GetGarbageObjectAllocTraces); 803 } 804 805 typedef struct sThreadsFound { 806 jint* threads; 807 int num_threads; 808 } ThreadsFound; 809 810 static void find_threads_in_traces(jvmtiAllocTraceInfo* traces, 811 jint trace_counter, 812 ThreadsFound* thread_data) { 813 int i; 814 jint* threads = thread_data->threads; 815 int num_threads = thread_data->num_threads; 816 817 // We are looking for at last expected_num_threads different traces. 818 for (i = 0; i < trace_counter; i++) { 819 jvmtiAllocTraceInfo* trace = traces + i; 820 jvmtiStackInfo* stack_info = trace->stack_info; 821 jint thread_id = trace->thread_id; 822 823 // Check it is the right frame: only accept helper top framed traces. 824 if (stack_info->frame_count == 0) { 825 continue; 826 } 827 828 jmethodID methodid = stack_info->frame_buffer[0].method; 829 char *name = NULL, *signature = NULL, *file_name = NULL; 830 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 831 832 if (strcmp(name, "helper")) { 833 continue; 834 } 835 836 // Really not efficient look-up but it's for a test... 837 int found = 0; 838 int j; 839 for (j = 0; j < num_threads; j++) { 840 if (thread_id == threads[j]) { 841 found = 1; 842 break; 843 } 844 } 845 846 if (!found) { 847 threads[num_threads] = thread_id; 848 num_threads++; 849 } 850 } 851 thread_data->num_threads = num_threads; 852 } 853 854 JNIEXPORT jboolean JNICALL 855 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, 856 jintArray threads) { 857 jvmtiAllocTraceInfo* traces; 858 jint trace_counter; 859 860 ThreadsFound thread_data; 861 thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0); 862 thread_data.num_threads = 0; 863 864 // Get live and garbage traces to ensure we capture all the threads that have 865 // been sampled. 866 if ((*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) { 867 return FALSE; 868 } 869 870 find_threads_in_traces(traces, trace_counter, &thread_data); 871 872 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) { 873 return FALSE; 874 } 875 876 if ((*jvmti)->GetGarbageObjectAllocTraces( 877 jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) { 878 return FALSE; 879 } 880 881 find_threads_in_traces(traces, trace_counter, &thread_data); 882 883 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) { 884 return FALSE; 885 } 886 887 (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0); 888 return TRUE; 889 } 890 891 JNIEXPORT void JNICALL 892 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env, 893 jclass cls) { 894 jvmtiAllocTraceInfo* traces; 895 jint trace_counter; 896 897 jvmtiError error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces, 898 &trace_counter); 899 900 if (error != JVMTI_ERROR_NONE) { 901 return; 902 } 903 904 (*jvmti)->Deallocate(jvmti, (unsigned char*) traces); 905 } 906 907 static jboolean compare_traces(jvmtiAllocTraceInfo* traces, 908 int trace_count, 909 jvmtiAllocTraceInfo* other_traces, 910 int other_trace_count, 911 int print_out_comparisons) { 912 if (trace_count != other_trace_count) { 913 fprintf(stderr, "Trace count not the same!\n %d %d", 914 trace_count, other_trace_count); 915 return FALSE; 916 } 917 918 int i; 919 for (i = 0; i < trace_count; i++) { 920 jvmtiAllocTraceInfo* trace = traces + i; 921 jvmtiAllocTraceInfo* other_trace = other_traces + i; 922 923 jvmtiStackInfo* stack_info = trace->stack_info; 924 jvmtiStackInfo* other_stack_info = trace->stack_info; 925 926 if (stack_info->frame_count != other_stack_info->frame_count) { 927 fprintf(stderr, "Frame count not the same!\n"); 928 return FALSE; 929 } 930 931 if (trace->size != other_trace->size) { 932 fprintf(stderr, "Size not the same!\n"); 933 return FALSE; 934 } 935 936 if (trace->thread_id != other_trace->thread_id) { 937 fprintf(stderr, "Thread id not the same!\n"); 938 return FALSE; 939 } 940 941 jvmtiFrameInfo* frames = stack_info->frame_buffer; 942 jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer; 943 if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) { 944 fprintf(stderr, "memcmp not the same!\n"); 945 return FALSE; 946 } 947 } 948 949 return TRUE; 950 } 951 952 JNIEXPORT jboolean JNICALL 953 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env, 954 jclass cls) { 955 // Get cached first, then get live (since live performs a GC). 956 jvmtiAllocTraceInfo* cached_traces; 957 jint cached_trace_counter; 958 jvmtiError error = 959 (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces, 960 &cached_trace_counter); 961 962 if (error != JVMTI_ERROR_NONE) { 963 return FALSE; 964 } 965 966 jvmtiAllocTraceInfo* live_traces; 967 jint live_trace_counter; 968 error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &live_traces, 969 &live_trace_counter); 970 971 if (error != JVMTI_ERROR_NONE) { 972 return FALSE; 973 } 974 975 int result = compare_traces(cached_traces, cached_trace_counter, 976 live_traces, live_trace_counter, 977 PRINT_OUT); 978 979 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) { 980 return FALSE; 981 } 982 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) live_traces) != JVMTI_ERROR_NONE) { 983 return FALSE; 984 } 985 return result; 986 } 987 988 JNIEXPORT jboolean JNICALL 989 Java_MyPackage_HeapMonitorCachedTest_forceGC(JNIEnv *env, jclass cls) { 990 jvmtiError error = (*jvmti)->ForceGarbageCollection(jvmti); 991 992 if (error != JVMTI_ERROR_NONE) { 993 return FALSE; 994 } 995 return TRUE; 996 } 997 998 static long hash(long hash_code, long value) { 999 return hash_code * 31 + value; 1000 } 1001 1002 static long get_hash_code(jvmtiAllocTraceInfo* traces, jint trace_counter) { 1003 int hash_code = 17; 1004 int i, j; 1005 1006 hash_code = hash(hash_code, trace_counter); 1007 for (i = 0; i < trace_counter; i++) { 1008 jvmtiAllocTraceInfo* trace = traces + i; 1009 1010 hash_code = hash(hash_code, trace->size); 1011 hash_code = hash(hash_code, trace->thread_id); 1012 1013 jvmtiStackInfo* stack_info = trace->stack_info; 1014 hash_code = hash(hash_code, stack_info->frame_count); 1015 1016 int frame_count = stack_info->frame_count; 1017 jvmtiFrameInfo* frames = stack_info->frame_buffer; 1018 hash_code = hash(hash_code, frame_count); 1019 for (j = 0; j < frame_count; j++) { 1020 hash_code = hash(hash_code, (long) frames[i].method); 1021 hash_code = hash(hash_code, frames[i].location); 1022 } 1023 } 1024 1025 return TRUE; 1026 } 1027 1028 JNIEXPORT jlong JNICALL 1029 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env, 1030 jclass cls) { 1031 // Get cached first, then get live. 1032 jvmtiAllocTraceInfo* cached_traces; 1033 jint cached_trace_counter; 1034 jvmtiError error = 1035 (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces, 1036 &cached_trace_counter); 1037 1038 if (error != JVMTI_ERROR_NONE) { 1039 return 0; 1040 } 1041 1042 long hash_code = get_hash_code(cached_traces, cached_trace_counter); 1043 1044 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) { 1045 return FALSE; 1046 } 1047 1048 return hash_code; 1049 } 1050 1051 JNIEXPORT jboolean JNICALL 1052 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env, 1053 jclass cls, 1054 jobjectArray frames) { 1055 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 1056 } 1057 1058 JNIEXPORT jboolean JNICALL 1059 Java_MyPackage_HeapMonitorEventNoCapabilityTest_eventSamplingFail(JNIEnv *env, 1060 jclass cls) { 1061 jvmtiCapabilities caps; 1062 memset(&caps, 0, sizeof(caps)); 1063 caps.can_generate_sampled_object_alloc_events = 1; 1064 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 1065 "Add capabilities\n")){ 1066 return FALSE; 1067 } 1068 1069 if (check_capability_error( 1070 (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL), 1071 "Set Tlab Heap Sampling")) { 1072 return FALSE; 1073 } 1074 return TRUE; 1075 } 1076 1077 JNIEXPORT jboolean JNICALL 1078 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) { 1079 return event_storage_get_count(&global_event_storage) == 0; 1080 } 1081 1082 JNIEXPORT jboolean JNICALL 1083 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) { 1084 jsize size = (*env)->GetArrayLength(env, frames); 1085 ExpectedContentFrame native_frames[size]; 1086 fill_native_frames(env, frames, native_frames, size); 1087 return event_storage_contains(env, &global_event_storage, native_frames, size); 1088 } 1089 1090 JNIEXPORT void JNICALL 1091 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) { 1092 return event_storage_reset(&global_event_storage); 1093 } 1094 1095 #ifdef __cplusplus 1096 } 1097 #endif