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 fprintf(stderr, "Checking all!!!\n"); 427 return check_and(env, frames, 1, 1, 1, print_out); 428 } 429 430 static jboolean checkNone(JNIEnv *env, jobjectArray frames, 431 int print_out) { 432 fprintf(stderr, "Checking none!!!\n"); 433 jobject loader = NULL; 434 435 if (frames == NULL) { 436 return FALSE; 437 } 438 439 // Start by transforming the frames into a C-friendly structure. 440 jsize size = (*env)->GetArrayLength(env, frames); 441 ExpectedContentFrame native_frames[size]; 442 fill_native_frames(env, frames, native_frames, size); 443 444 if (jvmti == NULL) { 445 throw_exc(env, "JVMTI client was not properly loaded!\n"); 446 return FALSE ; 447 } 448 449 if ((!frames_exist_live(env, native_frames, size, print_out)) && 450 (!frames_exist_recent(env, native_frames, size, print_out)) && 451 (!frames_exist_frequent(env, native_frames, size, print_out))) { 452 return TRUE; 453 } 454 return FALSE; 455 } 456 457 JNIEXPORT void JNICALL 458 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate, 459 int max_traces) { 460 check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces), 461 "Start Heap Sampling"); 462 } 463 464 JNIEXPORT void JNICALL 465 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) { 466 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling"); 467 } 468 469 JNIEXPORT jboolean JNICALL 470 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) { 471 jvmtiHeapSamplingStats stats; 472 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 473 "Heap Sampling Statistics"); 474 475 jvmtiHeapSamplingStats zero; 476 memset(&zero, 0, sizeof(zero)); 477 return memcmp(&stats, &zero, sizeof(zero)) == 0; 478 } 479 480 JNIEXPORT jboolean JNICALL 481 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls, 482 jobjectArray frames) { 483 // We want the frames in each part. 484 return checkAll(env, frames, PRINT_OUT); 485 } 486 487 JNIEXPORT jboolean JNICALL 488 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls, 489 jobjectArray frames) { 490 // We want the frames in none of the parts. 491 return checkNone(env, frames, PRINT_OUT); 492 } 493 494 JNIEXPORT jboolean JNICALL 495 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env, 496 jclass cls, 497 jobjectArray frames) { 498 return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT); 499 } 500 501 JNIEXPORT jboolean JNICALL 502 Java_MyPackage_HeapMonitorRecentTest_framesExistInLiveAndRecent(JNIEnv *env, 503 jclass cls, 504 jobjectArray frames) { 505 return check_and(env, frames, TRUE, TRUE, FALSE, PRINT_OUT); 506 } 507 508 JNIEXPORT jboolean JNICALL 509 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env, 510 jclass cls, 511 jobjectArray frames) { 512 return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 513 } 514 515 JNIEXPORT jboolean JNICALL 516 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, 517 jclass cls) { 518 jvmtiCapabilities caps; 519 memset(&caps, 0, sizeof(caps)); 520 caps.can_sample_heap= 1; 521 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps), 522 "Add capabilities\n")){ 523 return FALSE; 524 } 525 526 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19, 527 MAX_TRACES), 528 "Start Heap Sampling")) { 529 return FALSE; 530 } 531 532 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti), 533 "Stop Heap Sampling")) { 534 return FALSE; 535 } 536 537 if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL), 538 "Release Traces")) { 539 return FALSE; 540 } 541 542 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL), 543 "Get Heap Sampling Stats")) { 544 return FALSE; 545 } 546 547 if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL), 548 "Get Garbage Traces")) { 549 return FALSE; 550 } 551 552 if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL), 553 "Get Frequent Garbage Traces")) { 554 return FALSE; 555 } 556 557 if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL), 558 "Get Live Traces")) { 559 return FALSE; 560 } 561 return TRUE; 562 } 563 564 JNIEXPORT jboolean JNICALL 565 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env, 566 jclass cls, 567 int expected, 568 int percent_error) { 569 jvmtiHeapSamplingStats stats; 570 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 571 "Heap Sampling Statistics"); 572 573 fprintf(stderr, "Sample data count %ld, rate %ld, rate count %ld\n", 574 stats.sample_count, stats.sample_rate_accumulation, stats.sample_rate_count); 575 double diff_ratio = (stats.sample_count - expected); 576 diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio; 577 diff_ratio /= expected; 578 579 return diff_ratio * 100 < percent_error; 580 } 581 582 JNIEXPORT jdouble JNICALL 583 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) { 584 jvmtiHeapSamplingStats stats; 585 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats), 586 "Heap Sampling Statistics"); 587 return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count; 588 } 589 590 JNIEXPORT jdouble JNICALL 591 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env, 592 jclass cls) { 593 jvmtiStackTraces traces; 594 jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &traces);; 595 596 if (error != JVMTI_ERROR_NONE) { 597 return 0; 598 } 599 600 int trace_count = traces.trace_count; 601 602 if (trace_count == 0) { 603 return 0; 604 } 605 606 int i; 607 jvmtiStackTrace* stack_traces = traces.stack_traces; 608 double sum = 0; 609 for (i = 0; i < trace_count; i++) { 610 jvmtiStackTrace *stack_trace = stack_traces + i; 611 sum += stack_trace->frame_count; 612 } 613 614 return sum / i; 615 } 616 617 typedef struct sThreadsFound { 618 jint *threads; 619 int num_threads; 620 } ThreadsFound; 621 622 static void find_threads_in_traces(jvmtiStackTraces* traces, 623 ThreadsFound* thread_data) { 624 int i; 625 jvmtiStackTrace* stack_traces = traces->stack_traces; 626 int trace_count = traces->trace_count; 627 628 jint *threads = thread_data->threads; 629 int num_threads = thread_data->num_threads; 630 631 // We are looking for at last expected_num_threads different traces. 632 for (i = 0; i < trace_count; i++) { 633 jvmtiStackTrace *stack_trace = stack_traces + i; 634 jlong thread_id = stack_trace->thread_id; 635 636 // Check it is the right frame: only accept helper top framed traces. 637 jmethodID methodid = stack_trace->frames[0].method; 638 char *name = NULL, *signature = NULL, *file_name = NULL; 639 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0); 640 641 if (strcmp(name, "helper")) { 642 continue; 643 } 644 645 // Really not efficient look-up but it's for a test... 646 int found = 0; 647 int j; 648 for (j = 0; j < num_threads; j++) { 649 if (thread_id == threads[j]) { 650 found = 1; 651 break; 652 } 653 } 654 655 if (!found) { 656 threads[num_threads] = thread_id; 657 num_threads++; 658 } 659 } 660 thread_data->num_threads = num_threads; 661 } 662 663 JNIEXPORT jboolean JNICALL 664 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, 665 jintArray threads) { 666 jvmtiStackTraces traces; 667 ThreadsFound thread_data; 668 thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0); 669 thread_data.num_threads = 0; 670 671 // Get live and garbage traces to ensure we capture all the threads that have 672 // been sampled. 673 if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 674 return FALSE; 675 } 676 677 find_threads_in_traces(&traces, &thread_data); 678 679 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 680 return FALSE; 681 } 682 683 if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 684 return FALSE; 685 } 686 687 find_threads_in_traces(&traces, &thread_data); 688 689 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) { 690 return FALSE; 691 } 692 693 (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0); 694 return TRUE; 695 } 696 697 JNIEXPORT void JNICALL 698 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env, 699 jclass cls) { 700 jvmtiStackTraces live_traces; 701 jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &live_traces); 702 703 if (error != JVMTI_ERROR_NONE) { 704 return; 705 } 706 707 (*jvmti)->ReleaseTraces(jvmti, &live_traces); 708 } 709 710 static jboolean compare_traces(jvmtiStackTraces* traces, 711 jvmtiStackTraces* other_traces, 712 int print_out_comparisons) { 713 int trace_count = traces->trace_count; 714 if (trace_count != other_traces->trace_count) { 715 return FALSE; 716 } 717 718 int i; 719 for (i = 0; i < trace_count; i++) { 720 jvmtiStackTrace* trace = traces->stack_traces + i; 721 jvmtiStackTrace* other_trace = other_traces->stack_traces + i; 722 723 if (trace->frame_count != other_trace->frame_count) { 724 return FALSE; 725 } 726 727 if (trace->size != other_trace->size) { 728 return FALSE; 729 } 730 731 if (trace->thread_id != other_trace->thread_id) { 732 return FALSE; 733 } 734 735 jvmtiFrameInfo* frames = trace->frames; 736 jvmtiFrameInfo* other_frames = other_trace->frames; 737 if (memcmp(frames, other_frames, sizeof(*frames) * trace->frame_count)) { 738 return FALSE; 739 } 740 } 741 742 return TRUE; 743 } 744 745 JNIEXPORT jboolean JNICALL 746 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env, 747 jclass cls) { 748 // Get cached first, then get live (since live performs a GC). 749 jvmtiStackTraces cached_traces; 750 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces); 751 752 if (error != JVMTI_ERROR_NONE) { 753 return FALSE; 754 } 755 756 jvmtiStackTraces live_traces; 757 error = (*jvmti)->GetLiveTraces(jvmti, &live_traces); 758 759 if (error != JVMTI_ERROR_NONE) { 760 return FALSE; 761 } 762 763 int result = compare_traces(&cached_traces, &live_traces, PRINT_OUT); 764 765 (*jvmti)->ReleaseTraces(jvmti, &cached_traces); 766 (*jvmti)->ReleaseTraces(jvmti, &live_traces); 767 return result; 768 } 769 770 static long hash(long hash_code, long value) { 771 return hash_code * 31 + value; 772 } 773 774 static long get_hash_code(jvmtiStackTraces* traces) { 775 int trace_count = traces->trace_count; 776 int hash_code = 17; 777 778 int i; 779 hash_code = hash(hash_code, trace_count); 780 for (i = 0; i < trace_count; i++) { 781 jvmtiStackTrace* trace = traces->stack_traces + i; 782 hash_code = hash(hash_code, trace->frame_count); 783 hash_code = hash(hash_code, trace->size); 784 hash_code = hash(hash_code, trace->thread_id); 785 786 int j; 787 int frame_count = trace->frame_count; 788 jvmtiFrameInfo* frames = trace->frames; 789 hash_code = hash(hash_code, frame_count); 790 for (j = 0; j < frame_count; j++) { 791 hash_code = hash(hash_code, (long) frames[i].method); 792 hash_code = hash(hash_code, frames[i].location); 793 } 794 } 795 796 return TRUE; 797 } 798 799 JNIEXPORT jlong JNICALL 800 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env, 801 jclass cls) { 802 // Get cached first, then get live. 803 jvmtiStackTraces cached_traces; 804 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces); 805 806 if (error != JVMTI_ERROR_NONE) { 807 return 0; 808 } 809 810 long hash_code = get_hash_code(&cached_traces); 811 (*jvmti)->ReleaseTraces(jvmti, &cached_traces); 812 813 return hash_code; 814 } 815 816 JNIEXPORT jboolean JNICALL 817 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env, 818 jclass cls, 819 jobjectArray frames) { 820 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT); 821 } 822 823 #ifdef __cplusplus 824 } 825 #endif