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
|