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