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 <string.h>
  26 #include "jvmti.h"
  27 
  28 #ifdef __cplusplus
  29 extern "C" {
  30 #endif
  31 
  32 #ifndef JNI_ENV_ARG
  33 
  34 #ifdef __cplusplus
  35 #define JNI_ENV_ARG(x, y) y
  36 #define JNI_ENV_PTR(x) x
  37 #else
  38 #define JNI_ENV_ARG(x,y) x, y
  39 #define JNI_ENV_PTR(x) (*x)
  40 #endif
  41 
  42 #endif
  43 
  44 #define PASSED 0
  45 #define FAILED 2
  46 
  47 #define MAX_TRACES 400
  48 
  49 static const char *EXC_CNAME = "java/lang/Exception";
  50 static jvmtiEnv *jvmti = NULL;
  51 
  52 static int check_error(jvmtiError err, const char* s) {
  53   if (err != JVMTI_ERROR_NONE) {
  54     printf("  ## %s error: %d\n", s, err);
  55     return 1;
  56   }
  57   return 0;
  58 }
  59 
  60 static int check_capability_error(jvmtiError err, const char* s) {
  61   if (err != JVMTI_ERROR_NONE) {
  62     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
  63       return 0;
  64     }
  65     printf("  ## %s error: %d\n", s, err);
  66     return 1;
  67   }
  68   return 1;
  69 }
  70 
  71 static
  72 jint throw_exc(JNIEnv *env, char *msg) {
  73   jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
  74 
  75   if (exc_class == NULL) {
  76     printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
  77     return -1;
  78   }
  79   return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
  80 }
  81 
  82 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  83 
  84 JNIEXPORT
  85 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
  86   return Agent_Initialize(jvm, options, reserved);
  87 }
  88 
  89 JNIEXPORT
  90 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
  91   return Agent_Initialize(jvm, options, reserved);
  92 }
  93 
  94 JNIEXPORT
  95 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
  96   return JNI_VERSION_1_8;
  97 }
  98 
  99 JNIEXPORT void JNICALL OnVMInit(jvmtiEnv *jvmti, JNIEnv *jni_env, jthread thread) {
 100 }
 101 
 102 JNIEXPORT void JNICALL OnClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
 103                                               jthread thread, jclass klass) {
 104   // NOP.
 105 }
 106 
 107 JNIEXPORT void JNICALL OnClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
 108                                       jthread thread, jclass klass) {
 109   // We need to do this to "prime the pump", as it were -- make sure
 110   // that all of the methodIDs have been initialized internally, for
 111   // AsyncGetCallTrace.
 112   jint method_count;
 113   jmethodID *methods = 0;
 114   jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
 115   if ((err != JVMTI_ERROR_NONE) && (err != JVMTI_ERROR_CLASS_NOT_PREPARED)) {
 116     // JVMTI_ERROR_CLASS_NOT_PREPARED is okay because some classes may
 117     // be loaded but not prepared at this point.
 118     throw_exc(jni_env, "Failed to create method IDs for methods in class\n");
 119   }
 120 }
 121 
 122 static
 123 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 124   jint res;
 125 
 126   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 127                                  JVMTI_VERSION_9);
 128   if (res != JNI_OK || jvmti == NULL) {
 129     printf("    Error: wrong result of a valid call to GetEnv!\n");
 130     return JNI_ERR;
 131   }
 132 
 133   jvmtiEventCallbacks callbacks;
 134   memset(&callbacks, 0, sizeof(callbacks));
 135 
 136   callbacks.VMInit = &OnVMInit;
 137   callbacks.ClassLoad = &OnClassLoad;
 138   callbacks.ClassPrepare = &OnClassPrepare;
 139 
 140   jvmtiCapabilities caps;
 141   memset(&caps, 0, sizeof(caps));
 142   // Get line numbers, sample heap, and filename for the test.
 143   caps.can_get_line_numbers = 1;
 144   caps.can_sample_heap= 1;
 145   caps.can_get_source_file_name = 1;
 146   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
 147                   "Add capabilities\n")){
 148     return JNI_ERR;
 149   }
 150 
 151   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 152                                               sizeof(jvmtiEventCallbacks)),
 153                   " Set Event Callbacks")) {
 154     return JNI_ERR;
 155   }
 156   if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 157                                                      JVMTI_EVENT_VM_INIT, NULL),
 158                   "Set Event for VM Init")) {
 159     return JNI_ERR;
 160   }
 161   if (check_error((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 162                                                      JVMTI_EVENT_CLASS_LOAD, NULL),
 163                   "Set Event for Class Load")) {
 164     return JNI_ERR;
 165   }
 166   if (check_error( (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 167                                                       JVMTI_EVENT_CLASS_PREPARE, NULL),
 168                   "Set Event for Class Prepare")) {
 169     return JNI_ERR;
 170   }
 171 
 172   return JNI_OK;
 173 }
 174 
 175 // Given a method and a location, this method gets the line number.
 176 // Kind of expensive, comparatively.
 177 static
 178 jint get_line_number(jvmtiEnv *jvmti, jmethodID method, jlocation location) {
 179   // The location is -1 if the bci isn't known or -3 for a native method.
 180   if (location == -1 || location == -3) {
 181     return -1;
 182   }
 183 
 184   // Read the line number table.
 185   jvmtiLineNumberEntry *table_ptr = 0;
 186   jint line_number_table_entries;
 187   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
 188                                                  &line_number_table_entries,
 189                                                  &table_ptr);
 190 
 191   if (JVMTI_ERROR_NONE != jvmti_error) {
 192     return -1;
 193   }
 194   if (line_number_table_entries <= 0) {
 195     return -1;
 196   }
 197   if (line_number_table_entries == 1) {
 198     return table_ptr[0].line_number;
 199   }
 200 
 201   // Go through all the line numbers...
 202   jint last_location = table_ptr[0].start_location;
 203   int l;
 204   for (l = 1; l < line_number_table_entries; l++) {
 205     // ... and if you see one that is in the right place for your
 206     // location, you've found the line number!
 207     if ((location < table_ptr[l].start_location) &&
 208         (location >= last_location)) {
 209       return table_ptr[l - 1].line_number;
 210     }
 211     last_location = table_ptr[l].start_location;
 212   }
 213 
 214   if (location >= last_location) {
 215     return table_ptr[line_number_table_entries - 1].line_number;
 216   } else {
 217     return -1;
 218   }
 219 }
 220 
 221 typedef struct _ExpectedContentFrame {
 222   const char *name;
 223   const char *signature;
 224   const char *file_name;
 225   int line_number;
 226 } ExpectedContentFrame;
 227 
 228 static jint check_sample_content(JNIEnv *env,
 229                                  jvmtiStackTrace *trace,
 230                                  ExpectedContentFrame *expected,
 231                                  int expected_count) {
 232   int i;
 233 
 234   if (expected_count > trace->frame_count) {
 235     return 0;
 236   }
 237 
 238   for (i = 0; i < expected_count; i++) {
 239     // Get basic information out of the trace.
 240     int bci = trace->frames[i].location;
 241     jmethodID methodid = trace->frames[i].method;
 242     char *name = NULL, *signature = NULL, *file_name = NULL;
 243 
 244     if (bci < 0) {
 245       return 0;
 246     }
 247 
 248     // Transform into usable information.
 249     int line_number = get_line_number(jvmti, methodid, bci);
 250     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 251 
 252     jclass declaring_class;
 253     if (JVMTI_ERROR_NONE !=
 254         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 255       return 0;
 256     }
 257 
 258     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 259                                                  &file_name);
 260     if (err != JVMTI_ERROR_NONE) {
 261       return 0;
 262     }
 263 
 264     // Compare now, none should be NULL.
 265     if (name == NULL) {
 266       return 0;
 267     }
 268 
 269     if (file_name == NULL) {
 270       return 0;
 271     }
 272 
 273     if (signature == NULL) {
 274       return 0;
 275     }
 276 
 277     if (strcmp(name, expected[i].name) ||
 278         strcmp(signature, expected[i].signature) ||
 279         strcmp(file_name, expected[i].file_name) ||
 280         line_number != expected[i].line_number) {
 281       return 0;
 282     }
 283   }
 284 
 285   return 1;
 286 }
 287 
 288 static jint compare_samples(JNIEnv* env, jvmtiStackTrace* traces, int trace_count,
 289                             ExpectedContentFrame* expected_content, size_t size) {
 290   // We expect the code to record correctly the bci, retrieve the line
 291   // number, have the right method and the class name of the first frames.
 292   int i;
 293   for (i = 0; i < trace_count; i++) {
 294     jvmtiStackTrace *trace = traces + i;
 295     if (check_sample_content(env, trace, expected_content, size)) {
 296       // At least one frame matched what we were looking for.
 297       return 1;
 298     }
 299   }
 300 
 301   return 0;
 302 }
 303 
 304 static jint check_samples(JNIEnv* env, ExpectedContentFrame* expected,
 305                           size_t size,
 306                           jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) {
 307   jvmtiStackTraces traces;
 308   jvmtiError error = get_traces(jvmti, &traces);
 309 
 310   if (error != JVMTI_ERROR_NONE) {
 311     return 0;
 312   }
 313 
 314   int result = compare_samples(env, traces.stack_traces, traces.trace_count,
 315                             expected, size);
 316   (*jvmti)->ReleaseTraces(jvmti, &traces);
 317   return result;
 318 }
 319 
 320 static jint frames_exist_live(JNIEnv* env, ExpectedContentFrame* expected,
 321                             size_t size) {
 322   return check_samples(env, expected, size, (*jvmti)->GetLiveTraces);
 323 }
 324 
 325 static jint frames_exist_recent(JNIEnv* env, ExpectedContentFrame* expected,
 326                               size_t size) {
 327   return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces);
 328 }
 329 
 330 static jint frames_exist_frequent(JNIEnv* env, ExpectedContentFrame* expected,
 331                               size_t size) {
 332   return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces);
 333 }
 334 
 335 // Static native API for various tests.
 336 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 337                                ExpectedContentFrame* native_frames, size_t size) {
 338   size_t i;
 339   for(i = 0; i < size; i++) {
 340     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 341     jclass frame_class = (*env)->GetObjectClass(env, obj);
 342     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class, "lineNumber", "I");
 343     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 344 
 345     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method", "Ljava/lang/String;");
 346     jstring string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 347     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 348 
 349     string_id = (*env)->GetFieldID(env, frame_class, "fileName", "Ljava/lang/String;");
 350     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 351     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 352 
 353     string_id = (*env)->GetFieldID(env, frame_class, "signature", "Ljava/lang/String;");
 354     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 355     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 356 
 357     native_frames[i].name = method;
 358     native_frames[i].file_name = file_name;
 359     native_frames[i].signature = signature;
 360     native_frames[i].line_number = line_number;
 361   }
 362 }
 363 
 364 static jint checkAnd(JNIEnv *env, jobjectArray frames, int live, int recent,
 365                      int frequent) {
 366   jobject loader = NULL;
 367 
 368   if (frames == NULL) {
 369     return 0;
 370   }
 371 
 372   // Start by transforming the frames into a C-friendly structure.
 373   jsize size = (*env)->GetArrayLength(env, frames);
 374   ExpectedContentFrame native_frames[size];
 375   fill_native_frames(env, frames, native_frames, size);
 376 
 377   if (jvmti == NULL) {
 378     throw_exc(env, "JVMTI client was not properly loaded!\n");
 379     return 0;
 380   }
 381 
 382   int result = 1;
 383 
 384   if (live) {
 385     result = frames_exist_live(env, native_frames, size);
 386   }
 387 
 388   if (recent) {
 389     result = result &&
 390         frames_exist_recent(env, native_frames, size);
 391   }
 392 
 393   if (frequent) {
 394     result = result &&
 395         frames_exist_frequent(env, native_frames, size);
 396   }
 397 
 398   return result;
 399 }
 400 
 401 static jint checkOr(JNIEnv *env, jobjectArray frames, int live, int recent,
 402                     int frequent) {
 403   jobject loader = NULL;
 404 
 405   if (frames == NULL) {
 406     return 0;
 407   }
 408 
 409   // Start by transforming the frames into a C-friendly structure.
 410   jsize size = (*env)->GetArrayLength(env, frames);
 411   ExpectedContentFrame native_frames[size];
 412   fill_native_frames(env, frames, native_frames, size);
 413 
 414   if (jvmti == NULL) {
 415     throw_exc(env, "JVMTI client was not properly loaded!\n");
 416     return 0;
 417   }
 418 
 419   int result = 0;
 420 
 421   if (live) {
 422     result = frames_exist_live(env, native_frames, size);
 423   }
 424 
 425   if (recent) {
 426     result = result ||
 427         frames_exist_recent(env, native_frames, size);
 428   }
 429 
 430   if (frequent) {
 431     result = result ||
 432         frames_exist_frequent(env, native_frames, size);
 433   }
 434 
 435   return result;
 436 }
 437 
 438 static jint checkAll(JNIEnv *env, jobjectArray frames) {
 439   return checkAnd(env, frames, 1, 1, 1);
 440 }
 441 
 442 static jint checkNone(JNIEnv *env, jobjectArray frames) {
 443   jobject loader = NULL;
 444 
 445   if (frames == NULL) {
 446     return 0;
 447   }
 448 
 449   // Start by transforming the frames into a C-friendly structure.
 450   jsize size = (*env)->GetArrayLength(env, frames);
 451   ExpectedContentFrame native_frames[size];
 452   fill_native_frames(env, frames, native_frames, size);
 453 
 454   if (jvmti == NULL) {
 455     throw_exc(env, "JVMTI client was not properly loaded!\n");
 456     return 0;
 457   }
 458 
 459   if ((!frames_exist_live(env, native_frames, size)) &&
 460       (!frames_exist_recent(env, native_frames, size)) &&
 461       (!frames_exist_frequent(env, native_frames, size))) {
 462     return 1;
 463   }
 464   return 0;
 465 }
 466 
 467 static void enable_sampling() {
 468   check_error((*jvmti)->StartHeapSampling(jvmti, 1 << 19, MAX_TRACES),
 469               "Start Heap Sampling");
 470 }
 471 
 472 static void enable_sampling_with_rate(int rate) {
 473   check_error((*jvmti)->StartHeapSampling(jvmti, rate, MAX_TRACES),
 474               "Start Heap Sampling");
 475 }
 476 
 477 static void disable_sampling() {
 478   check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
 479 }
 480 
 481 // HeapMonitorTest JNI.
 482 JNIEXPORT jint JNICALL
 483 Java_MyPackage_HeapMonitorTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 484   // We want the frames in each part.
 485   if (!checkAll(env, frames)) {
 486     return FAILED;
 487   }
 488   return PASSED;
 489 }
 490 
 491 JNIEXPORT void JNICALL
 492 Java_MyPackage_HeapMonitorTest_enableSampling(JNIEnv *env, jclass cls) {
 493   enable_sampling();
 494 }
 495 
 496 // HeapMonitorOnOffTest JNI.
 497 JNIEXPORT jint JNICALL
 498 Java_MyPackage_HeapMonitorOnOffTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 499   // We want the frames in each part.
 500   if (!checkAll(env, frames)) {
 501     return FAILED;
 502   }
 503   return PASSED;
 504 }
 505 
 506 JNIEXPORT jint JNICALL
 507 Java_MyPackage_HeapMonitorOnOffTest_checkWipeOut(JNIEnv *env, jclass cls, jobjectArray frames) {
 508   // We want the frames in none of the parts.
 509   if (!checkNone(env, frames)) {
 510     return FAILED;
 511   }
 512   return PASSED;
 513 }
 514 
 515 JNIEXPORT void JNICALL
 516 Java_MyPackage_HeapMonitorOnOffTest_enableSampling(JNIEnv *env, jclass cls) {
 517   enable_sampling();
 518 }
 519 
 520 JNIEXPORT void JNICALL
 521 Java_MyPackage_HeapMonitorOnOffTest_disableSampling(JNIEnv *env, jclass cls) {
 522   disable_sampling();
 523 }
 524 
 525 // HeapMonitorRecentTest JNI.
 526 JNIEXPORT jint JNICALL
 527 Java_MyPackage_HeapMonitorRecentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 528   // We want the frames in each part.
 529   if (!checkAll(env, frames)) {
 530     return FAILED;
 531   }
 532   return PASSED;
 533 }
 534 
 535 JNIEXPORT jint JNICALL
 536 Java_MyPackage_HeapMonitorRecentTest_checkLiveOrRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 537   if (checkOr(env, frames, 1, 1, 0)) {
 538     return FAILED;
 539   }
 540   return PASSED;
 541 }
 542 
 543 JNIEXPORT jint JNICALL
 544 Java_MyPackage_HeapMonitorRecentTest_checkLiveAndRecentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 545   if (checkAnd(env, frames, 1, 1, 0)) {
 546     return FAILED;
 547   }
 548   return PASSED;
 549 }
 550 
 551 JNIEXPORT void JNICALL
 552 Java_MyPackage_HeapMonitorRecentTest_enableSampling(JNIEnv *env, jclass cls) {
 553   enable_sampling();
 554 }
 555 
 556 // HeapMonitorFrequentTest JNI.
 557 JNIEXPORT jint JNICALL
 558 Java_MyPackage_HeapMonitorFrequentTest_checkFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 559   // We want the frames in each part.
 560   if (!checkAll(env, frames)) {
 561     return FAILED;
 562   }
 563   return PASSED;
 564 }
 565 
 566 JNIEXPORT jint JNICALL
 567 Java_MyPackage_HeapMonitorFrequentTest_checkFrequentFrames(JNIEnv *env, jclass cls, jobjectArray frames) {
 568   if (checkAnd(env, frames, 0, 0, 1)) {
 569     return PASSED;
 570   }
 571   return FAILED;
 572 }
 573 
 574 JNIEXPORT void JNICALL
 575 Java_MyPackage_HeapMonitorFrequentTest_enableSampling(JNIEnv *env, jclass cls) {
 576   enable_sampling();
 577 }
 578 
 579 JNIEXPORT jboolean JNICALL
 580 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env, jclass cls) {
 581   jvmtiCapabilities caps;
 582   memset(&caps, 0, sizeof(caps));
 583   caps.can_sample_heap= 1;
 584   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 585                   "Add capabilities\n")){
 586     return 0;
 587   }
 588 
 589   if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
 590                                                          MAX_TRACES),
 591                              "Start Heap Sampling")) {
 592     return 0;
 593   }
 594 
 595   if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
 596                              "Stop Heap Sampling")) {
 597     return 0;
 598   }
 599 
 600   if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL),
 601                              "Release Traces")) {
 602     return 0;
 603   }
 604 
 605   if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
 606                              "Get Heap Sampling Stats")) {
 607     return 0;
 608   }
 609 
 610   if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL),
 611                              "Get Garbage Traces")) {
 612     return 0;
 613   }
 614 
 615   if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL),
 616                              "Get Frequent Garbage Traces")) {
 617     return 0;
 618   }
 619 
 620   if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL),
 621                              "Get Live Traces")) {
 622     return 0;
 623   }
 624 
 625   // Calling enable sampling should fail now.
 626   return 1;
 627 }
 628 
 629 JNIEXPORT void JNICALL
 630 Java_MyPackage_HeapMonitorStatSimpleTest_enableSampling(JNIEnv *env, jclass cls) {
 631   enable_sampling();
 632 }
 633 
 634 static jint stats_are_zero() {
 635   jvmtiHeapSamplingStats stats;
 636   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 637               "Heap Sampling Statistics");
 638 
 639   jvmtiHeapSamplingStats zero;
 640   memset(&zero, 0, sizeof(zero));
 641   return memcmp(&stats, &zero, sizeof(zero)) == 0;
 642 }
 643 
 644 JNIEXPORT jint JNICALL
 645 Java_MyPackage_HeapMonitorStatSimpleTest_statsNull(JNIEnv *env, jclass cls) {
 646   return stats_are_zero();
 647 }
 648 
 649 JNIEXPORT void JNICALL
 650 Java_MyPackage_HeapMonitorStatCorrectnessTest_disableSampling(JNIEnv *env, jclass cls) {
 651   disable_sampling();
 652 }
 653 
 654 JNIEXPORT void JNICALL
 655 Java_MyPackage_HeapMonitorStatCorrectnessTest_enableSampling(JNIEnv *env, jclass cls, jint rate) {
 656   enable_sampling_with_rate(rate);
 657 }
 658 
 659 JNIEXPORT jint JNICALL
 660 Java_MyPackage_HeapMonitorStatCorrectnessTest_statsNull(JNIEnv *env, jclass cls) {
 661   return stats_are_zero();
 662 }
 663 
 664 JNIEXPORT jint JNICALL
 665 Java_MyPackage_HeapMonitorStatCorrectnessTest_statsHaveSamples(JNIEnv *env,
 666                                                                jclass cls,
 667                                                                int expected,
 668                                                                int percent_error) {
 669   jvmtiHeapSamplingStats stats;
 670   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 671               "Heap Sampling Statistics");
 672 
 673   fprintf(stderr, "Statistics show:\n");
 674   fprintf(stderr, "\tCollected samples: %ld\n\tGarbage collected samples: %ld\n",
 675           stats.sample_count, stats.garbage_collected_samples);
 676   fprintf(stderr, "\tSample rate accumulated: %ld\n\tSample Rate Count: %ld\n",
 677           stats.sample_rate_accumulation, stats.sample_rate_count);
 678   fprintf(stderr, "\tStack depth accumulation: %ld\n",
 679           stats.stack_depth_accumulation);
 680 
 681   fprintf(stderr, "Expected is %d\n", expected);
 682   double diff_ratio = (stats.sample_count - expected);
 683   diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
 684   diff_ratio /= expected;
 685 
 686   fprintf(stderr, "Diff ratio is %f\n", diff_ratio);
 687 
 688   return diff_ratio * 100 > percent_error;
 689 }
 690 
 691 #ifdef __cplusplus
 692 }
 693 #endif