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 <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include "jvmti.h" 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 #ifndef JNI_ENV_ARG 34 35 #ifdef __cplusplus 36 #define JNI_ENV_ARG(x, y) y 37 #define JNI_ENV_PTR(x) x 38 #else 39 #define JNI_ENV_ARG(x,y) x, y 40 #define JNI_ENV_PTR(x) (*x) 41 #endif 42 43 #endif 44 45 #define TRUE 1 46 #define FALSE 0 47 #define PRINT_OUT 1 48 #define MAX_TRACES 400 49 50 static const char *EXC_CNAME = "java/lang/Exception"; 51 static jvmtiEnv *jvmti = NULL; 52 53 static int check_error(jvmtiError err, const char *s) { 54 if (err != JVMTI_ERROR_NONE) { 55 printf(" ## %s error: %d\n", s, err); 56 return 1; 57 } 58 return 0; 59 } 60 61 static int check_capability_error(jvmtiError err, const char *s) { 62 if (err != JVMTI_ERROR_NONE) { 63 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) { 64 return 0; 65 } 66 printf(" ## %s error: %d\n", s, err); 67 return 1; 68 } 69 return 1; 70 } 71 72 static 73 jint throw_exc(JNIEnv *env, char *msg) { 74 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 75 76 if (exc_class == NULL) { 77 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 78 return -1; 79 } 80 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 81 } 82 83 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 84 85 JNIEXPORT 86 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 87 return Agent_Initialize(jvm, options, reserved); 88 } 89 90 JNIEXPORT 91 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 92 return Agent_Initialize(jvm, options, reserved); 93 } 94 95 JNIEXPORT 96 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 97 return JNI_VERSION_1_8; 98 } 99 100 static 101 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 102 jint res; 103 104 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 105 JVMTI_VERSION_9); 106 if (res != JNI_OK || jvmti == NULL) { 107 printf(" Error: wrong result of a valid call to GetEnv!\n"); 108 return JNI_ERR; 109 } 110 111 jvmtiEventCallbacks callbacks; 112 memset(&callbacks, 0, sizeof(callbacks)); 113 114 jvmtiCapabilities caps; 115 memset(&caps, 0, sizeof(caps)); 116 // Get line numbers, sample heap, and filename for the test. 117 caps.can_get_line_numbers = 1; 118 caps.can_sample_heap = 1; 119 caps.can_get_source_file_name = 1; 120 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), 121 "Add capabilities\n")){ 122 return JNI_ERR; 123 } 124 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks, 125 sizeof(jvmtiEventCallbacks)), 126 " Set Event Callbacks")) { 127 return JNI_ERR; 128 } 129 return JNI_OK; 130 } 131 132 // Given a method and a location, this method gets the line number. 133 static 134 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, 135 jlocation location) { 136 // Read the line number table. 137 jvmtiLineNumberEntry *table_ptr = 0; 138 jint line_number_table_entries; 139 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method, 140 &line_number_table_entries, 141 &table_ptr); 142 143 if (JVMTI_ERROR_NONE != jvmti_error) { 144 return -1; 145 } 146 if (line_number_table_entries <= 0) { 147 return -1; 148 } 149 if (line_number_table_entries == 1) { 150 return table_ptr[0].line_number; 151 } 152 153 // Go through all the line numbers... 154 jint last_location = table_ptr[0].start_location; 155 int l; 156 for (l = 1; l < line_number_table_entries; l++) { 157 // ... and if you see one that is in the right place for your 158 // location, you've found the line number! 159 if ((location < table_ptr[l].start_location) && 160 (location >= last_location)) { 161 return table_ptr[l - 1].line_number; 162 } 163 last_location = table_ptr[l].start_location; 164 } 165 166 if (location >= last_location) { 167 return table_ptr[line_number_table_entries - 1].line_number; 168 } else { 169 return -1; 170 } 171 } 172 173 typedef struct _ExpectedContentFrame { 174 const char *name; 175 const char *signature; 176 const char *file_name; 177 int line_number; 178 } ExpectedContentFrame; 179 180 static jboolean check_sample_content(JNIEnv *env, 181 jvmtiStackTrace *trace, 182 ExpectedContentFrame *expected, 183 int expected_count, 184 int print_out_comparisons) { 185 int i; 186 187 if (expected_count > trace->frame_count) { 188 return FALSE; 189 } 190 191 for (i = 0; i < expected_count; i++) { 192 // Get basic information out of the trace. 193 int bci = trace->frames[i].location; 194 jmethodID methodid = trace->frames[i].method; 195 char *name = NULL, *signature = NULL, *file_name = NULL; 196 197 if (bci < 0) { 198 return FALSE; 199 } 200 201 // Transform into usable information. 202 int line_number = get_line_number(jvmti, methodid, bci); 203 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 204 205 jclass declaring_class; 206 if (JVMTI_ERROR_NONE != 207 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) { 208 return FALSE; 209 } 210 211 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class, 212 &file_name); 213 if (err != JVMTI_ERROR_NONE) { 214 return FALSE; 215 } 216 217 // Compare now, none should be NULL. 218 if (name == NULL) { 219 return FALSE; 220 } 221 222 if (file_name == NULL) { 223 return FALSE; 224 } 225 226 if (signature == NULL) { 227 return FALSE; 228 } 229 230 if (print_out_comparisons) { 231 fprintf(stderr, "Comparing:\n"); 232 fprintf(stderr, "\tNames: %s and %s\n", name, expected[i].name); 233 fprintf(stderr, "\tSignatures: %s and %s\n", signature, expected[i].signature); 234 fprintf(stderr, "\tFile name: %s and %s\n", file_name, expected[i].file_name); 235 fprintf(stderr, "\tLines: %d and %d\n", line_number, expected[i].line_number); 236 fprintf(stderr, "\tResult is %d\n", 237 (strcmp(name, expected[i].name) || 238 strcmp(signature, expected[i].signature) || 239 strcmp(file_name, expected[i].file_name) || 240 line_number != expected[i].line_number)); 241 } 242 243 if (strcmp(name, expected[i].name) || 244 strcmp(signature, expected[i].signature) || 245 strcmp(file_name, expected[i].file_name) || 246 line_number != expected[i].line_number) { 247 return FALSE; 248 } 249 } 250 251 return TRUE; 252 } 253 254 static jboolean compare_samples(JNIEnv* env, jvmtiStackTrace* traces, 255 int trace_count, 256 ExpectedContentFrame* expected_content, 257 size_t size, 258 int print_out_comparisons) { 259 // We expect the code to record correctly the bci, retrieve the line 260 // number, have the right method and the class name of the first frames. 261 int i; 262 for (i = 0; i < trace_count; i++) { 263 jvmtiStackTrace *trace = traces + i; 264 if (check_sample_content(env, trace, expected_content, size, 265 print_out_comparisons)) { 266 // At least one frame matched what we were looking for. 267 return TRUE; 268 } 269 } 270 271 return FALSE; 272 } 273 274 static jboolean 275 check_samples(JNIEnv* env, 276 ExpectedContentFrame* expected, 277 size_t size, 278 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*), 279 int print_out_comparisons) { 280 jvmtiStackTraces traces; 281 jvmtiError error = get_traces(jvmti, &traces); 282 283 if (error != JVMTI_ERROR_NONE) { 284 return FALSE; 285 } 286 287 int result = compare_samples(env, traces.stack_traces, traces.trace_count, 288 expected, size, print_out_comparisons); 289 (*jvmti)->ReleaseTraces(jvmti, &traces); 290 return result; 291 } 292 293 static jboolean frames_exist_live(JNIEnv* env, 294 ExpectedContentFrame* expected, 295 size_t size, 296 int print_out_comparisons) { 297 return check_samples(env, expected, size, (*jvmti)->GetLiveTraces, 298 print_out_comparisons); 299 } 300 301 static jboolean frames_exist_recent(JNIEnv* env, 302 ExpectedContentFrame* expected, 303 size_t size, 304 int print_out_comparisons) { 305 return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces, 306 print_out_comparisons); 307 } 308 309 static jboolean frames_exist_frequent(JNIEnv* env, 310 ExpectedContentFrame* expected, 311 size_t size, 312 int print_out_comparisons) { 313 return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces, 314 print_out_comparisons); 315 } 316 317 // Static native API for various tests. 318 static void fill_native_frames(JNIEnv* env, jobjectArray frames, 319 ExpectedContentFrame* native_frames, size_t size) { 320 size_t i; 321 for(i = 0; i < size; i++) { 322 jobject obj = (*env)->GetObjectArrayElement(env, frames, i); 323 jclass frame_class = (*env)->GetObjectClass(env, obj); 324 jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, 325 "lineNumber", "I"); 326 int line_number = (*env)->GetIntField(env, obj, line_number_field_id); 327 328 jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", 329 "Ljava/lang/String;"); 330 jstring string_object = (jstring) (*env)->GetObjectField(env, obj, 331 string_id); 332 const char* method = (*env)->GetStringUTFChars(env, string_object, 0); 333 334 string_id = (*env)->GetFieldID(env, frame_class, "fileName", 335 "Ljava/lang/String;"); 336 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 337 const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0); 338 339 string_id = (*env)->GetFieldID(env, frame_class, "signature", 340 "Ljava/lang/String;"); 341 string_object = (jstring) (*env)->GetObjectField(env, obj, string_id); 342 const char* signature= (*env)->GetStringUTFChars(env, string_object, 0); 343 344 native_frames[i].name = method; 345 native_frames[i].file_name = file_name; 346 native_frames[i].signature = signature; 347 native_frames[i].line_number = line_number; 348 } 349 } 350 351 static jboolean check_and(JNIEnv *env, jobjectArray frames, int live, 352 int recent, int frequent, int print_out) { 353 jobject loader = NULL; 354 355 if (frames == NULL) { 356 return FALSE; 357 } 358 359 // Start by transforming the frames into a C-friendly structure. 360 jsize size = (*env)->GetArrayLength(env, frames); 361 ExpectedContentFrame native_frames[size]; 362 fill_native_frames(env, frames, native_frames, size); 363 364 if (jvmti == NULL) { 365 throw_exc(env, "JVMTI client was not properly loaded!\n"); 366 return FALSE; 367 } 368 369 int result = TRUE; 370 371 if (live) { 372 result = frames_exist_live(env, native_frames, size, print_out); 373 } 374 375 if (recent) { 376 result = result && 377 frames_exist_recent(env, native_frames, size, print_out); 378 } 379 380 if (frequent) { 381 result = result && 382 frames_exist_frequent(env, native_frames, size, print_out); 383 } 384 385 return result; 386 } 387 388 static jboolean check_or(JNIEnv *env, jobjectArray frames, int live, int recent, 389 int frequent, int print_out) { 390 jobject loader = NULL; 391 392 if (frames == NULL) { 393 return FALSE; 394 } 395 396 // Start by transforming the frames into a C-friendly structure. 397 jsize size = (*env)->GetArrayLength(env, frames); 398 ExpectedContentFrame native_frames[size]; 399 fill_native_frames(env, frames, native_frames, size); 400 401 if (jvmti == NULL) { 402 throw_exc(env, "JVMTI client was not properly loaded!\n"); 403 return FALSE; 404 } 405 406 jboolean result = FALSE; 407 408 if (live) { 409 result = frames_exist_live(env, native_frames, size, print_out); 410 } 411 412 if (recent) { 413 result = result || 414 frames_exist_recent(env, native_frames, size, print_out); 415 } 416 417 if (frequent) { 418 result = result || 419 frames_exist_frequent(env, native_frames, size, print_out); 420 } 421 422 return result; 423 } 424 425 static jboolean checkAll(JNIEnv *env, jobjectArray frames, int print_out) { 426 return check_and(env, frames, 1, 1, 1, print_out); 427 } 428 429 static jboolean checkNone(JNIEnv *env, jobjectArray frames, 430 int print_out) { 431 jobject loader = NULL; 432 433 if (frames == NULL) { 434 return FALSE; 435 } 436 437 // Start by transforming the frames into a C-friendly structure. 438 jsize size = (*env)->GetArrayLength(env, frames); 439 ExpectedContentFrame native_frames[size]; 440 fill_native_frames(env, frames, native_frames, size); 441 442 if (jvmti == NULL) { 443 throw_exc(env, "JVMTI client was not properly loaded!\n"); 444 return FALSE ; 445 } 446 447 if ((!frames_exist_live(env, native_frames, size, print_out)) && 448 (!frames_exist_recent(env, native_frames, size, print_out)) && 449 (!frames_exist_frequent(env, native_frames, size, print_out))) { 450 return TRUE; 451 } 452 return FALSE; 453 } 454 455 JNIEXPORT void JNICALL 456 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate, 457 int max_traces) { 458 check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces), 459 "Start Heap Sampling"); 460 } 461 462 JNIEXPORT void JNICALL 463 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) { 464 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling"); 465 } 466 467 JNIEXPORT jboolean JNICALL 468 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) { 469 jvmtiHeapSamplingStats stats; 470 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 471 "Heap Sampling Statistics"); 472 473 jvmtiHeapSamplingStats zero; 474 memset(&zero, 0, sizeof(zero)); 475 return memcmp(&stats, &zero, sizeof(zero)) == 0; 476 } 477 478 JNIEXPORT jboolean JNICALL 479 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls, 480 jobjectArray frames) { 481 // We want the frames in each part. 482 return checkAll(env, frames, PRINT_OUT); 483 } 484 485 JNIEXPORT jboolean JNICALL 486 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls, 487 jobjectArray frames) { 488 // We want the frames in none of the parts. 489 return checkNone(env, frames, PRINT_OUT); 490 } 491 492 JNIEXPORT jboolean JNICALL 493 Java_MyPackage_HeapMonitor_framesExistSomewhere(JNIEnv *env, jclass cls, 494 jobjectArray frames) { 495 return check_or(env, frames, TRUE, TRUE, TRUE, PRINT_OUT); 496 } 497 498 JNIEXPORT jboolean JNICALL 499 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env, 500 jclass cls, 501 jobjectArray frames) { 502 return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT); 503 } 504 505 JNIEXPORT jboolean JNICALL 506 Java_MyPackage_HeapMonitorRecentTest_framesExistInRecent(JNIEnv *env, 507 jclass cls, 508 jobjectArray frames) { 509 return check_and(env, frames, FALSE, TRUE, FALSE, PRINT_OUT); 510 } 511 512 JNIEXPORT jboolean JNICALL 513 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env, 514 jclass cls, 515 jobjectArray frames) { 516 return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 517 } 518 519 JNIEXPORT jboolean JNICALL 520 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 521 jclass cls) { 522 jvmtiCapabilities caps; 523 memset(&caps, 0, sizeof(caps)); 524 caps.can_sample_heap= 1; 525 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 526 "Add capabilities\n")){ 527 return FALSE; 528 } 529 530 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19, 531 MAX_TRACES), 532 "Start Heap Sampling")) { 533 return FALSE; 534 } 535 536 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti), 537 "Stop Heap Sampling")) { 538 return FALSE; 539 } 540 541 if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL), 542 "Release Traces")) { 543 return FALSE; 544 } 545 546 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL), 547 "Get Heap Sampling Stats")) { 548 return FALSE; 549 } 550 551 if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL), 552 "Get Garbage Traces")) { 553 return FALSE; 554 } 555 556 if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL), 557 "Get Frequent Garbage Traces")) { 558 return FALSE; 559 } 560 561 if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL), 562 "Get Live Traces")) { 563 return FALSE; 564 } 565 return TRUE; 566 } 567 568 JNIEXPORT jboolean JNICALL 569 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env, 570 jclass cls, 571 int expected, 572 int percent_error) { 573 jvmtiHeapSamplingStats stats; 574 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 575 "Heap Sampling Statistics"); 576 577 double diff_ratio = (stats.sample_count - expected); 578 diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio; 579 diff_ratio /= expected; 580 581 if (diff_ratio * 100 >= percent_error) { 582 fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n", 583 stats.sample_count, expected); 584 } 585 return diff_ratio * 100 < percent_error; 586 } 587 588 JNIEXPORT jdouble JNICALL 589 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { 590 jvmtiHeapSamplingStats stats; 591 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 592 "Heap Sampling Statistics"); 593 return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count; 594 } 595 596 static double calculate_average_stack_depth( 597 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) { 598 jvmtiStackTraces traces; 599 600 jvmtiError error = get_traces(jvmti, &traces);; 601 602 if (error != JVMTI_ERROR_NONE) { 603 return 0; 604 } 605 606 int trace_count = traces.trace_count; 607 608 if (trace_count == 0) { 609 return 0; 610 } 611 612 int i; 613 jvmtiStackTrace* stack_traces = traces.stack_traces; 614 double sum = 0; 615 for (i = 0; i < trace_count; i++) { 616 jvmtiStackTrace *stack_trace = stack_traces + i; 617 sum += stack_trace->frame_count; 618 } 619 620 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 621 return 0; 622 } 623 624 return sum / i; 625 } 626 627 JNIEXPORT jdouble JNICALL 628 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env, 629 jclass cls) { 630 double result = calculate_average_stack_depth((*jvmti)->GetLiveTraces); 631 632 if (result != 0) { 633 return result; 634 } 635 636 // It is possible all the live objects got collected, check the garbage traces 637 // in case. 638 return calculate_average_stack_depth((*jvmti)->GetGarbageTraces); 639 } 640 641 typedef struct sThreadsFound { 642 jint *threads; 643 int num_threads; 644 } ThreadsFound; 645 646 static void find_threads_in_traces(jvmtiStackTraces* traces, 647 ThreadsFound* thread_data) { 648 int i; 649 jvmtiStackTrace* stack_traces = traces->stack_traces; 650 int trace_count = traces->trace_count; 651 652 jint *threads = thread_data->threads; 653 int num_threads = thread_data->num_threads; 654 655 // We are looking for at last expected_num_threads different traces. 656 for (i = 0; i < trace_count; i++) { 657 jvmtiStackTrace *stack_trace = stack_traces + i; 658 jlong thread_id = stack_trace->thread_id; 659 660 // Check it is the right frame: only accept helper top framed traces. 661 jmethodID methodid = stack_trace->frames[0].method; 662 char *name = NULL, *signature = NULL, *file_name = NULL; 663 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 664 665 if (strcmp(name, "helper")) { 666 continue; 667 } 668 669 // Really not efficient look-up but it's for a test... 670 int found = 0; 671 int j; 672 for (j = 0; j < num_threads; j++) { 673 if (thread_id == threads[j]) { 674 found = 1; 675 break; 676 } 677 } 678 679 if (!found) { 680 threads[num_threads] = thread_id; 681 num_threads++; 682 } 683 } 684 thread_data->num_threads = num_threads; 685 } 686 687 JNIEXPORT jboolean JNICALL 688 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, 689 jintArray threads) { 690 jvmtiStackTraces traces; 691 ThreadsFound thread_data; 692 thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0); 693 thread_data.num_threads = 0; 694 695 // Get live and garbage traces to ensure we capture all the threads that have 696 // been sampled. 697 if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 698 return FALSE; 699 } 700 701 find_threads_in_traces(&traces, &thread_data); 702 703 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 704 return FALSE; 705 } 706 707 if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 708 return FALSE; 709 } 710 711 find_threads_in_traces(&traces, &thread_data); 712 713 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 714 return FALSE; 715 } 716 717 (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0); 718 return TRUE; 719 } 720 721 JNIEXPORT void JNICALL 722 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env, 723 jclass cls) { 724 jvmtiStackTraces live_traces; 725 jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &live_traces); 726 727 if (error != JVMTI_ERROR_NONE) { 728 return; 729 } 730 731 (*jvmti)->ReleaseTraces(jvmti, &live_traces); 732 } 733 734 static jboolean compare_traces(jvmtiStackTraces* traces, 735 jvmtiStackTraces* other_traces, 736 int print_out_comparisons) { 737 int trace_count = traces->trace_count; 738 if (trace_count != other_traces->trace_count) { 739 return FALSE; 740 } 741 742 int i; 743 for (i = 0; i < trace_count; i++) { 744 jvmtiStackTrace* trace = traces->stack_traces + i; 745 jvmtiStackTrace* other_trace = other_traces->stack_traces + i; 746 747 if (trace->frame_count != other_trace->frame_count) { 748 return FALSE; 749 } 750 751 if (trace->size != other_trace->size) { 752 return FALSE; 753 } 754 755 if (trace->thread_id != other_trace->thread_id) { 756 return FALSE; 757 } 758 759 jvmtiFrameInfo* frames = trace->frames; 760 jvmtiFrameInfo* other_frames = other_trace->frames; 761 if (memcmp(frames, other_frames, sizeof(*frames) * trace->frame_count)) { 762 return FALSE; 763 } 764 } 765 766 return TRUE; 767 } 768 769 JNIEXPORT jboolean JNICALL 770 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env, 771 jclass cls) { 772 // Get cached first, then get live (since live performs a GC). 773 jvmtiStackTraces cached_traces; 774 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces); 775 776 if (error != JVMTI_ERROR_NONE) { 777 return FALSE; 778 } 779 780 jvmtiStackTraces live_traces; 781 error = (*jvmti)->GetLiveTraces(jvmti, &live_traces); 782 783 if (error != JVMTI_ERROR_NONE) { 784 return FALSE; 785 } 786 787 int result = compare_traces(&cached_traces, &live_traces, PRINT_OUT); 788 789 (*jvmti)->ReleaseTraces(jvmti, &cached_traces); 790 (*jvmti)->ReleaseTraces(jvmti, &live_traces); 791 return result; 792 } 793 794 static long hash(long hash_code, long value) { 795 return hash_code * 31 + value; 796 } 797 798 static long get_hash_code(jvmtiStackTraces* traces) { 799 int trace_count = traces->trace_count; 800 int hash_code = 17; 801 802 int i; 803 hash_code = hash(hash_code, trace_count); 804 for (i = 0; i < trace_count; i++) { 805 jvmtiStackTrace* trace = traces->stack_traces + i; 806 hash_code = hash(hash_code, trace->frame_count); 807 hash_code = hash(hash_code, trace->size); 808 hash_code = hash(hash_code, trace->thread_id); 809 810 int j; 811 int frame_count = trace->frame_count; 812 jvmtiFrameInfo* frames = trace->frames; 813 hash_code = hash(hash_code, frame_count); 814 for (j = 0; j < frame_count; j++) { 815 hash_code = hash(hash_code, (long) frames[i].method); 816 hash_code = hash(hash_code, frames[i].location); 817 } 818 } 819 820 return TRUE; 821 } 822 823 JNIEXPORT jlong JNICALL 824 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env, 825 jclass cls) { 826 // Get cached first, then get live. 827 jvmtiStackTraces cached_traces; 828 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces); 829 830 if (error != JVMTI_ERROR_NONE) { 831 return 0; 832 } 833 834 long hash_code = get_hash_code(&cached_traces); 835 (*jvmti)->ReleaseTraces(jvmti, &cached_traces); 836 837 return hash_code; 838 } 839 840 JNIEXPORT jboolean JNICALL 841 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env, 842 jclass cls, 843 jobjectArray frames) { 844 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 845 } 846 847 #ifdef __cplusplus 848 } 849 #endif