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