Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp
41153 views
1
/*
2
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2018, Google and/or its affiliates. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*/
24
25
#include <assert.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include "jvmti.h"
30
31
extern "C" {
32
33
#define TRUE 1
34
#define FALSE 0
35
#define PRINT_OUT 0
36
37
static jvmtiEnv *jvmti = NULL;
38
static jvmtiEnv *second_jvmti = NULL;
39
40
typedef struct _ObjectTrace{
41
jweak object;
42
jlong size;
43
jvmtiFrameInfo* frames;
44
size_t frame_count;
45
jthread thread;
46
} ObjectTrace;
47
48
typedef struct _EventStorage {
49
int live_object_additions;
50
int live_object_size;
51
int live_object_count;
52
ObjectTrace** live_objects;
53
54
int garbage_history_size;
55
int garbage_history_index;
56
ObjectTrace** garbage_collected_objects;
57
58
// Two separate monitors to separate storage data race and the compaction field
59
// data race.
60
jrawMonitorID storage_monitor;
61
62
int compaction_required;
63
jrawMonitorID compaction_monitor;
64
} EventStorage;
65
66
typedef struct _ExpectedContentFrame {
67
const char *name;
68
const char *signature;
69
const char *file_name;
70
int line_number;
71
} ExpectedContentFrame;
72
73
static
74
void event_storage_lock(EventStorage* storage) {
75
jvmti->RawMonitorEnter(storage->storage_monitor);
76
}
77
78
static
79
void event_storage_unlock(EventStorage* storage) {
80
jvmti->RawMonitorExit(storage->storage_monitor);
81
}
82
83
static
84
void event_storage_lock_compaction(EventStorage* storage) {
85
jvmti->RawMonitorEnter(storage->compaction_monitor);
86
}
87
88
static
89
void event_storage_unlock_compaction(EventStorage* storage) {
90
jvmti->RawMonitorExit(storage->compaction_monitor);
91
}
92
93
// Given a method and a location, this method gets the line number.
94
static
95
jint get_line_number(jmethodID method, jlocation location) {
96
// Read the line number table.
97
jvmtiLineNumberEntry *table_ptr = 0;
98
jint line_number_table_entries;
99
int l;
100
jlocation last_location;
101
int jvmti_error = jvmti->GetLineNumberTable(method,
102
&line_number_table_entries,
103
&table_ptr);
104
105
if (JVMTI_ERROR_NONE != jvmti_error) {
106
return -1;
107
}
108
if (line_number_table_entries <= 0) {
109
return -1;
110
}
111
if (line_number_table_entries == 1) {
112
return table_ptr[0].line_number;
113
}
114
115
// Go through all the line numbers...
116
last_location = table_ptr[0].start_location;
117
for (l = 1; l < line_number_table_entries; l++) {
118
// ... and if you see one that is in the right place for your
119
// location, you've found the line number!
120
if ((location < table_ptr[l].start_location) &&
121
(location >= last_location)) {
122
return table_ptr[l - 1].line_number;
123
}
124
last_location = table_ptr[l].start_location;
125
}
126
127
if (location >= last_location) {
128
return table_ptr[line_number_table_entries - 1].line_number;
129
} else {
130
return -1;
131
}
132
}
133
134
static void print_out_frames(JNIEnv* env, ObjectTrace* trace) {
135
jvmtiFrameInfo* frames = trace->frames;
136
size_t i;
137
for (i = 0; i < trace->frame_count; i++) {
138
// Get basic information out of the trace.
139
jlocation bci = frames[i].location;
140
jmethodID methodid = frames[i].method;
141
char *name = NULL, *signature = NULL, *file_name = NULL;
142
jclass declaring_class;
143
int line_number;
144
jvmtiError err;
145
146
if (bci < 0) {
147
fprintf(stderr, "\tNative frame\n");
148
continue;
149
}
150
151
// Transform into usable information.
152
line_number = get_line_number(methodid, bci);
153
if (JVMTI_ERROR_NONE != jvmti->GetMethodName(methodid, &name, &signature, 0)) {
154
fprintf(stderr, "\tUnknown method name\n");
155
continue;
156
}
157
158
if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {
159
fprintf(stderr, "\tUnknown class\n");
160
continue;
161
}
162
163
err = jvmti->GetSourceFileName(declaring_class, &file_name);
164
if (err != JVMTI_ERROR_NONE) {
165
fprintf(stderr, "\tUnknown file\n");
166
continue;
167
}
168
169
// Compare now, none should be NULL.
170
if (name == NULL) {
171
fprintf(stderr, "\tUnknown name\n");
172
continue;
173
}
174
175
if (file_name == NULL) {
176
fprintf(stderr, "\tUnknown file\n");
177
continue;
178
}
179
180
if (signature == NULL) {
181
fprintf(stderr, "\tUnknown signature\n");
182
continue;
183
}
184
185
fprintf(stderr, "\t%s%s (%s: %d)\n", name, signature, file_name, line_number);
186
}
187
}
188
189
static jboolean check_sample_content(JNIEnv* env,
190
ObjectTrace* trace,
191
ExpectedContentFrame *expected,
192
size_t expected_count,
193
jboolean check_lines,
194
int print_out_comparisons) {
195
jvmtiFrameInfo* frames;
196
size_t i;
197
198
if (expected_count > trace->frame_count) {
199
return FALSE;
200
}
201
202
frames = trace->frames;
203
for (i = 0; i < expected_count; i++) {
204
// Get basic information out of the trace.
205
jlocation bci = frames[i].location;
206
jmethodID methodid = frames[i].method;
207
char *name = NULL, *signature = NULL, *file_name = NULL;
208
jclass declaring_class;
209
int line_number;
210
jboolean differ;
211
jvmtiError err;
212
213
if (bci < 0 && expected[i].line_number != -1) {
214
return FALSE;
215
}
216
217
// Transform into usable information.
218
line_number = get_line_number(methodid, bci);
219
jvmti->GetMethodName(methodid, &name, &signature, 0);
220
221
if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {
222
return FALSE;
223
}
224
225
err = jvmti->GetSourceFileName(declaring_class, &file_name);
226
if (err != JVMTI_ERROR_NONE) {
227
return FALSE;
228
}
229
230
// Compare now, none should be NULL.
231
if (name == NULL) {
232
return FALSE;
233
}
234
235
if (file_name == NULL) {
236
return FALSE;
237
}
238
239
if (signature == NULL) {
240
return FALSE;
241
}
242
243
differ = (strcmp(name, expected[i].name) ||
244
strcmp(signature, expected[i].signature) ||
245
strcmp(file_name, expected[i].file_name) ||
246
(check_lines && line_number != expected[i].line_number));
247
248
if (print_out_comparisons) {
249
fprintf(stderr, "\tComparing: (check_lines: %d)\n", check_lines);
250
fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
251
fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
252
fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
253
fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
254
fprintf(stderr, "\t\tResult is %d\n", differ);
255
}
256
257
if (differ) {
258
return FALSE;
259
}
260
}
261
262
return TRUE;
263
}
264
265
// Static native API for various tests.
266
static int fill_native_frames(JNIEnv* env, jobjectArray frames,
267
ExpectedContentFrame* native_frames, size_t size) {
268
size_t i;
269
for (i = 0; i < size; i++) {
270
jclass frame_class = NULL;
271
jfieldID line_number_field_id = 0;
272
int line_number = 0;
273
jfieldID string_id = 0;
274
jstring string_object = NULL;
275
const char* method = NULL;
276
const char* file_name = NULL;
277
const char* signature = NULL;
278
279
jobject obj = env->GetObjectArrayElement(frames, (jsize) i);
280
281
if (env->ExceptionOccurred()) {
282
fprintf(stderr, "fill_native_frames: Exception in jni GetObjectArrayElement\n");
283
return -1;
284
}
285
286
frame_class = env->GetObjectClass(obj);
287
288
if (env->ExceptionOccurred()) {
289
fprintf(stderr, "fill_native_frames: Exception in jni GetObjectClass\n");
290
return -1;
291
}
292
293
line_number_field_id = env->GetFieldID(frame_class, "lineNumber", "I");
294
295
if (env->ExceptionOccurred()) {
296
fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
297
return -1;
298
}
299
300
line_number = env->GetIntField(obj, line_number_field_id);
301
302
if (env->ExceptionOccurred()) {
303
fprintf(stderr, "fill_native_frames: Exception in jni GetIntField\n");
304
return -1;
305
}
306
307
string_id = env->GetFieldID(frame_class, "method", "Ljava/lang/String;");
308
309
if (env->ExceptionOccurred()) {
310
fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
311
return -1;
312
}
313
314
string_object = (jstring) env->GetObjectField(obj, string_id);
315
316
if (env->ExceptionOccurred()) {
317
fprintf(stderr, "fill_native_frames: Exception in jni GetObjectField\n");
318
return -1;
319
}
320
321
method = env->GetStringUTFChars(string_object, 0);
322
323
if (env->ExceptionOccurred()) {
324
fprintf(stderr, "Exception in jni GetStringUTFChars\n");
325
return -1;
326
}
327
328
string_id = env->GetFieldID(frame_class, "fileName", "Ljava/lang/String;");
329
330
if (env->ExceptionOccurred()) {
331
fprintf(stderr, "Exception in jni GetFieldID\n");
332
return -1;
333
}
334
335
string_object = (jstring) (env->GetObjectField(obj, string_id));
336
337
if (env->ExceptionOccurred()) {
338
fprintf(stderr, "fill_native_frames: Exception in second jni GetObjectField\n");
339
return -1;
340
}
341
342
file_name = env->GetStringUTFChars(string_object, 0);
343
344
if (env->ExceptionOccurred()) {
345
fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
346
return -1;
347
}
348
349
string_id = env->GetFieldID(frame_class, "signature", "Ljava/lang/String;");
350
351
if (env->ExceptionOccurred()) {
352
fprintf(stderr, "fill_native_frames: Exception in second jni GetFieldID\n");
353
return -1;
354
}
355
356
string_object = (jstring) (env->GetObjectField(obj, string_id));
357
358
if (env->ExceptionOccurred()) {
359
fprintf(stderr, "fill_native_frames: Exception in third jni GetObjectField\n");
360
return -1;
361
}
362
363
signature = env->GetStringUTFChars(string_object, 0);
364
365
if (env->ExceptionOccurred()) {
366
fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
367
return -1;
368
}
369
370
native_frames[i].name = method;
371
native_frames[i].file_name = file_name;
372
native_frames[i].signature = signature;
373
native_frames[i].line_number = line_number;
374
}
375
376
return 0;
377
}
378
379
// Internal storage system implementation.
380
static EventStorage global_event_storage;
381
static EventStorage second_global_event_storage;
382
383
static void event_storage_set_compaction_required(EventStorage* storage) {
384
event_storage_lock_compaction(storage);
385
storage->compaction_required = 1;
386
event_storage_unlock_compaction(storage);
387
}
388
389
static int event_storage_get_compaction_required(EventStorage* storage) {
390
int result;
391
event_storage_lock_compaction(storage);
392
result = storage->compaction_required;
393
event_storage_unlock_compaction(storage);
394
return result;
395
}
396
397
static void event_storage_set_garbage_history(EventStorage* storage, int value) {
398
size_t size;
399
event_storage_lock(storage);
400
global_event_storage.garbage_history_size = value;
401
free(global_event_storage.garbage_collected_objects);
402
size = sizeof(*global_event_storage.garbage_collected_objects) * value;
403
global_event_storage.garbage_collected_objects = reinterpret_cast<ObjectTrace**>(malloc(size));
404
memset(global_event_storage.garbage_collected_objects, 0, size);
405
event_storage_unlock(storage);
406
}
407
408
// No mutex here, it is handled by the caller.
409
static void event_storage_add_garbage_collected_object(EventStorage* storage,
410
ObjectTrace* object) {
411
int idx = storage->garbage_history_index;
412
ObjectTrace* old_object = storage->garbage_collected_objects[idx];
413
if (old_object != NULL) {
414
free(old_object->frames);
415
free(storage->garbage_collected_objects[idx]);
416
}
417
418
storage->garbage_collected_objects[idx] = object;
419
storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
420
}
421
422
static int event_storage_get_count(EventStorage* storage) {
423
int result;
424
event_storage_lock(storage);
425
result = storage->live_object_count;
426
event_storage_unlock(storage);
427
return result;
428
}
429
430
static double event_storage_get_average_size(EventStorage* storage) {
431
double accumulation = 0;
432
int max_size;
433
int i;
434
435
event_storage_lock(storage);
436
max_size = storage->live_object_count;
437
438
for (i = 0; i < max_size; i++) {
439
accumulation += storage->live_objects[i]->size;
440
}
441
442
event_storage_unlock(storage);
443
return accumulation / max_size;
444
}
445
446
static jboolean event_storage_contains(JNIEnv* env,
447
EventStorage* storage,
448
ExpectedContentFrame* frames,
449
size_t size,
450
jboolean check_lines) {
451
int i;
452
event_storage_lock(storage);
453
fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
454
for (i = 0; i < storage->live_object_count; i++) {
455
ObjectTrace* trace = storage->live_objects[i];
456
457
if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
458
event_storage_unlock(storage);
459
return TRUE;
460
}
461
}
462
event_storage_unlock(storage);
463
return FALSE;
464
}
465
466
static jlong event_storage_get_size(JNIEnv* env,
467
EventStorage* storage,
468
ExpectedContentFrame* frames,
469
size_t size,
470
jboolean check_lines) {
471
int i;
472
event_storage_lock(storage);
473
fprintf(stderr, "Getting element from storage count, size %d\n", storage->live_object_count);
474
for (i = 0; i < storage->live_object_count; i++) {
475
ObjectTrace* trace = storage->live_objects[i];
476
477
if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
478
jlong result = trace->size;
479
event_storage_unlock(storage);
480
return result;
481
}
482
}
483
event_storage_unlock(storage);
484
return 0;
485
}
486
487
static jboolean event_storage_garbage_contains(JNIEnv* env,
488
EventStorage* storage,
489
ExpectedContentFrame* frames,
490
size_t size,
491
jboolean check_lines) {
492
int i;
493
event_storage_lock(storage);
494
fprintf(stderr, "Checking garbage storage count %d\n",
495
storage->garbage_history_size);
496
for (i = 0; i < storage->garbage_history_size; i++) {
497
ObjectTrace* trace = storage->garbage_collected_objects[i];
498
499
if (trace == NULL) {
500
continue;
501
}
502
503
if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
504
event_storage_unlock(storage);
505
return TRUE;
506
}
507
}
508
event_storage_unlock(storage);
509
return FALSE;
510
}
511
512
// No mutex here, handled by the caller.
513
static void event_storage_augment_storage(EventStorage* storage) {
514
int new_max = (storage->live_object_size * 2) + 1;
515
ObjectTrace** new_objects = reinterpret_cast<ObjectTrace**>(malloc(new_max * sizeof(*new_objects)));
516
517
int current_count = storage->live_object_count;
518
memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
519
free(storage->live_objects);
520
storage->live_objects = new_objects;
521
storage->live_object_size = new_max;
522
}
523
524
static void event_storage_add(EventStorage* storage,
525
JNIEnv* jni,
526
jthread thread,
527
jobject object,
528
jclass klass,
529
jlong size) {
530
jvmtiFrameInfo frames[64];
531
jint count;
532
jvmtiError err;
533
534
err = jvmti->GetStackTrace(thread, 0, 64, frames, &count);
535
if (err == JVMTI_ERROR_NONE && count >= 1) {
536
ObjectTrace* live_object;
537
jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
538
memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
539
540
live_object = (ObjectTrace*) malloc(sizeof(*live_object));
541
live_object->frames = allocated_frames;
542
live_object->frame_count = count;
543
live_object->size = size;
544
live_object->thread = thread;
545
live_object->object = jni->NewWeakGlobalRef(object);
546
547
if (jni->ExceptionOccurred()) {
548
jni->FatalError("Error in event_storage_add: Exception in jni NewWeakGlobalRef");
549
}
550
551
// Only now lock and get things done quickly.
552
event_storage_lock(storage);
553
554
storage->live_object_additions++;
555
556
if (storage->live_object_count >= storage->live_object_size) {
557
event_storage_augment_storage(storage);
558
}
559
assert(storage->live_object_count < storage->live_object_size);
560
561
if (PRINT_OUT) {
562
fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n",
563
thread, count, storage);
564
print_out_frames(jni, live_object);
565
}
566
storage->live_objects[storage->live_object_count] = live_object;
567
storage->live_object_count++;
568
569
event_storage_unlock(storage);
570
}
571
}
572
573
static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
574
int max, i, dest;
575
ObjectTrace** live_objects;
576
577
event_storage_lock_compaction(storage);
578
storage->compaction_required = 0;
579
event_storage_unlock_compaction(storage);
580
581
event_storage_lock(storage);
582
583
max = storage->live_object_count;
584
live_objects = storage->live_objects;
585
586
for (i = 0, dest = 0; i < max; i++) {
587
ObjectTrace* live_object = live_objects[i];
588
jweak object = live_object->object;
589
590
if (!jni->IsSameObject(object, NULL)) {
591
if (dest != i) {
592
live_objects[dest] = live_object;
593
dest++;
594
}
595
} else {
596
jni->DeleteWeakGlobalRef(object);
597
live_object->object = NULL;
598
599
event_storage_add_garbage_collected_object(storage, live_object);
600
}
601
}
602
603
storage->live_object_count = dest;
604
event_storage_unlock(storage);
605
}
606
607
static void event_storage_free_objects(ObjectTrace** array, int max) {
608
int i;
609
for (i = 0; i < max; i++) {
610
free(array[i]), array[i] = NULL;
611
}
612
}
613
614
static void event_storage_reset(EventStorage* storage) {
615
event_storage_lock(storage);
616
617
// Reset everything except the mutex and the garbage collection.
618
event_storage_free_objects(storage->live_objects,
619
storage->live_object_count);
620
storage->live_object_additions = 0;
621
storage->live_object_size = 0;
622
storage->live_object_count = 0;
623
free(storage->live_objects), storage->live_objects = NULL;
624
625
event_storage_free_objects(storage->garbage_collected_objects,
626
storage->garbage_history_size);
627
628
storage->compaction_required = 0;
629
storage->garbage_history_index = 0;
630
631
event_storage_unlock(storage);
632
}
633
634
static int event_storage_number_additions(EventStorage* storage) {
635
int result;
636
event_storage_lock(storage);
637
result = storage->live_object_additions;
638
event_storage_unlock(storage);
639
return result;
640
}
641
642
// Start of the JVMTI agent code.
643
static const char *EXC_CNAME = "java/lang/Exception";
644
645
static int check_error(jvmtiError err, const char *s) {
646
if (err != JVMTI_ERROR_NONE) {
647
printf(" ## %s error: %d\n", s, err);
648
return 1;
649
}
650
return 0;
651
}
652
653
static int check_capability_error(jvmtiError err, const char *s) {
654
if (err != JVMTI_ERROR_NONE) {
655
if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
656
return 0;
657
}
658
fprintf(stderr, " ## %s error: %d\n", s, err);
659
}
660
return 1;
661
}
662
663
static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
664
665
JNIEXPORT
666
jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
667
return Agent_Initialize(jvm, options, reserved);
668
}
669
670
JNIEXPORT
671
jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
672
return Agent_Initialize(jvm, options, reserved);
673
}
674
675
JNIEXPORT
676
jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
677
return JNI_VERSION_1_8;
678
}
679
680
#define MAX_THREADS 500
681
682
typedef struct ThreadStats {
683
int thread_count;
684
int counts[MAX_THREADS];
685
char* threads[MAX_THREADS];
686
} ThreadStats;
687
688
static ThreadStats thread_stats;
689
690
JNIEXPORT jboolean JNICALL
691
Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(
692
JNIEnv* env, jclass cls, jthread thread) {
693
jvmtiThreadInfo info;
694
jvmtiError err;
695
char* expected_name;
696
int found_thread = FALSE;
697
698
err = jvmti->GetThreadInfo(thread, &info);
699
expected_name = info.name;
700
701
if (err != JVMTI_ERROR_NONE) {
702
fprintf(stderr, "Failed to get thread information\n");
703
return FALSE;
704
}
705
706
if (thread_stats.thread_count != 1) {
707
fprintf(stderr, "Wrong thread number: %d (expected 1)\n",
708
thread_stats.thread_count);
709
return FALSE;
710
}
711
712
if (strcmp(expected_name, thread_stats.threads[0]) != 0) {
713
fprintf(stderr, "Unexpected thread name: '%s' (expected '%s')\n",
714
thread_stats.threads[0], expected_name);
715
return FALSE;
716
}
717
718
return TRUE;
719
}
720
721
static void add_thread_count(jthread thread) {
722
int i;
723
jvmtiThreadInfo info;
724
jvmtiError err;
725
726
err = jvmti->GetThreadInfo(thread, &info);
727
if (err != JVMTI_ERROR_NONE) {
728
fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",
729
thread);
730
return;
731
}
732
733
event_storage_lock(&global_event_storage);
734
for (i = 0; i < thread_stats.thread_count; i++) {
735
if (!strcmp(thread_stats.threads[i], info.name)) {
736
thread_stats.counts[i]++;
737
event_storage_unlock(&global_event_storage);
738
return;
739
}
740
}
741
742
thread_stats.threads[thread_stats.thread_count] = info.name;
743
thread_stats.counts[thread_stats.thread_count]++;
744
thread_stats.thread_count++;
745
event_storage_unlock(&global_event_storage);
746
}
747
748
JNIEXPORT void JNICALL
749
Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(
750
JNIEnv* env, jclass cls, jthread thread) {
751
fprintf(stderr, "Enabling for %p\n", thread);
752
check_error(jvmti->SetEventNotificationMode(
753
JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),
754
"Set event notifications for a single thread");
755
}
756
757
static void print_thread_stats() {
758
int i;
759
event_storage_lock(&global_event_storage);
760
fprintf(stderr, "Thread count:\n");
761
for (i = 0; i < thread_stats.thread_count; i++) {
762
fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);
763
}
764
event_storage_unlock(&global_event_storage);
765
}
766
767
JNIEXPORT
768
void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
769
JNIEnv* jni_env,
770
jthread thread,
771
jobject object,
772
jclass object_klass,
773
jlong size) {
774
add_thread_count(thread);
775
776
if (event_storage_get_compaction_required(&global_event_storage)) {
777
event_storage_compact(&global_event_storage, jni_env);
778
}
779
780
event_storage_add(&global_event_storage, jni_env, thread, object,
781
object_klass, size);
782
}
783
784
JNIEXPORT
785
void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
786
JNIEnv* jni_env,
787
jthread thread,
788
jobject object,
789
jclass object_klass,
790
jlong size) {
791
event_storage_add(&second_global_event_storage, jni_env, thread, object,
792
object_klass, size);
793
}
794
795
JNIEXPORT
796
void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
797
event_storage_set_compaction_required(&global_event_storage);
798
}
799
800
static int enable_notifications() {
801
if (check_error(jvmti->SetEventNotificationMode(
802
JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
803
"Set event notifications")) {
804
return 1;
805
}
806
807
return check_error(jvmti->SetEventNotificationMode(
808
JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
809
"Set event notifications");
810
}
811
812
static
813
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
814
jint res;
815
jvmtiEventCallbacks callbacks;
816
jvmtiCapabilities caps;
817
818
res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION);
819
if (res != JNI_OK || jvmti == NULL) {
820
fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
821
return JNI_ERR;
822
}
823
824
// Get second jvmti environment.
825
res = jvm->GetEnv((void **) &second_jvmti, JVMTI_VERSION);
826
if (res != JNI_OK || second_jvmti == NULL) {
827
fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
828
return JNI_ERR;
829
}
830
831
if (PRINT_OUT) {
832
fprintf(stderr, "Storage is at %p, secondary is at %p\n",
833
&global_event_storage, &second_global_event_storage);
834
}
835
836
jvmti->CreateRawMonitor("storage_monitor",
837
&global_event_storage.storage_monitor);
838
jvmti->CreateRawMonitor("second_storage_monitor",
839
&second_global_event_storage.storage_monitor);
840
841
jvmti->CreateRawMonitor("compaction_monitor",
842
&global_event_storage.compaction_monitor);
843
jvmti->CreateRawMonitor("second_compaction_monitor",
844
&second_global_event_storage.compaction_monitor);
845
846
event_storage_set_garbage_history(&global_event_storage, 200);
847
event_storage_set_garbage_history(&second_global_event_storage, 200);
848
849
memset(&callbacks, 0, sizeof(callbacks));
850
callbacks.SampledObjectAlloc = &SampledObjectAlloc;
851
callbacks.VMObjectAlloc = &VMObjectAlloc;
852
callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
853
854
memset(&caps, 0, sizeof(caps));
855
// Get line numbers, sample events, filename, and gc events for the tests.
856
caps.can_get_line_numbers = 1;
857
caps.can_get_source_file_name = 1;
858
caps.can_generate_garbage_collection_events = 1;
859
caps.can_generate_sampled_object_alloc_events = 1;
860
caps.can_generate_vm_object_alloc_events = 1;
861
if (check_error(jvmti->AddCapabilities(&caps), "Add capabilities")) {
862
return JNI_ERR;
863
}
864
865
if (check_error(jvmti->SetEventCallbacks(&callbacks,
866
sizeof(jvmtiEventCallbacks)),
867
" Set Event Callbacks")) {
868
return JNI_ERR;
869
}
870
return JNI_OK;
871
}
872
873
JNIEXPORT void JNICALL
874
Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
875
jvmti->SetHeapSamplingInterval(value);
876
}
877
878
JNIEXPORT jboolean JNICALL
879
Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
880
return event_storage_get_count(&global_event_storage) == 0;
881
}
882
883
JNIEXPORT jint JNICALL
884
Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
885
return event_storage_get_count(&global_event_storage);
886
}
887
888
JNIEXPORT void JNICALL
889
Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
890
enable_notifications();
891
}
892
893
JNIEXPORT void JNICALL
894
Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
895
check_error(jvmti->SetEventNotificationMode(
896
JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
897
"Set event notifications");
898
899
check_error(jvmti->SetEventNotificationMode(
900
JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
901
"Garbage Collection Finish");
902
}
903
904
static ExpectedContentFrame *get_native_frames(JNIEnv* env, jclass cls,
905
jobjectArray frames) {
906
ExpectedContentFrame *native_frames;
907
jsize size = env->GetArrayLength(frames);
908
909
if (env->ExceptionOccurred()) {
910
env->FatalError("get_native_frames failed with the GetArrayLength call");
911
}
912
913
native_frames = reinterpret_cast<ExpectedContentFrame*> (malloc(size * sizeof(*native_frames)));
914
915
if (native_frames == NULL) {
916
env->FatalError("Error in get_native_frames: malloc returned NULL\n");
917
}
918
919
if (fill_native_frames(env, frames, native_frames, size) != 0) {
920
env->FatalError("Error in get_native_frames: fill_native_frames returned failed status\n");
921
}
922
923
return native_frames;
924
}
925
926
JNIEXPORT jboolean JNICALL
927
Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
928
jobjectArray frames,
929
jboolean check_lines) {
930
jboolean result;
931
jsize size = env->GetArrayLength(frames);
932
ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
933
934
result = event_storage_contains(env, &global_event_storage, native_frames,
935
size, check_lines);
936
937
free(native_frames), native_frames = NULL;
938
return result;
939
}
940
941
JNIEXPORT jboolean JNICALL
942
Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls,
943
jobjectArray frames,
944
jboolean check_lines) {
945
jboolean result;
946
jsize size = env->GetArrayLength(frames);
947
ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
948
949
result = event_storage_garbage_contains(env, &global_event_storage,
950
native_frames, size, check_lines);
951
952
free(native_frames), native_frames = NULL;
953
return result;
954
}
955
956
JNIEXPORT jlong JNICALL
957
Java_MyPackage_HeapMonitor_getSize(JNIEnv* env, jclass cls,
958
jobjectArray frames,
959
jboolean check_lines) {
960
jlong result = 0;
961
jsize size = env->GetArrayLength(frames);
962
ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
963
964
result = event_storage_get_size(env, &global_event_storage,
965
native_frames, size, check_lines);
966
967
free(native_frames), native_frames = NULL;
968
return result;
969
}
970
971
JNIEXPORT void JNICALL
972
Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
973
check_error(jvmti->ForceGarbageCollection(),
974
"Forced Garbage Collection");
975
}
976
977
JNIEXPORT void JNICALL
978
Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
979
event_storage_reset(&global_event_storage);
980
event_storage_reset(&second_global_event_storage);
981
}
982
983
JNIEXPORT jboolean JNICALL
984
Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
985
jclass cls) {
986
jvmtiCapabilities caps;
987
memset(&caps, 0, sizeof(caps));
988
caps.can_generate_sampled_object_alloc_events = 1;
989
if (check_error(jvmti->RelinquishCapabilities(&caps),
990
"Add capabilities\n")){
991
return FALSE;
992
}
993
994
if (check_capability_error(jvmti->SetHeapSamplingInterval(1<<19),
995
"Set Heap Sampling Interval")) {
996
return FALSE;
997
}
998
return TRUE;
999
}
1000
1001
JNIEXPORT jboolean JNICALL
1002
Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,
1003
jclass cls) {
1004
if (check_error(jvmti->SetHeapSamplingInterval(0),
1005
"Sampling interval 0 failed\n")){
1006
return FALSE;
1007
}
1008
1009
if (check_error(jvmti->SetHeapSamplingInterval(1024),
1010
"Sampling interval 1024 failed\n")){
1011
return FALSE;
1012
}
1013
1014
if (!check_error(jvmti->SetHeapSamplingInterval(-1),
1015
"Sampling interval -1 passed\n")){
1016
return FALSE;
1017
}
1018
1019
if (!check_error(jvmti->SetHeapSamplingInterval(-1024),
1020
"Sampling interval -1024 passed\n")){
1021
return FALSE;
1022
}
1023
1024
return TRUE;
1025
}
1026
1027
JNIEXPORT jdouble JNICALL
1028
Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1029
return event_storage_get_average_size(&global_event_storage);
1030
}
1031
1032
typedef struct sThreadsFound {
1033
jthread* threads;
1034
int num_threads;
1035
} ThreadsFound;
1036
1037
JNIEXPORT jboolean JNICALL
1038
Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1039
jint num_threads) {
1040
print_thread_stats();
1041
// Ensure we got stacks from at least num_threads.
1042
return thread_stats.thread_count >= num_threads;
1043
}
1044
1045
JNIEXPORT
1046
void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1047
JNIEnv* jni_env,
1048
jthread thread,
1049
jobject object,
1050
jclass object_klass,
1051
jlong size) {
1052
// Nop for now, two agents are not yet implemented.
1053
assert(0);
1054
}
1055
1056
JNIEXPORT jboolean JNICALL
1057
Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1058
JNIEnv* env, jclass cls) {
1059
// Currently this method should be failing directly at the AddCapability step
1060
// but the implementation is correct for when multi-agent support is enabled.
1061
jvmtiCapabilities caps;
1062
jvmtiEventCallbacks callbacks;
1063
1064
memset(&caps, 0, sizeof(caps));
1065
caps.can_generate_sampled_object_alloc_events = 1;
1066
if (check_error(second_jvmti->AddCapabilities(&caps),
1067
"Set the capability for second agent")) {
1068
return FALSE;
1069
}
1070
1071
memset(&callbacks, 0, sizeof(callbacks));
1072
callbacks.SampledObjectAlloc = &SampledObjectAlloc2;
1073
1074
if (check_error(second_jvmti->SetEventCallbacks(&callbacks,
1075
sizeof(jvmtiEventCallbacks)),
1076
" Set Event Callbacks for second agent")) {
1077
return FALSE;
1078
}
1079
1080
return TRUE;
1081
}
1082
1083
JNIEXPORT void JNICALL
1084
Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) {
1085
check_error(jvmti->SetEventNotificationMode(
1086
JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL),
1087
"Set vm event notifications");
1088
}
1089
1090
JNIEXPORT jint JNICALL
1091
Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {
1092
return event_storage_number_additions(&second_global_event_storage);
1093
}
1094
1095
JNIEXPORT jint JNICALL
1096
Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) {
1097
return event_storage_number_additions(&global_event_storage);
1098
}
1099
1100
static jobject allocate_object(JNIEnv* env) {
1101
// Construct an Object.
1102
jclass cls = env->FindClass("java/lang/Object");
1103
jmethodID constructor;
1104
jobject result;
1105
1106
if (env->ExceptionOccurred() || cls == NULL) {
1107
env->FatalError("Error in jni FindClass: Cannot find Object class\n");
1108
}
1109
1110
constructor = env->GetMethodID(cls, "<init>", "()V");
1111
if (env->ExceptionOccurred() || constructor == NULL) {
1112
env->FatalError("Error in jni GetMethodID: Cannot find Object class constructor\n");
1113
}
1114
1115
// Call back constructor to allocate a new instance, with an int argument
1116
result = env->NewObject(cls, constructor);
1117
1118
if (env->ExceptionOccurred() || result == NULL) {
1119
env->FatalError("Error in jni NewObject: Cannot allocate an object\n");
1120
}
1121
return result;
1122
}
1123
1124
// Ensure we got a callback for the test.
1125
static int did_recursive_callback_test;
1126
1127
JNIEXPORT
1128
void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env,
1129
JNIEnv* jni_env,
1130
jthread thread,
1131
jobject object,
1132
jclass object_klass,
1133
jlong size) {
1134
// Basically ensure that if we were to allocate objects, we would not have an
1135
// infinite recursion here.
1136
int i;
1137
for (i = 0; i < 1000; i++) {
1138
if (allocate_object(jni_env) == NULL) {
1139
jni_env->FatalError("allocate_object returned NULL\n");
1140
}
1141
}
1142
1143
did_recursive_callback_test = 1;
1144
}
1145
1146
JNIEXPORT jboolean JNICALL
1147
Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) {
1148
return did_recursive_callback_test != 0;
1149
}
1150
1151
JNIEXPORT void JNICALL
1152
Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) {
1153
jvmtiEventCallbacks callbacks;
1154
1155
memset(&callbacks, 0, sizeof(callbacks));
1156
callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc;
1157
1158
if (check_error(jvmti->SetEventCallbacks(&callbacks,
1159
sizeof(jvmtiEventCallbacks)),
1160
"Set Event Callbacks")) {
1161
env->FatalError("Cannot reset the callback.");
1162
}
1163
}
1164
1165
}
1166
1167