< prev index next >

test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitor.c

Print this page
rev 49244 : [mq]: event-only
rev 49246 : [mq]: event4
rev 49247 : [mq]: event5


   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 <stdio.h>
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include "jvmti.h"
  29 
  30 #ifdef __cplusplus
  31 extern "C" {
  32 #endif
  33 
  34 #ifndef JNI_ENV_ARG
  35 
  36 #ifdef __cplusplus
  37 #define JNI_ENV_ARG(x, y) y
  38 #define JNI_ENV_PTR(x) x
  39 #else
  40 #define JNI_ENV_ARG(x,y) x, y
  41 #define JNI_ENV_PTR(x) (*x)
  42 #endif
  43 
  44 #endif
  45 
  46 #define TRUE 1
  47 #define FALSE 0
  48 #define PRINT_OUT 1
  49 #define MAX_TRACES 400
  50 
  51 static jvmtiEnv *jvmti = NULL;
  52 
  53 typedef struct _LiveObjectTrace{


  54   jvmtiFrameInfo* frames;
  55   size_t frame_count;
  56 } LiveObjectTrace;

  57 
  58 typedef struct _EventStorage {

  59   int live_object_size;
  60   int live_object_count;
  61   LiveObjectTrace** live_objects;






  62 } EventStorage;
  63 
  64 typedef struct _ExpectedContentFrame {
  65   const char *name;
  66   const char *signature;
  67   const char *file_name;
  68   int line_number;
  69 } ExpectedContentFrame;
  70 
  71 // Given a method and a location, this method gets the line number.
  72 static
  73 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
  74                      jlocation location) {
  75   // Read the line number table.
  76   jvmtiLineNumberEntry *table_ptr = 0;
  77   jint line_number_table_entries;
  78   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
  79                                                  &line_number_table_entries,
  80                                                  &table_ptr);
  81 


  93   jint last_location = table_ptr[0].start_location;
  94   int l;
  95   for (l = 1; l < line_number_table_entries; l++) {
  96     // ... and if you see one that is in the right place for your
  97     // location, you've found the line number!
  98     if ((location < table_ptr[l].start_location) &&
  99         (location >= last_location)) {
 100       return table_ptr[l - 1].line_number;
 101     }
 102     last_location = table_ptr[l].start_location;
 103   }
 104 
 105   if (location >= last_location) {
 106     return table_ptr[line_number_table_entries - 1].line_number;
 107   } else {
 108     return -1;
 109   }
 110 }
 111 
 112 static jboolean check_sample_content(JNIEnv *env,
 113                                      LiveObjectTrace* trace,
 114                                      ExpectedContentFrame *expected,
 115                                      size_t expected_count,
 116                                      int print_out_comparisons) {
 117   if (expected_count > trace->frame_count) {
 118     return FALSE;
 119   }
 120 
 121   jvmtiFrameInfo* frames = trace->frames;
 122 
 123   size_t i;
 124   for (i = 0; i < expected_count; i++) {
 125     // Get basic information out of the trace.
 126     int bci = frames[i].location;
 127     jmethodID methodid = frames[i].method;
 128     char *name = NULL, *signature = NULL, *file_name = NULL;
 129 
 130     if (bci < 0) {
 131       return FALSE;
 132     }
 133 


 205                                    "Ljava/lang/String;");
 206     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 207     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 208 
 209     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 210                                    "Ljava/lang/String;");
 211     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 212     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 213 
 214     native_frames[i].name = method;
 215     native_frames[i].file_name = file_name;
 216     native_frames[i].signature = signature;
 217     native_frames[i].line_number = line_number;
 218   }
 219 }
 220 
 221 // Internal storage system implementation.
 222 
 223 static EventStorage global_event_storage;
 224 

































 225 static int event_storage_get_count(EventStorage* storage) {
 226   return storage->live_object_count;
















 227 }
 228 
 229 static jboolean event_storage_contains(JNIEnv* env,
 230                                        EventStorage* storage,
 231                                        ExpectedContentFrame* frames,
 232                                        size_t size) {

 233   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 234   int i;
 235   for (i = 0; i < storage->live_object_count; i++) {
 236     LiveObjectTrace* trace = storage->live_objects[i];
























 237 
 238     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {

 239       return TRUE;
 240     }
 241   }

 242   return FALSE;
 243 }
 244 

 245 static void event_storage_augment_storage(EventStorage* storage) {
 246   int new_max = (storage->live_object_size * 2) + 1;
 247   LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
 248 
 249   int current_count = storage->live_object_count;
 250   memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 251   free(storage->live_objects);
 252   storage->live_objects = new_objects;
 253 
 254   storage->live_object_size = new_max;
 255 }
 256 
 257 static void event_storage_add(EventStorage* storage,

 258                               jthread thread,
 259                               jobject object,
 260                               jclass klass,
 261                               jlong size) {
 262   jvmtiFrameInfo frames[64];
 263   jint count;
 264   jvmtiError err;

 265   err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
 266   if (err == JVMTI_ERROR_NONE && count >= 1) {


 267     if (storage->live_object_count >= storage->live_object_size) {
 268       event_storage_augment_storage(storage);
 269     }
 270     assert(storage->live_object_count < storage->live_object_size);
 271 
 272     jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames));
 273     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 274 
 275     LiveObjectTrace* live_object = malloc(sizeof(*live_object));
 276     live_object->frames = allocated_frames;
 277     live_object->frame_count = count;



 278     storage->live_objects[storage->live_object_count] = live_object;
 279     storage->live_object_count++;


 280   }
 281 }
 282 
 283 static void event_storage_reset(EventStorage* storage) {



 284   int max = storage->live_object_count;






















 285   int i;
 286   for (i = 0; i < max; i++) {
 287     LiveObjectTrace* object = storage->live_objects[i];
 288     free(object);
 289   }
 290   free(storage->live_objects);
 291   memset(storage, 0, sizeof(*storage));

















 292 }
 293 
 294 // Start of the JVMTI agent code.
 295 
 296 static const char *EXC_CNAME = "java/lang/Exception";
 297 
 298 static int check_error(jvmtiError err, const char *s) {
 299   if (err != JVMTI_ERROR_NONE) {
 300     printf("  ## %s error: %d\n", s, err);
 301     return 1;
 302   }
 303   return 0;
 304 }
 305 
 306 static int check_capability_error(jvmtiError err, const char *s) {
 307   if (err != JVMTI_ERROR_NONE) {
 308     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 309       return 0;
 310     }
 311     printf("  ## %s error: %d\n", s, err);


 332   return Agent_Initialize(jvm, options, reserved);
 333 }
 334 
 335 JNIEXPORT
 336 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 337   return Agent_Initialize(jvm, options, reserved);
 338 }
 339 
 340 JNIEXPORT
 341 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 342   return JNI_VERSION_1_8;
 343 }
 344 
 345 JNIEXPORT
 346 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 347                                 JNIEnv* jni_env,
 348                                 jthread thread,
 349                                 jobject object,
 350                                 jclass object_klass,
 351                                 jlong size) {
 352   event_storage_add(&global_event_storage, thread, object, object_klass, size);










 353 }
 354 
 355 static int enable_notifications() {






 356   return check_error((*jvmti)->SetEventNotificationMode(
 357       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 358                      "Set event notifications");
 359 }
 360 
 361 static
 362 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 363   jint res;
 364 
 365   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 366                                  JVMTI_VERSION_9);
 367   if (res != JNI_OK || jvmti == NULL) {
 368     printf("    Error: wrong result of a valid call to GetEnv!\n");
 369     return JNI_ERR;
 370   }
 371 



 372   jvmtiEventCallbacks callbacks;
 373   memset(&callbacks, 0, sizeof(callbacks));
 374   callbacks.SampledObjectAlloc = &SampledObjectAlloc;

 375 
 376   jvmtiCapabilities caps;
 377   memset(&caps, 0, sizeof(caps));
 378   // Get line numbers, sample heap, sample events, and filename for the test.
 379   caps.can_get_line_numbers = 1;
 380   caps.can_sample_heap = 1;
 381   caps.can_get_source_file_name = 1;

 382   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){
 383     return JNI_ERR;
 384   }
 385 
 386   if (enable_notifications()) {
 387     return JNI_ERR;
 388   }
 389 
 390   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 391                                               sizeof(jvmtiEventCallbacks)),
 392                   " Set Event Callbacks")) {
 393     return JNI_ERR;
 394   }
 395   return JNI_OK;
 396 }
 397 
 398 JNIEXPORT void JNICALL
 399 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
 400   (*jvmti)->SetTlabHeapSampling(jvmti, value);





 401 }
 402 
 403 JNIEXPORT jboolean JNICALL
 404 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 405   return event_storage_get_count(&global_event_storage) == 0;
 406 }
 407 





 408 JNIEXPORT void JNICALL
 409 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 410   enable_notifications();
 411 }
 412 
 413 JNIEXPORT void JNICALL
 414 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 415   check_error((*jvmti)->SetEventNotificationMode(
 416       jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 417               "Set event notifications");
 418 }
 419 
 420 JNIEXPORT void JNICALL
 421 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {

 422 }
 423 
 424 JNIEXPORT jboolean JNICALL
 425 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
 426   jsize size = (*env)->GetArrayLength(env, frames);
 427   ExpectedContentFrame native_frames[size];
 428   fill_native_frames(env, frames, native_frames, size);
 429   return event_storage_contains(env, &global_event_storage, native_frames, size);
 430 }
 431 














 432 JNIEXPORT void JNICALL
 433 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 434   return event_storage_reset(&global_event_storage);
 435 }
 436 
 437 JNIEXPORT jboolean JNICALL
 438 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 439                                                                   jclass cls) {
 440   jvmtiCapabilities caps;
 441   memset(&caps, 0, sizeof(caps));
 442   caps.can_sample_heap= 1;
 443   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 444                   "Add capabilities\n")){
 445     return FALSE;
 446   }
 447 
 448   if (check_capability_error((*jvmti)->SetTlabHeapSampling(jvmti, 1<<19),
 449                              "Set Tlab Heap Sampling")) {
 450     return FALSE;
 451   }
 452   return TRUE;
















































































 453 }
 454 
 455 #ifdef __cplusplus
 456 }
 457 #endif


   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 compaction_required;
  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   pthread_mutex_t mutex;
  73 } EventStorage;
  74 
  75 typedef struct _ExpectedContentFrame {
  76   const char *name;
  77   const char *signature;
  78   const char *file_name;
  79   int line_number;
  80 } ExpectedContentFrame;
  81 
  82 // Given a method and a location, this method gets the line number.
  83 static
  84 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
  85                      jlocation location) {
  86   // Read the line number table.
  87   jvmtiLineNumberEntry *table_ptr = 0;
  88   jint line_number_table_entries;
  89   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
  90                                                  &line_number_table_entries,
  91                                                  &table_ptr);
  92 


 104   jint last_location = table_ptr[0].start_location;
 105   int l;
 106   for (l = 1; l < line_number_table_entries; l++) {
 107     // ... and if you see one that is in the right place for your
 108     // location, you've found the line number!
 109     if ((location < table_ptr[l].start_location) &&
 110         (location >= last_location)) {
 111       return table_ptr[l - 1].line_number;
 112     }
 113     last_location = table_ptr[l].start_location;
 114   }
 115 
 116   if (location >= last_location) {
 117     return table_ptr[line_number_table_entries - 1].line_number;
 118   } else {
 119     return -1;
 120   }
 121 }
 122 
 123 static jboolean check_sample_content(JNIEnv *env,
 124                                      ObjectTrace* trace,
 125                                      ExpectedContentFrame *expected,
 126                                      size_t expected_count,
 127                                      int print_out_comparisons) {
 128   if (expected_count > trace->frame_count) {
 129     return FALSE;
 130   }
 131 
 132   jvmtiFrameInfo* frames = trace->frames;
 133 
 134   size_t i;
 135   for (i = 0; i < expected_count; i++) {
 136     // Get basic information out of the trace.
 137     int bci = frames[i].location;
 138     jmethodID methodid = frames[i].method;
 139     char *name = NULL, *signature = NULL, *file_name = NULL;
 140 
 141     if (bci < 0) {
 142       return FALSE;
 143     }
 144 


 216                                    "Ljava/lang/String;");
 217     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 218     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 219 
 220     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 221                                    "Ljava/lang/String;");
 222     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 223     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 224 
 225     native_frames[i].name = method;
 226     native_frames[i].file_name = file_name;
 227     native_frames[i].signature = signature;
 228     native_frames[i].line_number = line_number;
 229   }
 230 }
 231 
 232 // Internal storage system implementation.
 233 
 234 static EventStorage global_event_storage;
 235 
 236 static void event_storage_set_compaction_required(EventStorage* storage) {
 237   pthread_mutex_lock(&storage->mutex);
 238   storage->compaction_required = 1;
 239   pthread_mutex_unlock(&storage->mutex);
 240 }
 241 
 242 static int event_storage_get_compaction_required(EventStorage* storage) {
 243   pthread_mutex_lock(&storage->mutex);
 244   int result = storage->compaction_required;
 245   pthread_mutex_unlock(&storage->mutex);
 246   return result;
 247 }
 248 
 249 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
 250   pthread_mutex_lock(&storage->mutex);
 251   global_event_storage.garbage_history_size = value;
 252   free(global_event_storage.garbage_collected_objects);
 253   size_t size =
 254       sizeof(*global_event_storage.garbage_collected_objects) * value;
 255   global_event_storage.garbage_collected_objects = malloc(size);
 256   memset(global_event_storage.garbage_collected_objects, 0, size);
 257   pthread_mutex_unlock(&storage->mutex);
 258 }
 259 
 260 // No mutex here, it is handled by the caller.
 261 static void event_storage_add_garbage_collected_object(EventStorage* storage,
 262                                                        ObjectTrace* object) {
 263   int idx = storage->garbage_history_index;
 264   free(storage->garbage_collected_objects[idx]);
 265   storage->garbage_collected_objects[idx] = object;
 266   storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
 267 }
 268 
 269 static int event_storage_get_count(EventStorage* storage) {
 270   pthread_mutex_lock(&storage->mutex);
 271   int result = storage->live_object_count;
 272   pthread_mutex_unlock(&storage->mutex);
 273   return result;
 274 }
 275 
 276 static double event_storage_get_average_rate(EventStorage* storage) {
 277   double accumulation = 0;
 278 
 279   pthread_mutex_lock(&storage->mutex);
 280   int max_size = storage->live_object_count;
 281 
 282   for (int i = 0; i < max_size; i++) {
 283     accumulation += storage->live_objects[i]->size;
 284   }
 285   pthread_mutex_unlock(&storage->mutex);
 286   return accumulation / max_size;
 287 }
 288 
 289 static jboolean event_storage_contains(JNIEnv* env,
 290                                        EventStorage* storage,
 291                                        ExpectedContentFrame* frames,
 292                                        size_t size) {
 293   pthread_mutex_lock(&storage->mutex);
 294   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 295   int i;
 296   for (i = 0; i < storage->live_object_count; i++) {
 297     ObjectTrace* trace = storage->live_objects[i];
 298 
 299     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 300       pthread_mutex_unlock(&storage->mutex);
 301       return TRUE;
 302     }
 303   }
 304   pthread_mutex_unlock(&storage->mutex);
 305   return FALSE;
 306 }
 307 
 308 static jboolean event_storage_garbage_contains(JNIEnv* env,
 309                                                EventStorage* storage,
 310                                                ExpectedContentFrame* frames,
 311                                                size_t size) {
 312   pthread_mutex_lock(&storage->mutex);
 313   fprintf(stderr, "Checking garbage storage count %d\n",
 314           storage->garbage_history_size);
 315   int i;
 316   for (i = 0; i < storage->garbage_history_size; i++) {
 317     ObjectTrace* trace = storage->garbage_collected_objects[i];
 318 
 319     if (trace == NULL) {
 320       continue;
 321     }
 322 
 323     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 324       pthread_mutex_unlock(&storage->mutex);
 325       return TRUE;
 326     }
 327   }
 328   pthread_mutex_unlock(&storage->mutex);
 329   return FALSE;
 330 }
 331 
 332 // No mutex here, handled by the caller.
 333 static void event_storage_augment_storage(EventStorage* storage) {
 334   int new_max = (storage->live_object_size * 2) + 1;
 335   ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
 336 
 337   int current_count = storage->live_object_count;
 338   memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 339   free(storage->live_objects);
 340   storage->live_objects = new_objects;
 341 
 342   storage->live_object_size = new_max;
 343 }
 344 
 345 static void event_storage_add(EventStorage* storage,
 346                               JNIEnv* jni,
 347                               jthread thread,
 348                               jobject object,
 349                               jclass klass,
 350                               jlong size) {
 351   jvmtiFrameInfo frames[64];
 352   jint count;
 353   jvmtiError err;
 354 
 355   err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
 356   if (err == JVMTI_ERROR_NONE && count >= 1) {
 357     pthread_mutex_lock(&storage->mutex);
 358 
 359     if (storage->live_object_count >= storage->live_object_size) {
 360       event_storage_augment_storage(storage);
 361     }
 362     assert(storage->live_object_count < storage->live_object_size);
 363 
 364     jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames));
 365     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 366 
 367     ObjectTrace* live_object = malloc(sizeof(*live_object));
 368     live_object->frames = allocated_frames;
 369     live_object->frame_count = count;
 370     live_object->size = size;
 371     live_object->thread = thread;
 372     live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
 373     storage->live_objects[storage->live_object_count] = live_object;
 374     storage->live_object_count++;
 375 
 376     pthread_mutex_unlock(&storage->mutex);
 377   }
 378 }
 379 
 380 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 381   pthread_mutex_lock(&storage->mutex);
 382   storage->compaction_required = 0;
 383 
 384   int max = storage->live_object_count;
 385   int i, dest;
 386   ObjectTrace** live_objects = storage->live_objects;
 387 
 388   for (i = 0, dest = 0; i < max; i++) {
 389     ObjectTrace* live_object = live_objects[i];
 390     jweak object = live_object->object;
 391 
 392     if (!(*jni)->IsSameObject(jni, object, NULL)) {
 393       if (dest != i) {
 394         live_objects[dest] = live_object;
 395         dest++;
 396       }
 397     } else {
 398       event_storage_add_garbage_collected_object(storage, live_object);
 399     }
 400   }
 401 
 402   storage->live_object_count = dest;
 403   pthread_mutex_unlock(&storage->mutex);
 404 }
 405 
 406 static void event_storage_free_objects(ObjectTrace** array, int max) {
 407   int i;
 408   for (i = 0; i < max; i++) {
 409     free(array[i]), array[i] = NULL;

 410   }
 411 }
 412 
 413 static void event_storage_reset(EventStorage* storage) {
 414   pthread_mutex_lock(&storage->mutex);
 415 
 416   // Reset everything except the mutex and the garbage collection.
 417   event_storage_free_objects(storage->live_objects,
 418                              storage->live_object_count);
 419   storage->live_object_size = 0;
 420   storage->live_object_count = 0;
 421   free(storage->live_objects), storage->live_objects = NULL;
 422 
 423   event_storage_free_objects(storage->garbage_collected_objects,
 424                              storage->garbage_history_size);
 425 
 426   storage->compaction_required = 0;
 427   storage->garbage_history_index = 0;
 428 
 429   pthread_mutex_unlock(&storage->mutex);
 430 }
 431 
 432 // Start of the JVMTI agent code.
 433 
 434 static const char *EXC_CNAME = "java/lang/Exception";
 435 
 436 static int check_error(jvmtiError err, const char *s) {
 437   if (err != JVMTI_ERROR_NONE) {
 438     printf("  ## %s error: %d\n", s, err);
 439     return 1;
 440   }
 441   return 0;
 442 }
 443 
 444 static int check_capability_error(jvmtiError err, const char *s) {
 445   if (err != JVMTI_ERROR_NONE) {
 446     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 447       return 0;
 448     }
 449     printf("  ## %s error: %d\n", s, err);


 470   return Agent_Initialize(jvm, options, reserved);
 471 }
 472 
 473 JNIEXPORT
 474 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 475   return Agent_Initialize(jvm, options, reserved);
 476 }
 477 
 478 JNIEXPORT
 479 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 480   return JNI_VERSION_1_8;
 481 }
 482 
 483 JNIEXPORT
 484 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 485                                 JNIEnv* jni_env,
 486                                 jthread thread,
 487                                 jobject object,
 488                                 jclass object_klass,
 489                                 jlong size) {
 490   if (event_storage_get_compaction_required(&global_event_storage)) {
 491     event_storage_compact(&global_event_storage, jni_env);
 492   }
 493 
 494   event_storage_add(&global_event_storage, jni_env, thread, object,
 495                     object_klass, size);
 496 }
 497 
 498 JNIEXPORT
 499 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 500   event_storage_set_compaction_required(&global_event_storage);
 501 }
 502 
 503 static int enable_notifications() {
 504   if (check_error((*jvmti)->SetEventNotificationMode(
 505       jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 506                      "Set event notifications")) {
 507     return 1;
 508   }
 509 
 510   return check_error((*jvmti)->SetEventNotificationMode(
 511       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 512                      "Set event notifications");
 513 }
 514 
 515 static
 516 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 517   jint res;
 518 
 519   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 520                                  JVMTI_VERSION_9);
 521   if (res != JNI_OK || jvmti == NULL) {
 522     printf("    Error: wrong result of a valid call to GetEnv!\n");
 523     return JNI_ERR;
 524   }
 525 
 526   pthread_mutex_init(&global_event_storage.mutex, 0);
 527   event_storage_set_garbage_history(&global_event_storage, 200);
 528 
 529   jvmtiEventCallbacks callbacks;
 530   memset(&callbacks, 0, sizeof(callbacks));
 531   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 532   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 533 
 534   jvmtiCapabilities caps;
 535   memset(&caps, 0, sizeof(caps));
 536   // Get line numbers, sample heap, sample events, and filename for the test.
 537   caps.can_get_line_numbers = 1;
 538   caps.can_sample_heap = 1;
 539   caps.can_get_source_file_name = 1;
 540   caps.can_generate_garbage_collection_events = 1;
 541   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")){
 542     return JNI_ERR;
 543   }
 544 
 545   if (enable_notifications()) {
 546     return JNI_ERR;
 547   }
 548 
 549   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 550                                               sizeof(jvmtiEventCallbacks)),
 551                   " Set Event Callbacks")) {
 552     return JNI_ERR;
 553   }
 554   return JNI_OK;
 555 }
 556 
 557 JNIEXPORT void JNICALL
 558 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
 559   (*jvmti)->SetHeapSamplingRate(jvmti, value);
 560 }
 561 
 562 JNIEXPORT void JNICALL
 563 Java_MyPackage_HeapMonitor_setGarbageHistory(JNIEnv* env, jclass cls, jint value) {
 564   event_storage_set_garbage_history(&global_event_storage, value);
 565 }
 566 
 567 JNIEXPORT jboolean JNICALL
 568 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 569   return event_storage_get_count(&global_event_storage) == 0;
 570 }
 571 
 572 JNIEXPORT jint JNICALL
 573 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 574   return event_storage_get_count(&global_event_storage);
 575 }
 576 
 577 JNIEXPORT void JNICALL
 578 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 579   enable_notifications();
 580 }
 581 
 582 JNIEXPORT void JNICALL
 583 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 584   check_error((*jvmti)->SetEventNotificationMode(
 585       jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 586               "Set event notifications");

 587 
 588   check_error((*jvmti)->SetEventNotificationMode(
 589       jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 590               "Garbage Collection Finish");
 591 }
 592 
 593 JNIEXPORT jboolean JNICALL
 594 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
 595   jsize size = (*env)->GetArrayLength(env, frames);
 596   ExpectedContentFrame native_frames[size];
 597   fill_native_frames(env, frames, native_frames, size);
 598   return event_storage_contains(env, &global_event_storage, native_frames, size);
 599 }
 600 
 601 JNIEXPORT jboolean JNICALL
 602 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) {
 603   jsize size = (*env)->GetArrayLength(env, frames);
 604   ExpectedContentFrame native_frames[size];
 605   fill_native_frames(env, frames, native_frames, size);
 606   return event_storage_garbage_contains(env, &global_event_storage, native_frames, size);
 607 }
 608 
 609 JNIEXPORT void JNICALL
 610 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 611   check_error((*jvmti)->ForceGarbageCollection(jvmti),
 612               "Forced Garbage Collection");
 613 }
 614 
 615 JNIEXPORT void JNICALL
 616 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 617   return event_storage_reset(&global_event_storage);
 618 }
 619 
 620 JNIEXPORT jboolean JNICALL
 621 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 622                                                                   jclass cls) {
 623   jvmtiCapabilities caps;
 624   memset(&caps, 0, sizeof(caps));
 625   caps.can_sample_heap= 1;
 626   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 627                   "Add capabilities\n")){
 628     return FALSE;
 629   }
 630 
 631   if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19),
 632                              "Set Heap Sampling Rate")) {
 633     return FALSE;
 634   }
 635   return TRUE;
 636 }
 637 
 638 JNIEXPORT jdouble JNICALL
 639 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 640   return event_storage_get_average_rate(&global_event_storage);
 641 }
 642 
 643 typedef struct sThreadsFound {
 644   jthread* threads;
 645   int num_threads;
 646 } ThreadsFound;
 647 
 648 static void find_threads_in_array(ThreadsFound* thread_data,
 649                                   ObjectTrace** array,
 650                                   int array_size) {
 651   int i;
 652   jthread* threads = thread_data->threads;
 653   int num_threads = thread_data->num_threads;
 654 
 655   for (i = 0; i < array_size; i++) {
 656     ObjectTrace* object = array[i];
 657 
 658     if (object == NULL) {
 659       continue;
 660     }
 661 
 662     // Check it is the right frame: only accept helper top framed traces.
 663     if (object->frame_count == 0) {
 664       continue;
 665     }
 666 
 667     jvmtiFrameInfo* frames = object->frames;
 668     jthread thread = object->thread;
 669 
 670     jmethodID methodid = frames[0].method;
 671     char *name = NULL, *signature = NULL, *file_name = NULL;
 672     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 673 
 674     if (strcmp(name, "helper")) {
 675       continue;
 676     }
 677 
 678     // Really not efficient look-up but it's for a test...
 679     int found = 0;
 680     int j;
 681     for (j = 0; j < num_threads; j++) {
 682       if (thread == threads[j]) {
 683         found = 1;
 684         break;
 685       }
 686     }
 687 
 688     if (!found) {
 689       threads[num_threads] = thread;
 690       num_threads++;
 691     }
 692   }
 693   thread_data->num_threads = num_threads;
 694 }
 695 
 696 JNIEXPORT jboolean JNICALL
 697 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 698                                                   jint num_threads) {
 699   pthread_mutex_lock(&global_event_storage.mutex);
 700   jint trace_counter;
 701 
 702   ThreadsFound thread_data;
 703   thread_data.num_threads = 0;
 704   thread_data.threads = malloc(sizeof(jthread) * num_threads);
 705   memset(thread_data.threads, 0, sizeof(jthread) * num_threads);
 706 
 707   find_threads_in_array(&thread_data, global_event_storage.live_objects,
 708                         global_event_storage.live_object_count);
 709   find_threads_in_array(&thread_data,
 710                         global_event_storage.garbage_collected_objects,
 711                         global_event_storage.garbage_history_size);
 712 
 713   free(thread_data.threads);
 714   pthread_mutex_unlock(&global_event_storage.mutex);
 715   return thread_data.num_threads == num_threads;
 716 }
 717 
 718 #ifdef __cplusplus
 719 }
 720 #endif
< prev index next >