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 PASSED 0
  46 #define FAILED 2
  47 
  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 JNIEXPORT void JNICALL OnVMInit(jvmtiEnv *jvmti, JNIEnv *jni_env, jthread thread) {
 101 }
 102 
 103 JNIEXPORT void JNICALL OnClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
 104                                               jthread thread, jclass klass) {
 105   // NOP.
 106 }
 107 
 108 JNIEXPORT void JNICALL OnClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
 109                                       jthread thread, jclass klass) {
 110   // We need to do this to "prime the pump", as it were -- make sure
 111   // that all of the methodIDs have been initialized internally, for
 112   // AsyncGetCallTrace.
 113   jint method_count;
 114   jmethodID *methods = 0;
 115   jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
 116   if ((err != JVMTI_ERROR_NONE) && (err != JVMTI_ERROR_CLASS_NOT_PREPARED)) {
 117     // JVMTI_ERROR_CLASS_NOT_PREPARED is okay because some classes may
 118     // be loaded but not prepared at this point.
 119     throw_exc(jni_env, "Failed to create method IDs for methods in class\n");
 120   }
 121 }
 122 
 123 static
 124 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 125   jint res;
 126 
 127   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 128                                  JVMTI_VERSION_9);
 129   if (res != JNI_OK || jvmti == NULL) {
 130     printf("    Error: wrong result of a valid call to GetEnv!\n");
 131     return JNI_ERR;
 132   }
 133 
 134   jvmtiEventCallbacks callbacks;
 135   memset(&callbacks, 0, sizeof(callbacks));
 136 
 137   callbacks.VMInit = &OnVMInit;
 138   callbacks.ClassLoad = &OnClassLoad;
 139   callbacks.ClassPrepare = &OnClassPrepare;
 140 
 141   jvmtiCapabilities caps;
 142   memset(&caps, 0, sizeof(caps));
 143   // Get line numbers, sample heap, and filename for the test.
 144   caps.can_get_line_numbers = 1;
 145   caps.can_sample_heap = 1;
 146   caps.can_get_source_file_name = 1;
 147   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
 148                   "Add capabilities\n")){
 149     return JNI_ERR;
 150   }
 151 
 152   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 153                                               sizeof(jvmtiEventCallbacks)),
 154                   " Set Event Callbacks")) {
 155     return JNI_ERR;
 156   }
 157   if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 158                                                      JVMTI_EVENT_VM_INIT, NULL),
 159                   "Set Event for VM Init")) {
 160     return JNI_ERR;
 161   }
 162   if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 163                                                      JVMTI_EVENT_CLASS_LOAD, NULL),
 164                   "Set Event for Class Load")) {
 165     return JNI_ERR;
 166   }
 167   if (check_error( (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 168                                                       JVMTI_EVENT_CLASS_PREPARE, NULL),
 169                   "Set Event for Class Prepare")) {
 170     return JNI_ERR;
 171   }
 172 
 173   return JNI_OK;
 174 }
 175 
 176 // Given a method and a location, this method gets the line number.
 177 // Kind of expensive, comparatively.
 178 static
 179 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, jlocation location) {
 180   // The location is -1 if the bci isn't known or -3 for a native method.
 181   if (location == -1 || location == -3) {
 182     return -1;
 183   }
 184 
 185   // Read the line number table.
 186   jvmtiLineNumberEntry *table_ptr = 0;
 187   jint line_number_table_entries;
 188   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
 189                                                  &line_number_table_entries,
 190                                                  &table_ptr);
 191 
 192   if (JVMTI_ERROR_NONE != jvmti_error) {
 193     return -1;
 194   }
 195   if (line_number_table_entries <= 0) {
 196     return -1;
 197   }
 198   if (line_number_table_entries == 1) {
 199     return table_ptr[0].line_number;
 200   }
 201 
 202   // Go through all the line numbers...
 203   jint last_location = table_ptr[0].start_location;
 204   int l;
 205   for (l = 1; l < line_number_table_entries; l++) {
 206     // ... and if you see one that is in the right place for your
 207     // location, you've found the line number!
 208     if ((location < table_ptr[l].start_location) &&
 209         (location >= last_location)) {
 210       return table_ptr[l - 1].line_number;
 211     }
 212     last_location = table_ptr[l].start_location;
 213   }
 214 
 215   if (location >= last_location) {
 216     return table_ptr[line_number_table_entries - 1].line_number;
 217   } else {
 218     return -1;
 219   }
 220 }
 221 
 222 typedef struct _ExpectedContentFrame {
 223   const char *name;
 224   const char *signature;
 225   const char *file_name;
 226   int line_number;
 227 } ExpectedContentFrame;
 228 
 229 static jint check_sample_content(JNIEnv *env,
 230                                  jvmtiStackTrace *trace,
 231                                  ExpectedContentFrame *expected,
 232                                  int expected_count) {
 233   int i;
 234 
 235   if (expected_count > trace->frame_count) {
 236     return 0;
 237   }
 238 
 239   for (i = 0; i < expected_count; i++) {
 240     // Get basic information out of the trace.
 241     int bci = trace->frames[i].location;
 242     jmethodID methodid = trace->frames[i].method;
 243     char *name = NULL, *signature = NULL, *file_name = NULL;
 244 
 245     if (bci < 0) {
 246       return 0;
 247     }
 248 
 249     // Transform into usable information.
 250     int line_number = get_line_number(jvmti, methodid, bci);
 251     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 252 
 253     jclass declaring_class;
 254     if (JVMTI_ERROR_NONE !=
 255         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 256       return 0;
 257     }
 258 
 259     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 260                                                  &file_name);
 261     if (err != JVMTI_ERROR_NONE) {
 262       return 0;
 263     }
 264 
 265     // Compare now, none should be NULL.
 266     if (name == NULL) {
 267       return 0;
 268     }
 269 
 270     if (file_name == NULL) {
 271       return 0;
 272     }
 273 
 274     if (signature == NULL) {
 275       return 0;
 276     }
 277 
 278     if (strcmp(name, expected[i].name) ||
 279         strcmp(signature, expected[i].signature) ||
 280         strcmp(file_name, expected[i].file_name) ||
 281         line_number != expected[i].line_number) {
 282       return 0;
 283     }
 284   }
 285 
 286   return 1;
 287 }
 288 
 289 static jint compare_samples(JNIEnv* env, jvmtiStackTrace* traces, int trace_count,
 290                             ExpectedContentFrame* expected_content, size_t size) {
 291   // We expect the code to record correctly the bci, retrieve the line
 292   // number, have the right method and the class name of the first frames.
 293   int i;
 294   for (i = 0; i < trace_count; i++) {
 295     jvmtiStackTrace *trace = traces + i;
 296     if (check_sample_content(env, trace, expected_content, size)) {
 297       // At least one frame matched what we were looking for.
 298       return 1;
 299     }
 300   }
 301 
 302   return 0;
 303 }
 304 
 305 static jint check_samples(JNIEnv* env, ExpectedContentFrame* expected,
 306                           size_t size,
 307                           jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) {
 308   jvmtiStackTraces traces;
 309   jvmtiError error = get_traces(jvmti, &traces);
 310 
 311   if (error != JVMTI_ERROR_NONE) {
 312     return 0;
 313   }
 314 
 315   int result = compare_samples(env, traces.stack_traces, traces.trace_count,
 316                             expected, size);
 317   (*jvmti)->ReleaseTraces(jvmti, &traces);
 318   return result;
 319 }
 320 
 321 static jint frames_exist_live(JNIEnv* env, ExpectedContentFrame* expected,
 322                             size_t size) {
 323   return check_samples(env, expected, size, (*jvmti)->GetLiveTraces);
 324 }
 325 
 326 static jint frames_exist_recent(JNIEnv* env, ExpectedContentFrame* expected,
 327                               size_t size) {
 328   return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces);
 329 }
 330 
 331 static jint frames_exist_frequent(JNIEnv* env, ExpectedContentFrame* expected,
 332                               size_t size) {
 333   return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces);
 334 }
 335 
 336 // Static native API for various tests.
 337 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 338                                ExpectedContentFrame* native_frames, size_t size) {
 339   size_t i;
 340   for(i = 0; i < size; i++) {
 341     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 342     jclass frame_class = (*env)->GetObjectClass(env, obj);
 343     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, "lineNumber", "I");
 344     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 345 
 346     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", "Ljava/lang/String;");
 347     jstring string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 348     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 349 
 350     string_id = (*env)->GetFieldID(env, frame_class, "fileName", "Ljava/lang/String;");
 351     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 352     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 353 
 354     string_id = (*env)->GetFieldID(env, frame_class, "signature", "Ljava/lang/String;");
 355     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 356     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 357 
 358     native_frames[i].name = method;
 359     native_frames[i].file_name = file_name;
 360     native_frames[i].signature = signature;
 361     native_frames[i].line_number = line_number;
 362   }
 363 }
 364 
 365 static jint check_and(JNIEnv *env, jobjectArray frames, int live, int recent,
 366                      int frequent) {
 367   jobject loader = NULL;
 368 
 369   if (frames == NULL) {
 370     return 0;
 371   }
 372 
 373   // Start by transforming the frames into a C-friendly structure.
 374   jsize size = (*env)->GetArrayLength(env, frames);
 375   ExpectedContentFrame native_frames[size];
 376   fill_native_frames(env, frames, native_frames, size);
 377 
 378   if (jvmti == NULL) {
 379     throw_exc(env, "JVMTI client was not properly loaded!\n");
 380     return 0;
 381   }
 382 
 383   int result = 1;
 384 
 385   if (live) {
 386     result = frames_exist_live(env, native_frames, size);
 387   }
 388 
 389   if (recent) {
 390     result = result &&
 391         frames_exist_recent(env, native_frames, size);
 392   }
 393 
 394   if (frequent) {
 395     result = result &&
 396         frames_exist_frequent(env, native_frames, size);
 397   }
 398 
 399   return result;
 400 }
 401 
 402 static jint check_or(JNIEnv *env, jobjectArray frames, int live, int recent,
 403                     int frequent) {
 404   jobject loader = NULL;
 405 
 406   if (frames == NULL) {
 407     return 0;
 408   }
 409 
 410   // Start by transforming the frames into a C-friendly structure.
 411   jsize size = (*env)->GetArrayLength(env, frames);
 412   ExpectedContentFrame native_frames[size];
 413   fill_native_frames(env, frames, native_frames, size);
 414 
 415   if (jvmti == NULL) {
 416     throw_exc(env, "JVMTI client was not properly loaded!\n");
 417     return 0;
 418   }
 419 
 420   int result = 0;
 421 
 422   if (live) {
 423     result = frames_exist_live(env, native_frames, size);
 424   }
 425 
 426   if (recent) {
 427     result = result ||
 428         frames_exist_recent(env, native_frames, size);
 429   }
 430 
 431   if (frequent) {
 432     result = result ||
 433         frames_exist_frequent(env, native_frames, size);
 434   }
 435 
 436   return result;
 437 }
 438 
 439 static jint checkAll(JNIEnv *env, jobjectArray frames) {
 440   return check_and(env, frames, 1, 1, 1);
 441 }
 442 
 443 static jint checkNone(JNIEnv *env, jobjectArray frames) {
 444   jobject loader = NULL;
 445 
 446   if (frames == NULL) {
 447     return 0;
 448   }
 449 
 450   // Start by transforming the frames into a C-friendly structure.
 451   jsize size = (*env)->GetArrayLength(env, frames);
 452   ExpectedContentFrame native_frames[size];
 453   fill_native_frames(env, frames, native_frames, size);
 454 
 455   if (jvmti == NULL) {
 456     throw_exc(env, "JVMTI client was not properly loaded!\n");
 457     return 0;
 458   }
 459 
 460   if ((!frames_exist_live(env, native_frames, size)) &&
 461       (!frames_exist_recent(env, native_frames, size)) &&
 462       (!frames_exist_frequent(env, native_frames, size))) {
 463     return 1;
 464   }
 465   return 0;
 466 }
 467 
 468 static void enable_sampling() {
 469   check_error((*jvmti)->StartHeapSampling(jvmti, 1 << 19, MAX_TRACES),
 470               "Start Heap Sampling");
 471 }
 472 
 473 static void enable_sampling_with_rate(int rate) {
 474   check_error((*jvmti)->StartHeapSampling(jvmti, rate, MAX_TRACES),
 475               "Start Heap Sampling");
 476 }
 477 
 478 static void enable_sampling_with_max_traces(int max_traces) {
 479   check_error((*jvmti)->StartHeapSampling(jvmti, 1 << 19, max_traces),
 480               "Start Heap Sampling");
 481 }
 482 
 483 static void disable_sampling() {
 484   check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
 485 }
 486 
 487 JNIEXPORT jint JNICALL
 488 Java_MyPackage_HeapMonitorTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 489   // We want the frames in each part.
 490   if (!checkAll(env, frames)) {
 491     return FAILED;
 492   }
 493   return PASSED;
 494 }
 495 
 496 JNIEXPORT void JNICALL
 497 Java_MyPackage_HeapMonitorTest_enableSampling(JNIEnv *env, jclass cls) {
 498   enable_sampling();
 499 }
 500 
 501 JNIEXPORT jint JNICALL
 502 Java_MyPackage_HeapMonitorOnOffTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 503   // We want the frames in each part.
 504   if (!checkAll(env, frames)) {
 505     return FAILED;
 506   }
 507   return PASSED;
 508 }
 509 
 510 JNIEXPORT jint JNICALL
 511 Java_MyPackage_HeapMonitorOnOffTest_checkWipeOut(JNIEnv *env, jclass cls, jobjectArray frames) {
 512   // We want the frames in none of the parts.
 513   if (!checkNone(env, frames)) {
 514     return FAILED;
 515   }
 516   return PASSED;
 517 }
 518 
 519 JNIEXPORT void JNICALL
 520 Java_MyPackage_HeapMonitorOnOffTest_enableSampling(JNIEnv *env, jclass cls) {
 521   enable_sampling();
 522 }
 523 
 524 JNIEXPORT void JNICALL
 525 Java_MyPackage_HeapMonitorOnOffTest_disableSampling(JNIEnv *env, jclass cls) {
 526   disable_sampling();
 527 }
 528 
 529 JNIEXPORT jint JNICALL
 530 Java_MyPackage_HeapMonitorRecentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 531   // We want the frames in each part.
 532   if (!checkAll(env, frames)) {
 533     return FAILED;
 534   }
 535   return PASSED;
 536 }
 537 
 538 JNIEXPORT jint JNICALL
 539 Java_MyPackage_HeapMonitorRecentTest_checkLiveOrRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 540   if (check_or(env, frames, 1, 1, 0)) {
 541     return FAILED;
 542   }
 543   return PASSED;
 544 }
 545 
 546 JNIEXPORT jint JNICALL
 547 Java_MyPackage_HeapMonitorRecentTest_checkLiveAndRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 548   if (check_and(env, frames, 1, 1, 0)) {
 549     return FAILED;
 550   }
 551   return PASSED;
 552 }
 553 
 554 JNIEXPORT void JNICALL
 555 Java_MyPackage_HeapMonitorRecentTest_enableSampling(JNIEnv *env, jclass cls) {
 556   enable_sampling();
 557 }
 558 
 559 JNIEXPORT jint JNICALL
 560 Java_MyPackage_HeapMonitorFrequentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 561   // We want the frames in each part.
 562   if (!checkAll(env, frames)) {
 563     return FAILED;
 564   }
 565   return PASSED;
 566 }
 567 
 568 JNIEXPORT jint JNICALL
 569 Java_MyPackage_HeapMonitorFrequentTest_checkFrequentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 570   if (check_and(env, frames, 0, 0, 1)) {
 571     return PASSED;
 572   }
 573   return FAILED;
 574 }
 575 
 576 JNIEXPORT void JNICALL
 577 Java_MyPackage_HeapMonitorFrequentTest_enableSampling(JNIEnv *env, jclass cls) {
 578   enable_sampling();
 579 }
 580 
 581 JNIEXPORT jboolean JNICALL
 582 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, jclass cls) {
 583   jvmtiCapabilities caps;
 584   memset(&caps, 0, sizeof(caps));
 585   caps.can_sample_heap= 1;
 586   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 587                   "Add capabilities\n")){
 588     return 0;
 589   }
 590 
 591   if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
 592                                                          MAX_TRACES),
 593                              "Start Heap Sampling")) {
 594     return 0;
 595   }
 596 
 597   if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
 598                              "Stop Heap Sampling")) {
 599     return 0;
 600   }
 601 
 602   if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL),
 603                              "Release Traces")) {
 604     return 0;
 605   }
 606 
 607   if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
 608                              "Get Heap Sampling Stats")) {
 609     return 0;
 610   }
 611 
 612   if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL),
 613                              "Get Garbage Traces")) {
 614     return 0;
 615   }
 616 
 617   if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL),
 618                              "Get Frequent Garbage Traces")) {
 619     return 0;
 620   }
 621 
 622   if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL),
 623                              "Get Live Traces")) {
 624     return 0;
 625   }
 626 
 627   // Calling enable sampling should fail now.
 628   return 1;
 629 }
 630 
 631 JNIEXPORT void JNICALL
 632 Java_MyPackage_HeapMonitorStatSimpleTest_enableSampling(JNIEnv *env, jclass cls) {
 633   enable_sampling();
 634 }
 635 
 636 static jint stats_are_zero() {
 637   jvmtiHeapSamplingStats stats;
 638   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 639               "Heap Sampling Statistics");
 640 
 641   jvmtiHeapSamplingStats zero;
 642   memset(&zero, 0, sizeof(zero));
 643   return memcmp(&stats, &zero, sizeof(zero)) == 0;
 644 }
 645 
 646 JNIEXPORT jint JNICALL
 647 Java_MyPackage_HeapMonitorStatSimpleTest_statsNull(JNIEnv *env, jclass cls) {
 648   return stats_are_zero();
 649 }
 650 
 651 JNIEXPORT void JNICALL
 652 Java_MyPackage_HeapMonitorStatCorrectnessTest_disableSampling(JNIEnv *env, jclass cls) {
 653   disable_sampling();
 654 }
 655 
 656 JNIEXPORT void JNICALL
 657 Java_MyPackage_HeapMonitorStatCorrectnessTest_enableSampling(JNIEnv *env, jclass cls, jint rate) {
 658   enable_sampling_with_rate(rate);
 659 }
 660 
 661 JNIEXPORT jint JNICALL
 662 Java_MyPackage_HeapMonitorStatCorrectnessTest_statsNull(JNIEnv *env, jclass cls) {
 663   return stats_are_zero();
 664 }
 665 
 666 JNIEXPORT jint JNICALL
 667 Java_MyPackage_HeapMonitorStatCorrectnessTest_statsHaveSamples(JNIEnv *env,
 668                                                                jclass cls,
 669                                                                int expected,
 670                                                                int percent_error) {
 671   jvmtiHeapSamplingStats stats;
 672   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 673               "Heap Sampling Statistics");
 674 
 675   double diff_ratio = (stats.sample_count - expected);
 676   diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
 677   diff_ratio /= expected;
 678 
 679   return diff_ratio * 100 > percent_error;
 680 }
 681 
 682 JNIEXPORT void JNICALL
 683 Java_MyPackage_HeapMonitorStatRateTest_enableSampling(JNIEnv *env, jclass cls, jint rate) {
 684   enable_sampling_with_rate(rate);
 685 }
 686 
 687 JNIEXPORT void JNICALL
 688 Java_MyPackage_HeapMonitorStatRateTest_disableSampling(JNIEnv *env, jclass cls) {
 689   disable_sampling();
 690 }
 691 
 692 JNIEXPORT jdouble JNICALL
 693 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 694   jvmtiHeapSamplingStats stats;
 695   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 696               "Heap Sampling Statistics");
 697   return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
 698 }
 699 
 700 JNIEXPORT void JNICALL
 701 Java_MyPackage_HeapMonitorStackDepthTest_enableSampling(JNIEnv *env, jclass cls) {
 702   enable_sampling();
 703 }
 704 
 705 JNIEXPORT void JNICALL
 706 Java_MyPackage_HeapMonitorStackDepthTest_disableSampling(JNIEnv *env, jclass cls) {
 707   disable_sampling();
 708 }
 709 
 710 JNIEXPORT jdouble JNICALL
 711 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env, jclass cls) {
 712   jvmtiStackTraces traces;
 713   jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &traces);;
 714 
 715   if (error != JVMTI_ERROR_NONE) {
 716     return 0;
 717   }
 718 
 719   int trace_count = traces.trace_count;
 720 
 721   if (trace_count == 0) {
 722     return 0;
 723   }
 724 
 725   int i;
 726   jvmtiStackTrace* stack_traces = traces.stack_traces;
 727   double sum = 0;
 728   for (i = 0; i < trace_count; i++) {
 729     jvmtiStackTrace *stack_trace = stack_traces + i;
 730     sum += stack_trace->frame_count;
 731   }
 732 
 733   return sum / i;
 734 }
 735 
 736 JNIEXPORT void JNICALL
 737 Java_MyPackage_HeapMonitorThreadTest_enableSampling(JNIEnv *env, jclass cls) {
 738   // Remember a lot of the garbage collected samples to ensure test correctness.
 739   enable_sampling_with_max_traces(100000);
 740 }
 741 
 742 typedef struct sThreadsFound {
 743   jint *threads;
 744   int num_threads;
 745 }ThreadsFound;
 746 
 747 static void find_threads_in_traces(jvmtiStackTraces* traces, ThreadsFound* thread_data) {
 748   int i;
 749   jvmtiStackTrace* stack_traces = traces->stack_traces;
 750   int trace_count = traces->trace_count;
 751 
 752   jint *threads = thread_data->threads;
 753   int num_threads = thread_data->num_threads;
 754 
 755   // We are looking for at last expected_num_threads different traces.
 756   for (i = 0; i < trace_count; i++) {
 757     jvmtiStackTrace *stack_trace = stack_traces + i;
 758     jlong thread_id = stack_trace->thread_id;
 759 
 760     // Check it is the right frame: only accept helper top framed traces.
 761     jmethodID methodid = stack_trace->frames[0].method;
 762     char *name = NULL, *signature = NULL, *file_name = NULL;
 763     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 764 
 765     if (strcmp(name, "helper")) {
 766       continue;
 767     }
 768 
 769     // Really not efficient look-up but it's for a test...
 770     int found = 0;
 771     int j;
 772     for (j = 0; j < num_threads; j++) {
 773       if (thread_id == threads[j]) {
 774         found = 1;
 775         break;
 776       }
 777     }
 778 
 779     if (!found) {
 780       threads[num_threads] = thread_id;
 781       num_threads++;
 782     }
 783   }
 784   thread_data->num_threads = num_threads;
 785 }
 786 
 787 JNIEXPORT jboolean JNICALL
 788 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls, jintArray threads) {
 789   jvmtiStackTraces traces;
 790   ThreadsFound thread_data;
 791   thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
 792   thread_data.num_threads = 0;
 793 
 794   // Get live and garbage traces to ensure we capture all the threads that have
 795   // been sampled.
 796   if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 797     return 0;
 798   }
 799 
 800   find_threads_in_traces(&traces, &thread_data);
 801 
 802   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 803     return 0;
 804   }
 805 
 806   if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 807     return 0;
 808   }
 809 
 810   find_threads_in_traces(&traces, &thread_data);
 811 
 812   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 813     return 0;
 814   }
 815 
 816   (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
 817   return 1;
 818 }
 819 
 820 JNIEXPORT void JNICALL
 821 Java_MyPackage_Switch_enableSampling(JNIEnv *env, jclass cls) {
 822   enable_sampling();
 823 }
 824 
 825 JNIEXPORT void JNICALL
 826 Java_MyPackage_Switch_disableSampling(JNIEnv *env, jclass cls) {
 827   disable_sampling();
 828 }
 829 
 830 #ifdef __cplusplus
 831 }
 832 #endif