1 /*
   2  * Copyright (c) 2018, 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 <assert.h>
  25 #include <pthread.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include "jvmti.h"
  30 
  31 #ifdef __cplusplus
  32 extern "C" {
  33 #endif
  34 
  35 #ifndef JNI_ENV_ARG
  36 
  37 #ifdef __cplusplus
  38 #define JNI_ENV_ARG(x, y) y
  39 #define JNI_ENV_PTR(x) x
  40 #else
  41 #define JNI_ENV_ARG(x,y) x, y
  42 #define JNI_ENV_PTR(x) (*x)
  43 #endif
  44 
  45 #endif
  46 
  47 #define TRUE 1
  48 #define FALSE 0
  49 #define PRINT_OUT 1
  50 #define MAX_TRACES 400
  51 
  52 static jvmtiEnv *jvmti = NULL;
  53 
  54 typedef struct _ObjectTrace{
  55   jweak object;
  56   size_t size;
  57   jvmtiFrameInfo* frames;
  58   size_t frame_count;
  59   jthread thread;
  60 } ObjectTrace;
  61 
  62 typedef struct _EventStorage {
  63   int live_object_size;
  64   int live_object_count;
  65   ObjectTrace** live_objects;
  66 
  67   int garbage_history_size;
  68   int garbage_history_index;
  69   ObjectTrace** garbage_collected_objects;
  70 
  71   // Two separate mutexes to separate storage data race and the compaction field
  72   // data race.
  73   pthread_mutex_t storage_mutex;
  74 
  75   int compaction_required;
  76   pthread_mutex_t compaction_mutex;
  77 } EventStorage;
  78 
  79 typedef struct _ExpectedContentFrame {
  80   const char *name;
  81   const char *signature;
  82   const char *file_name;
  83   int line_number;
  84 } ExpectedContentFrame;
  85 
  86 // Given a method and a location, this method gets the line number.
  87 static
  88 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
  89                      jlocation location) {
  90   // Read the line number table.
  91   jvmtiLineNumberEntry *table_ptr = 0;
  92   jint line_number_table_entries;
  93   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
  94                                                  &line_number_table_entries,
  95                                                  &table_ptr);
  96 
  97   if (JVMTI_ERROR_NONE != jvmti_error) {
  98     return -1;
  99   }
 100   if (line_number_table_entries <= 0) {
 101     return -1;
 102   }
 103   if (line_number_table_entries == 1) {
 104     return table_ptr[0].line_number;
 105   }
 106 
 107   // Go through all the line numbers...
 108   jint last_location = table_ptr[0].start_location;
 109   int l;
 110   for (l = 1; l < line_number_table_entries; l++) {
 111     // ... and if you see one that is in the right place for your
 112     // location, you've found the line number!
 113     if ((location < table_ptr[l].start_location) &&
 114         (location >= last_location)) {
 115       return table_ptr[l - 1].line_number;
 116     }
 117     last_location = table_ptr[l].start_location;
 118   }
 119 
 120   if (location >= last_location) {
 121     return table_ptr[line_number_table_entries - 1].line_number;
 122   } else {
 123     return -1;
 124   }
 125 }
 126 
 127 static jboolean check_sample_content(JNIEnv *env,
 128                                      ObjectTrace* trace,
 129                                      ExpectedContentFrame *expected,
 130                                      size_t expected_count,
 131                                      int print_out_comparisons) {
 132   if (expected_count > trace->frame_count) {
 133     return FALSE;
 134   }
 135 
 136   jvmtiFrameInfo* frames = trace->frames;
 137 
 138   size_t i;
 139   for (i = 0; i < expected_count; i++) {
 140     // Get basic information out of the trace.
 141     int bci = frames[i].location;
 142     jmethodID methodid = frames[i].method;
 143     char *name = NULL, *signature = NULL, *file_name = NULL;
 144 
 145     if (bci < 0) {
 146       return FALSE;
 147     }
 148 
 149     // Transform into usable information.
 150     int line_number = get_line_number(jvmti, methodid, bci);
 151     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 152 
 153     jclass declaring_class;
 154     if (JVMTI_ERROR_NONE !=
 155         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 156       return FALSE;
 157     }
 158 
 159     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 160                                                  &file_name);
 161     if (err != JVMTI_ERROR_NONE) {
 162       return FALSE;
 163     }
 164 
 165     // Compare now, none should be NULL.
 166     if (name == NULL) {
 167       return FALSE;
 168     }
 169 
 170     if (file_name == NULL) {
 171       return FALSE;
 172     }
 173 
 174     if (signature == NULL) {
 175       return FALSE;
 176     }
 177 
 178     if (print_out_comparisons) {
 179       fprintf(stderr, "\tComparing:\n");
 180       fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
 181       fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
 182       fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
 183       fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
 184       fprintf(stderr, "\t\tResult is %d\n",
 185               (strcmp(name, expected[i].name) ||
 186                strcmp(signature, expected[i].signature) ||
 187                strcmp(file_name, expected[i].file_name) ||
 188                line_number != expected[i].line_number));
 189     }
 190 
 191     if (strcmp(name, expected[i].name) ||
 192         strcmp(signature, expected[i].signature) ||
 193         strcmp(file_name, expected[i].file_name) ||
 194         line_number != expected[i].line_number) {
 195       return FALSE;
 196     }
 197   }
 198 
 199   return TRUE;
 200 }
 201 
 202 // Static native API for various tests.
 203 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 204                                ExpectedContentFrame* native_frames, size_t size) {
 205   size_t i;
 206   for (i = 0; i < size; i++) {
 207     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 208     jclass frame_class = (*env)->GetObjectClass(env, obj);
 209     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class,
 210                                                        "lineNumber", "I");
 211     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 212 
 213     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method",
 214                                             "Ljava/lang/String;");
 215     jstring string_object = (jstring) (*env)->GetObjectField(env, obj,
 216                                                              string_id);
 217     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 218 
 219     string_id = (*env)->GetFieldID(env, frame_class, "fileName",
 220                                    "Ljava/lang/String;");
 221     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 222     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 223 
 224     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 225                                    "Ljava/lang/String;");
 226     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 227     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 228 
 229     native_frames[i].name = method;
 230     native_frames[i].file_name = file_name;
 231     native_frames[i].signature = signature;
 232     native_frames[i].line_number = line_number;
 233   }
 234 }
 235 
 236 // Internal storage system implementation.
 237 
 238 static EventStorage global_event_storage;
 239 
 240 static void event_storage_set_compaction_required(EventStorage* storage) {
 241   pthread_mutex_lock(&storage->compaction_mutex);
 242   storage->compaction_required = 1;
 243   pthread_mutex_unlock(&storage->compaction_mutex);
 244 }
 245 
 246 static int event_storage_get_compaction_required(EventStorage* storage) {
 247   pthread_mutex_lock(&storage->compaction_mutex);
 248   int result = storage->compaction_required;
 249   pthread_mutex_unlock(&storage->compaction_mutex);
 250   return result;
 251 }
 252 
 253 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
 254   pthread_mutex_lock(&storage->storage_mutex);
 255   global_event_storage.garbage_history_size = value;
 256   free(global_event_storage.garbage_collected_objects);
 257   size_t size =
 258       sizeof(*global_event_storage.garbage_collected_objects) * value;
 259   global_event_storage.garbage_collected_objects = malloc(size);
 260   memset(global_event_storage.garbage_collected_objects, 0, size);
 261   pthread_mutex_unlock(&storage->storage_mutex);
 262 }
 263 
 264 // No mutex here, it is handled by the caller.
 265 static void event_storage_add_garbage_collected_object(EventStorage* storage,
 266                                                        ObjectTrace* object) {
 267   int idx = storage->garbage_history_index;
 268   free(storage->garbage_collected_objects[idx]);
 269   storage->garbage_collected_objects[idx] = object;
 270   storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
 271 }
 272 
 273 static int event_storage_get_count(EventStorage* storage) {
 274   pthread_mutex_lock(&storage->storage_mutex);
 275   int result = storage->live_object_count;
 276   pthread_mutex_unlock(&storage->storage_mutex);
 277   return result;
 278 }
 279 
 280 static double event_storage_get_average_rate(EventStorage* storage) {
 281   double accumulation = 0;
 282 
 283   pthread_mutex_lock(&storage->storage_mutex);
 284   int max_size = storage->live_object_count;
 285 
 286   int i;
 287   for (i = 0; i < max_size; i++) {
 288     accumulation += storage->live_objects[i]->size;
 289   }
 290   pthread_mutex_unlock(&storage->storage_mutex);
 291   return accumulation / max_size;
 292 }
 293 
 294 static jboolean event_storage_contains(JNIEnv* env,
 295                                        EventStorage* storage,
 296                                        ExpectedContentFrame* frames,
 297                                        size_t size) {
 298   pthread_mutex_lock(&storage->storage_mutex);
 299   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 300   int i;
 301   for (i = 0; i < storage->live_object_count; i++) {
 302     ObjectTrace* trace = storage->live_objects[i];
 303 
 304     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 305       pthread_mutex_unlock(&storage->storage_mutex);
 306       return TRUE;
 307     }
 308   }
 309   pthread_mutex_unlock(&storage->storage_mutex);
 310   return FALSE;
 311 }
 312 
 313 static jboolean event_storage_garbage_contains(JNIEnv* env,
 314                                                EventStorage* storage,
 315                                                ExpectedContentFrame* frames,
 316                                                size_t size) {
 317   pthread_mutex_lock(&storage->storage_mutex);
 318   fprintf(stderr, "Checking garbage storage count %d\n",
 319           storage->garbage_history_size);
 320   int i;
 321   for (i = 0; i < storage->garbage_history_size; i++) {
 322     ObjectTrace* trace = storage->garbage_collected_objects[i];
 323 
 324     if (trace == NULL) {
 325       continue;
 326     }
 327 
 328     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 329       pthread_mutex_unlock(&storage->storage_mutex);
 330       return TRUE;
 331     }
 332   }
 333   pthread_mutex_unlock(&storage->storage_mutex);
 334   return FALSE;
 335 }
 336 
 337 // No mutex here, handled by the caller.
 338 static void event_storage_augment_storage(EventStorage* storage) {
 339   int new_max = (storage->live_object_size * 2) + 1;
 340   ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
 341 
 342   int current_count = storage->live_object_count;
 343   memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 344   free(storage->live_objects);
 345   storage->live_objects = new_objects;
 346 
 347   storage->live_object_size = new_max;
 348 }
 349 
 350 static void event_storage_add(EventStorage* storage,
 351                               JNIEnv* jni,
 352                               jthread thread,
 353                               jobject object,
 354                               jclass klass,
 355                               jlong size) {
 356   jvmtiFrameInfo frames[64];
 357   jint count;
 358   jvmtiError err;
 359 
 360   err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
 361   if (err == JVMTI_ERROR_NONE && count >= 1) {
 362     jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
 363     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 364 
 365     ObjectTrace* live_object = (ObjectTrace*) malloc(sizeof(*live_object));
 366     live_object->frames = allocated_frames;
 367     live_object->frame_count = count;
 368     live_object->size = size;
 369     live_object->thread = thread;
 370     live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
 371 
 372     // Only now lock and get things done quickly.
 373     pthread_mutex_lock(&storage->storage_mutex);
 374 
 375     if (storage->live_object_count >= storage->live_object_size) {
 376       event_storage_augment_storage(storage);
 377     }
 378     assert(storage->live_object_count < storage->live_object_size);
 379 
 380     storage->live_objects[storage->live_object_count] = live_object;
 381     storage->live_object_count++;
 382 
 383     pthread_mutex_unlock(&storage->storage_mutex);
 384   }
 385 }
 386 
 387 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 388   pthread_mutex_lock(&storage->compaction_mutex);
 389   storage->compaction_required = 0;
 390   pthread_mutex_unlock(&storage->compaction_mutex);
 391 
 392   pthread_mutex_lock(&storage->storage_mutex);
 393 
 394   int max = storage->live_object_count;
 395   int i, dest;
 396   ObjectTrace** live_objects = storage->live_objects;
 397 
 398   for (i = 0, dest = 0; i < max; i++) {
 399     ObjectTrace* live_object = live_objects[i];
 400     jweak object = live_object->object;
 401 
 402     if (!(*jni)->IsSameObject(jni, object, NULL)) {
 403       if (dest != i) {
 404         live_objects[dest] = live_object;
 405         dest++;
 406       }
 407     } else {
 408       event_storage_add_garbage_collected_object(storage, live_object);
 409     }
 410   }
 411 
 412   storage->live_object_count = dest;
 413   pthread_mutex_unlock(&storage->storage_mutex);
 414 }
 415 
 416 static void event_storage_free_objects(ObjectTrace** array, int max) {
 417   int i;
 418   for (i = 0; i < max; i++) {
 419     free(array[i]), array[i] = NULL;
 420   }
 421 }
 422 
 423 static void event_storage_reset(EventStorage* storage) {
 424   pthread_mutex_lock(&storage->storage_mutex);
 425 
 426   // Reset everything except the mutex and the garbage collection.
 427   event_storage_free_objects(storage->live_objects,
 428                              storage->live_object_count);
 429   storage->live_object_size = 0;
 430   storage->live_object_count = 0;
 431   free(storage->live_objects), storage->live_objects = NULL;
 432 
 433   event_storage_free_objects(storage->garbage_collected_objects,
 434                              storage->garbage_history_size);
 435 
 436   storage->compaction_required = 0;
 437   storage->garbage_history_index = 0;
 438 
 439   pthread_mutex_unlock(&storage->storage_mutex);
 440 }
 441 
 442 // Start of the JVMTI agent code.
 443 
 444 static const char *EXC_CNAME = "java/lang/Exception";
 445 
 446 static int check_error(jvmtiError err, const char *s) {
 447   if (err != JVMTI_ERROR_NONE) {
 448     printf("  ## %s error: %d\n", s, err);
 449     return 1;
 450   }
 451   return 0;
 452 }
 453 
 454 static int check_capability_error(jvmtiError err, const char *s) {
 455   if (err != JVMTI_ERROR_NONE) {
 456     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 457       return 0;
 458     }
 459     printf("  ## %s error: %d\n", s, err);
 460     return 1;
 461   }
 462   return 1;
 463 }
 464 
 465 static
 466 jint throw_exc(JNIEnv *env, char *msg) {
 467   jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
 468 
 469   if (exc_class == NULL) {
 470     printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
 471     return -1;
 472   }
 473   return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
 474 }
 475 
 476 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 477 
 478 JNIEXPORT
 479 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 480   return Agent_Initialize(jvm, options, reserved);
 481 }
 482 
 483 JNIEXPORT
 484 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 485   return Agent_Initialize(jvm, options, reserved);
 486 }
 487 
 488 JNIEXPORT
 489 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 490   return JNI_VERSION_1_8;
 491 }
 492 
 493 JNIEXPORT
 494 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 495                                 JNIEnv* jni_env,
 496                                 jthread thread,
 497                                 jobject object,
 498                                 jclass object_klass,
 499                                 jlong size) {
 500   if (event_storage_get_compaction_required(&global_event_storage)) {
 501     event_storage_compact(&global_event_storage, jni_env);
 502   }
 503 
 504   event_storage_add(&global_event_storage, jni_env, thread, object,
 505                     object_klass, size);
 506 }
 507 
 508 JNIEXPORT
 509 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 510   event_storage_set_compaction_required(&global_event_storage);
 511 }
 512 
 513 static int enable_notifications() {
 514   if (check_error((*jvmti)->SetEventNotificationMode(
 515       jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 516                      "Set event notifications")) {
 517     return 1;
 518   }
 519 
 520   return check_error((*jvmti)->SetEventNotificationMode(
 521       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 522                      "Set event notifications");
 523 }
 524 
 525 static
 526 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 527   jint res;
 528 
 529   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 530                                  JVMTI_VERSION_9);
 531   if (res != JNI_OK || jvmti == NULL) {
 532     printf("    Error: wrong result of a valid call to GetEnv!\n");
 533     return JNI_ERR;
 534   }
 535 
 536   pthread_mutex_init(&global_event_storage.storage_mutex, 0);
 537   pthread_mutex_init(&global_event_storage.compaction_mutex, 0);
 538   event_storage_set_garbage_history(&global_event_storage, 200);
 539 
 540   jvmtiEventCallbacks callbacks;
 541   memset(&callbacks, 0, sizeof(callbacks));
 542   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 543   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 544 
 545   jvmtiCapabilities caps;
 546   memset(&caps, 0, sizeof(caps));
 547   // Get line numbers, sample heap, sample events, and filename for the test.
 548   caps.can_get_line_numbers = 1;
 549   caps.can_generate_sampled_alloc_events = 1;
 550   caps.can_get_source_file_name = 1;
 551   caps.can_generate_garbage_collection_events = 1;
 552   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){
 553     return JNI_ERR;
 554   }
 555 
 556  if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 557                                               sizeof(jvmtiEventCallbacks)),
 558                   " Set Event Callbacks")) {
 559     return JNI_ERR;
 560   }
 561   return JNI_OK;
 562 }
 563 
 564 JNIEXPORT void JNICALL
 565 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
 566   (*jvmti)->SetHeapSamplingRate(jvmti, value);
 567 }
 568 
 569 JNIEXPORT void JNICALL
 570 Java_MyPackage_HeapMonitor_setGarbageHistory(JNIEnv* env, jclass cls, jint value) {
 571   event_storage_set_garbage_history(&global_event_storage, value);
 572 }
 573 
 574 JNIEXPORT jboolean JNICALL
 575 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 576   return event_storage_get_count(&global_event_storage) == 0;
 577 }
 578 
 579 JNIEXPORT jint JNICALL
 580 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 581   return event_storage_get_count(&global_event_storage);
 582 }
 583 
 584 JNIEXPORT void JNICALL
 585 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 586   enable_notifications();
 587 }
 588 
 589 JNIEXPORT void JNICALL
 590 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 591   check_error((*jvmti)->SetEventNotificationMode(
 592       jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 593               "Set event notifications");
 594 
 595   check_error((*jvmti)->SetEventNotificationMode(
 596       jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 597               "Garbage Collection Finish");
 598 }
 599 
 600 JNIEXPORT jboolean JNICALL
 601 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
 602   jsize size = (*env)->GetArrayLength(env, frames);
 603   ExpectedContentFrame native_frames[size];
 604   fill_native_frames(env, frames, native_frames, size);
 605   return event_storage_contains(env, &global_event_storage, native_frames, size);
 606 }
 607 
 608 JNIEXPORT jboolean JNICALL
 609 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) {
 610   jsize size = (*env)->GetArrayLength(env, frames);
 611   ExpectedContentFrame native_frames[size];
 612   fill_native_frames(env, frames, native_frames, size);
 613   return event_storage_garbage_contains(env, &global_event_storage, native_frames, size);
 614 }
 615 
 616 JNIEXPORT void JNICALL
 617 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 618   check_error((*jvmti)->ForceGarbageCollection(jvmti),
 619               "Forced Garbage Collection");
 620 }
 621 
 622 JNIEXPORT void JNICALL
 623 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 624   return event_storage_reset(&global_event_storage);
 625 }
 626 
 627 JNIEXPORT jboolean JNICALL
 628 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 629                                                                   jclass cls) {
 630   jvmtiCapabilities caps;
 631   memset(&caps, 0, sizeof(caps));
 632   caps.can_generate_sampled_alloc_events = 1;
 633   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 634                   "Add capabilities\n")){
 635     return FALSE;
 636   }
 637 
 638   if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19),
 639                              "Set Heap Sampling Rate")) {
 640     return FALSE;
 641   }
 642   return TRUE;
 643 }
 644 
 645 JNIEXPORT jdouble JNICALL
 646 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 647   return event_storage_get_average_rate(&global_event_storage);
 648 }
 649 
 650 typedef struct sThreadsFound {
 651   jthread* threads;
 652   int num_threads;
 653 } ThreadsFound;
 654 
 655 static void find_threads_in_array(ThreadsFound* thread_data,
 656                                   ObjectTrace** array,
 657                                   int array_size) {
 658   int i;
 659   jthread* threads = thread_data->threads;
 660   int num_threads = thread_data->num_threads;
 661 
 662   for (i = 0; i < array_size; i++) {
 663     ObjectTrace* object = array[i];
 664 
 665     if (object == NULL) {
 666       continue;
 667     }
 668 
 669     // Check it is the right frame: only accept helper top framed traces.
 670     if (object->frame_count == 0) {
 671       continue;
 672     }
 673 
 674     jvmtiFrameInfo* frames = object->frames;
 675     jthread thread = object->thread;
 676 
 677     jmethodID methodid = frames[0].method;
 678     char *name = NULL, *signature = NULL, *file_name = NULL;
 679     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 680 
 681     if (strcmp(name, "helper")) {
 682       continue;
 683     }
 684 
 685     // Really not efficient look-up but it's for a test...
 686     int found = 0;
 687     int j;
 688     for (j = 0; j < num_threads; j++) {
 689       if (thread == threads[j]) {
 690         found = 1;
 691         break;
 692       }
 693     }
 694 
 695     if (!found) {
 696       threads[num_threads] = thread;
 697       num_threads++;
 698     }
 699   }
 700   thread_data->num_threads = num_threads;
 701 }
 702 
 703 JNIEXPORT jboolean JNICALL
 704 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 705                                                   jint num_threads) {
 706   pthread_mutex_lock(&global_event_storage.storage_mutex);
 707   jint trace_counter;
 708 
 709   ThreadsFound thread_data;
 710   thread_data.num_threads = 0;
 711   thread_data.threads = malloc(sizeof(jthread) * num_threads);
 712   memset(thread_data.threads, 0, sizeof(jthread) * num_threads);
 713 
 714   find_threads_in_array(&thread_data, global_event_storage.live_objects,
 715                         global_event_storage.live_object_count);
 716   find_threads_in_array(&thread_data,
 717                         global_event_storage.garbage_collected_objects,
 718                         global_event_storage.garbage_history_size);
 719 
 720   free(thread_data.threads);
 721   pthread_mutex_unlock(&global_event_storage.storage_mutex);
 722   return thread_data.num_threads == num_threads;
 723 }
 724 
 725 #ifdef __cplusplus
 726 }
 727 #endif