4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "jvmti.h"
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #ifndef JNI_ENV_ARG
34
35 #ifdef __cplusplus
36 #define JNI_ENV_ARG(x, y) y
37 #define JNI_ENV_PTR(x) x
38 #else
39 #define JNI_ENV_ARG(x,y) x, y
40 #define JNI_ENV_PTR(x) (*x)
41 #endif
42
43 #endif
44
45 #define TRUE 1
46 #define FALSE 0
47 #define PRINT_OUT 1
48 #define MAX_TRACES 400
49
50 static const char *EXC_CNAME = "java/lang/Exception";
51 static jvmtiEnv *jvmti = NULL;
52
53 static int check_error(jvmtiError err, const char *s) {
54 if (err != JVMTI_ERROR_NONE) {
55 printf(" ## %s error: %d\n", s, err);
56 return 1;
57 }
58 return 0;
59 }
60
61 static int check_capability_error(jvmtiError err, const char *s) {
62 if (err != JVMTI_ERROR_NONE) {
63 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
64 return 0;
65 }
66 printf(" ## %s error: %d\n", s, err);
67 return 1;
68 }
69 return 1;
70 }
71
80 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
81 }
82
83 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
84
85 JNIEXPORT
86 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
87 return Agent_Initialize(jvm, options, reserved);
88 }
89
90 JNIEXPORT
91 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
92 return Agent_Initialize(jvm, options, reserved);
93 }
94
95 JNIEXPORT
96 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
97 return JNI_VERSION_1_8;
98 }
99
100 static
101 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
102 jint res;
103
104 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
105 JVMTI_VERSION_9);
106 if (res != JNI_OK || jvmti == NULL) {
107 printf(" Error: wrong result of a valid call to GetEnv!\n");
108 return JNI_ERR;
109 }
110
111 jvmtiEventCallbacks callbacks;
112 memset(&callbacks, 0, sizeof(callbacks));
113
114 jvmtiCapabilities caps;
115 memset(&caps, 0, sizeof(caps));
116 // Get line numbers, sample heap, and filename for the test.
117 caps.can_get_line_numbers = 1;
118 caps.can_sample_heap = 1;
119 caps.can_get_source_file_name = 1;
120 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
121 "Add capabilities\n")){
122 return JNI_ERR;
123 }
124 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
125 sizeof(jvmtiEventCallbacks)),
126 " Set Event Callbacks")) {
127 return JNI_ERR;
128 }
129 return JNI_OK;
130 }
131
132 // Given a method and a location, this method gets the line number.
133 static
134 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
135 jlocation location) {
136 // Read the line number table.
137 jvmtiLineNumberEntry *table_ptr = 0;
138 jint line_number_table_entries;
139 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
140 &line_number_table_entries,
141 &table_ptr);
142
143 if (JVMTI_ERROR_NONE != jvmti_error) {
144 return -1;
145 }
146 if (line_number_table_entries <= 0) {
147 return -1;
148 }
153 // Go through all the line numbers...
154 jint last_location = table_ptr[0].start_location;
155 int l;
156 for (l = 1; l < line_number_table_entries; l++) {
157 // ... and if you see one that is in the right place for your
158 // location, you've found the line number!
159 if ((location < table_ptr[l].start_location) &&
160 (location >= last_location)) {
161 return table_ptr[l - 1].line_number;
162 }
163 last_location = table_ptr[l].start_location;
164 }
165
166 if (location >= last_location) {
167 return table_ptr[line_number_table_entries - 1].line_number;
168 } else {
169 return -1;
170 }
171 }
172
173 typedef struct _ExpectedContentFrame {
174 const char *name;
175 const char *signature;
176 const char *file_name;
177 int line_number;
178 } ExpectedContentFrame;
179
180 static jboolean check_sample_content(JNIEnv *env,
181 jvmtiAllocTraceInfo* trace,
182 ExpectedContentFrame *expected,
183 int expected_count,
184 int print_out_comparisons) {
185 int i;
186
187 jvmtiStackInfo* stack_info = trace->stack_info;
188
189 if (expected_count > stack_info->frame_count) {
190 return FALSE;
191 }
192
193 jvmtiFrameInfo* frames = stack_info->frame_buffer;
194
195 for (i = 0; i < expected_count; i++) {
196 // Get basic information out of the trace.
197 int bci = frames[i].location;
198 jmethodID methodid = frames[i].method;
199 char *name = NULL, *signature = NULL, *file_name = NULL;
200
201 if (bci < 0) {
202 return FALSE;
203 }
204
205 // Transform into usable information.
206 int line_number = get_line_number(jvmti, methodid, bci);
207 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
208
209 jclass declaring_class;
210 if (JVMTI_ERROR_NONE !=
211 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
212 return FALSE;
213 }
214
238 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
239 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
240 fprintf(stderr, "\t\tResult is %d\n",
241 (strcmp(name, expected[i].name) ||
242 strcmp(signature, expected[i].signature) ||
243 strcmp(file_name, expected[i].file_name) ||
244 line_number != expected[i].line_number));
245 }
246
247 if (strcmp(name, expected[i].name) ||
248 strcmp(signature, expected[i].signature) ||
249 strcmp(file_name, expected[i].file_name) ||
250 line_number != expected[i].line_number) {
251 return FALSE;
252 }
253 }
254
255 return TRUE;
256 }
257
258 static jboolean compare_samples(JNIEnv* env, jvmtiAllocTraceInfo* traces,
259 int trace_count,
260 ExpectedContentFrame* expected_content,
261 size_t size,
262 int print_out_comparisons) {
263 // We expect the code to record correctly the bci, retrieve the line
264 // number, have the right method and the class name of the first frames.
265 int i;
266 if (print_out_comparisons) {
267 fprintf(stderr, "\tNumber of traces: %d\n", print_out_comparisons);
268 }
269
270 for (i = 0; i < trace_count; i++) {
271 jvmtiAllocTraceInfo* trace = traces + i;
272 if (check_sample_content(env, trace, expected_content, size,
273 print_out_comparisons)) {
274 // At least one frame matched what we were looking for.
275 return TRUE;
276 }
277 }
456 fill_native_frames(env, frames, native_frames, size);
457
458 if (jvmti == NULL) {
459 throw_exc(env, "JVMTI client was not properly loaded!\n");
460 return FALSE ;
461 }
462
463 if ((!frames_exist_live(env, native_frames, size, print_out)) &&
464 (!frames_exist_recent(env, native_frames, size, print_out)) &&
465 (!frames_exist_frequent(env, native_frames, size, print_out))) {
466 return TRUE;
467 }
468 return FALSE;
469 }
470
471 JNIEXPORT void JNICALL
472 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate,
473 int max_traces) {
474 check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces),
475 "Start Heap Sampling");
476 }
477
478 JNIEXPORT void JNICALL
479 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) {
480 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
481 }
482
483 JNIEXPORT jboolean JNICALL
484 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) {
485 jvmtiHeapSamplingStats stats;
486 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
487 "Heap Sampling Statistics");
488
489 jvmtiHeapSamplingStats zero;
490 memset(&zero, 0, sizeof(zero));
491 return memcmp(&stats, &zero, sizeof(zero)) == 0;
492 }
493
494 JNIEXPORT jboolean JNICALL
495 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls,
496 jobjectArray frames) {
497 // We want the frames in each part.
498 return checkAll(env, frames, PRINT_OUT);
499 }
500
745 jclass cls) {
746 jvmtiAllocTraceInfo* traces;
747 jint trace_counter;
748
749 jvmtiError error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces,
750 &trace_counter);
751
752 if (error != JVMTI_ERROR_NONE) {
753 return;
754 }
755
756 (*jvmti)->Deallocate(jvmti, (unsigned char*) traces);
757 }
758
759 static jboolean compare_traces(jvmtiAllocTraceInfo* traces,
760 int trace_count,
761 jvmtiAllocTraceInfo* other_traces,
762 int other_trace_count,
763 int print_out_comparisons) {
764 if (trace_count != other_trace_count) {
765 return FALSE;
766 }
767
768 int i;
769 for (i = 0; i < trace_count; i++) {
770 jvmtiAllocTraceInfo* trace = traces + i;
771 jvmtiAllocTraceInfo* other_trace = other_traces + i;
772
773 jvmtiStackInfo* stack_info = trace->stack_info;
774 jvmtiStackInfo* other_stack_info = trace->stack_info;
775
776 if (stack_info->frame_count != other_stack_info->frame_count) {
777 return FALSE;
778 }
779
780 if (trace->size != other_trace->size) {
781 return FALSE;
782 }
783
784 if (trace->thread_id != other_trace->thread_id) {
785 return FALSE;
786 }
787
788 jvmtiFrameInfo* frames = stack_info->frame_buffer;
789 jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer;
790 if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) {
791 return FALSE;
792 }
793 }
794
795 return TRUE;
796 }
797
798 JNIEXPORT jboolean JNICALL
799 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
800 jclass cls) {
801 // Get cached first, then get live (since live performs a GC).
802 jvmtiAllocTraceInfo* cached_traces;
803 jint cached_trace_counter;
804 jvmtiError error =
805 (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces,
806 &cached_trace_counter);
807
808 if (error != JVMTI_ERROR_NONE) {
809 return FALSE;
810 }
814 error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &live_traces,
815 &live_trace_counter);
816
817 if (error != JVMTI_ERROR_NONE) {
818 return FALSE;
819 }
820
821 int result = compare_traces(cached_traces, cached_trace_counter,
822 live_traces, live_trace_counter,
823 PRINT_OUT);
824
825 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
826 return FALSE;
827 }
828 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) live_traces) != JVMTI_ERROR_NONE) {
829 return FALSE;
830 }
831 return result;
832 }
833
834 static long hash(long hash_code, long value) {
835 return hash_code * 31 + value;
836 }
837
838 static long get_hash_code(jvmtiAllocTraceInfo* traces, jint trace_counter) {
839 int hash_code = 17;
840 int i, j;
841
842 hash_code = hash(hash_code, trace_counter);
843 for (i = 0; i < trace_counter; i++) {
844 jvmtiAllocTraceInfo* trace = traces + i;
845
846 hash_code = hash(hash_code, trace->size);
847 hash_code = hash(hash_code, trace->thread_id);
848
849 jvmtiStackInfo* stack_info = trace->stack_info;
850 hash_code = hash(hash_code, stack_info->frame_count);
851
852 int frame_count = stack_info->frame_count;
853 jvmtiFrameInfo* frames = stack_info->frame_buffer;
872 &cached_trace_counter);
873
874 if (error != JVMTI_ERROR_NONE) {
875 return 0;
876 }
877
878 long hash_code = get_hash_code(cached_traces, cached_trace_counter);
879
880 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
881 return FALSE;
882 }
883
884 return hash_code;
885 }
886
887 JNIEXPORT jboolean JNICALL
888 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
889 jclass cls,
890 jobjectArray frames) {
891 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
892 }
893
894 #ifdef __cplusplus
895 }
896 #endif
|
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include <assert.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "jvmti.h"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #ifndef JNI_ENV_ARG
36
37 #ifdef __cplusplus
38 #define JNI_ENV_ARG(x, y) y
39 #define JNI_ENV_PTR(x) x
40 #else
41 #define JNI_ENV_ARG(x,y) x, y
42 #define JNI_ENV_PTR(x) (*x)
43 #endif
44
45 #endif
46
47 #define TRUE 1
48 #define FALSE 0
49 #define PRINT_OUT 1
50 #define MAX_TRACES 400
51
52 static const char *EXC_CNAME = "java/lang/Exception";
53 static jvmtiEnv *jvmti = NULL;
54 static pthread_mutex_t event_data_lock;
55
56 // Event storage code.
57
58 typedef struct _LiveObjectTrace{
59 jvmtiFrameInfo* frames;
60 size_t frame_count;
61 } LiveObjectTrace;
62
63 typedef struct _EventStorage {
64 int live_object_size;
65 int live_object_count;
66 LiveObjectTrace** live_objects;
67 } EventStorage;
68
69 typedef struct _ExpectedContentFrame {
70 const char *name;
71 const char *signature;
72 const char *file_name;
73 int line_number;
74 } ExpectedContentFrame;
75
76 static jboolean check_live_object_trace_content(
77 JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected,
78 size_t expected_count, int print_out_comparisons);
79
80 static EventStorage global_event_storage;
81
82 static int event_storage_get_count(EventStorage* storage) {
83 return storage->live_object_count;
84 }
85
86 static jboolean event_storage_contains(JNIEnv* env,
87 EventStorage* storage,
88 ExpectedContentFrame* frames,
89 size_t size) {
90 int i;
91 fprintf(stderr, "Event storage contains: %d\n", storage->live_object_count);
92 for (i = 0; i < storage->live_object_count; i++) {
93 LiveObjectTrace* trace = storage->live_objects[i];
94
95 if (check_live_object_trace_content(env, trace, frames, size, PRINT_OUT)) {
96 return TRUE;
97 }
98 }
99 return FALSE;
100 }
101
102 static void event_storage_augment_storage(EventStorage* storage) {
103 int new_max = (storage->live_object_size * 2) + 1;
104 LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
105
106 int current_count = storage->live_object_count;
107 memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
108 free(storage->live_objects);
109 storage->live_objects = new_objects;
110
111 storage->live_object_size = new_max;
112 }
113
114 static void event_storage_add(EventStorage* storage,
115 jthread thread,
116 jobject object,
117 jclass klass,
118 jlong size) {
119 pthread_mutex_lock(&event_data_lock);
120 jvmtiFrameInfo frames[64];
121 jint count;
122 jvmtiError err;
123 err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
124 if (err == JVMTI_ERROR_NONE && count >= 1) {
125 if (storage->live_object_count >= storage->live_object_size) {
126 event_storage_augment_storage(storage);
127 }
128 assert(storage->live_object_count < storage->live_object_size);
129
130 jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames));
131 memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
132
133 LiveObjectTrace* live_object = malloc(sizeof(*live_object));
134 live_object->frames = allocated_frames;
135 live_object->frame_count = count;
136 storage->live_objects[storage->live_object_count] = live_object;
137 storage->live_object_count++;
138 }
139 pthread_mutex_unlock(&event_data_lock);
140 }
141
142 static void event_storage_reset(EventStorage* storage) {
143 pthread_mutex_lock(&event_data_lock);
144 int max = storage->live_object_count;
145 int i;
146 for (i = 0; i < max; i++) {
147 LiveObjectTrace* object = storage->live_objects[i];
148 free(object);
149 }
150 free(storage->live_objects);
151 memset(storage, 0, sizeof(*storage));
152 pthread_mutex_unlock(&event_data_lock);
153 }
154
155 // General JVMTI agent code.
156
157 static int check_error(jvmtiError err, const char *s) {
158 if (err != JVMTI_ERROR_NONE) {
159 printf(" ## %s error: %d\n", s, err);
160 return 1;
161 }
162 return 0;
163 }
164
165 static int check_capability_error(jvmtiError err, const char *s) {
166 if (err != JVMTI_ERROR_NONE) {
167 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
168 return 0;
169 }
170 printf(" ## %s error: %d\n", s, err);
171 return 1;
172 }
173 return 1;
174 }
175
184 return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
185 }
186
187 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
188
189 JNIEXPORT
190 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
191 return Agent_Initialize(jvm, options, reserved);
192 }
193
194 JNIEXPORT
195 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
196 return Agent_Initialize(jvm, options, reserved);
197 }
198
199 JNIEXPORT
200 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
201 return JNI_VERSION_1_8;
202 }
203
204 JNIEXPORT
205 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
206 JNIEnv* jni_env,
207 jthread thread,
208 jobject object,
209 jclass object_klass,
210 jlong size) {
211 // Not optimal to do this at the callback but makes testing easier for now.
212 event_storage_add(&global_event_storage, thread, object, object_klass, size);
213 }
214
215 static
216 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
217 jint res;
218
219 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
220 JVMTI_VERSION_9);
221 if (res != JNI_OK || jvmti == NULL) {
222 printf(" Error: wrong result of a valid call to GetEnv!\n");
223 return JNI_ERR;
224 }
225
226 jvmtiEventCallbacks callbacks;
227 memset(&callbacks, 0, sizeof(callbacks));
228 callbacks.SampledObjectAlloc = &SampledObjectAlloc;
229
230 jvmtiCapabilities caps;
231 memset(&caps, 0, sizeof(caps));
232 // Get line numbers, sample heap, and filename for the test.
233 caps.can_get_line_numbers = 1;
234 caps.can_sample_heap = 1;
235 caps.can_generate_sampled_object_alloc_events = 1;
236 caps.can_get_source_file_name = 1;
237 if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
238 "Add capabilities\n")){
239 return JNI_ERR;
240 }
241
242 if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
243 sizeof(jvmtiEventCallbacks)),
244 " Set Event Callbacks")) {
245 return JNI_ERR;
246 }
247
248
249 if (pthread_mutex_init(&event_data_lock, NULL) != 0) {
250 return JNI_ERR;
251 }
252
253 return JNI_OK;
254 }
255
256 // Given a method and a location, this method gets the line number.
257 static
258 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
259 jlocation location) {
260 // Read the line number table.
261 jvmtiLineNumberEntry *table_ptr = 0;
262 jint line_number_table_entries;
263 int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
264 &line_number_table_entries,
265 &table_ptr);
266
267 if (JVMTI_ERROR_NONE != jvmti_error) {
268 return -1;
269 }
270 if (line_number_table_entries <= 0) {
271 return -1;
272 }
277 // Go through all the line numbers...
278 jint last_location = table_ptr[0].start_location;
279 int l;
280 for (l = 1; l < line_number_table_entries; l++) {
281 // ... and if you see one that is in the right place for your
282 // location, you've found the line number!
283 if ((location < table_ptr[l].start_location) &&
284 (location >= last_location)) {
285 return table_ptr[l - 1].line_number;
286 }
287 last_location = table_ptr[l].start_location;
288 }
289
290 if (location >= last_location) {
291 return table_ptr[line_number_table_entries - 1].line_number;
292 } else {
293 return -1;
294 }
295 }
296
297 static jboolean check_frame_content(JNIEnv *env,
298 jvmtiFrameInfo* frames,
299 ExpectedContentFrame *expected,
300 int expected_count,
301 int print_out_comparisons) {
302 int i;
303 for (i = 0; i < expected_count; i++) {
304 // Get basic information out of the trace.
305 int bci = frames[i].location;
306 jmethodID methodid = frames[i].method;
307 char *name = NULL, *signature = NULL, *file_name = NULL;
308
309 if (bci < 0) {
310 return FALSE;
311 }
312
313 // Transform into usable information.
314 int line_number = get_line_number(jvmti, methodid, bci);
315 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
316
317 jclass declaring_class;
318 if (JVMTI_ERROR_NONE !=
319 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
320 return FALSE;
321 }
322
346 fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
347 fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
348 fprintf(stderr, "\t\tResult is %d\n",
349 (strcmp(name, expected[i].name) ||
350 strcmp(signature, expected[i].signature) ||
351 strcmp(file_name, expected[i].file_name) ||
352 line_number != expected[i].line_number));
353 }
354
355 if (strcmp(name, expected[i].name) ||
356 strcmp(signature, expected[i].signature) ||
357 strcmp(file_name, expected[i].file_name) ||
358 line_number != expected[i].line_number) {
359 return FALSE;
360 }
361 }
362
363 return TRUE;
364 }
365
366 static jboolean check_live_object_trace_content(
367 JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected,
368 size_t expected_count, int print_out_comparisons) {
369
370 if (expected_count > trace->frame_count) {
371 return FALSE;
372 }
373
374 return check_frame_content(env, trace->frames,
375 expected, expected_count, print_out_comparisons);
376 }
377
378 static jboolean check_sample_content(JNIEnv *env,
379 jvmtiAllocTraceInfo* trace,
380 ExpectedContentFrame *expected,
381 int expected_count,
382 int print_out_comparisons) {
383 jvmtiStackInfo* stack_info = trace->stack_info;
384
385 if (expected_count > stack_info->frame_count) {
386 return FALSE;
387 }
388
389 return check_frame_content(env, stack_info->frame_buffer,
390 expected, expected_count, print_out_comparisons);
391 }
392
393 static jboolean compare_samples(JNIEnv* env, jvmtiAllocTraceInfo* traces,
394 int trace_count,
395 ExpectedContentFrame* expected_content,
396 size_t size,
397 int print_out_comparisons) {
398 // We expect the code to record correctly the bci, retrieve the line
399 // number, have the right method and the class name of the first frames.
400 int i;
401 if (print_out_comparisons) {
402 fprintf(stderr, "\tNumber of traces: %d\n", print_out_comparisons);
403 }
404
405 for (i = 0; i < trace_count; i++) {
406 jvmtiAllocTraceInfo* trace = traces + i;
407 if (check_sample_content(env, trace, expected_content, size,
408 print_out_comparisons)) {
409 // At least one frame matched what we were looking for.
410 return TRUE;
411 }
412 }
591 fill_native_frames(env, frames, native_frames, size);
592
593 if (jvmti == NULL) {
594 throw_exc(env, "JVMTI client was not properly loaded!\n");
595 return FALSE ;
596 }
597
598 if ((!frames_exist_live(env, native_frames, size, print_out)) &&
599 (!frames_exist_recent(env, native_frames, size, print_out)) &&
600 (!frames_exist_frequent(env, native_frames, size, print_out))) {
601 return TRUE;
602 }
603 return FALSE;
604 }
605
606 JNIEXPORT void JNICALL
607 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate,
608 int max_traces) {
609 check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces),
610 "Start Heap Sampling");
611 check_error(
612 (*jvmti)->SetEventNotificationMode(jvmti,
613 JVMTI_ENABLE,
614 JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
615 NULL),
616 "Start sampling events");
617 }
618
619 JNIEXPORT void JNICALL
620 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) {
621 check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
622
623 check_error(
624 (*jvmti)->SetEventNotificationMode(jvmti,
625 JVMTI_DISABLE,
626 JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
627 NULL),
628 "Start sampling events");
629 }
630
631 JNIEXPORT jboolean JNICALL
632 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) {
633 jvmtiHeapSamplingStats stats;
634 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
635 "Heap Sampling Statistics");
636
637 jvmtiHeapSamplingStats zero;
638 memset(&zero, 0, sizeof(zero));
639 return memcmp(&stats, &zero, sizeof(zero)) == 0;
640 }
641
642 JNIEXPORT jboolean JNICALL
643 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls,
644 jobjectArray frames) {
645 // We want the frames in each part.
646 return checkAll(env, frames, PRINT_OUT);
647 }
648
893 jclass cls) {
894 jvmtiAllocTraceInfo* traces;
895 jint trace_counter;
896
897 jvmtiError error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces,
898 &trace_counter);
899
900 if (error != JVMTI_ERROR_NONE) {
901 return;
902 }
903
904 (*jvmti)->Deallocate(jvmti, (unsigned char*) traces);
905 }
906
907 static jboolean compare_traces(jvmtiAllocTraceInfo* traces,
908 int trace_count,
909 jvmtiAllocTraceInfo* other_traces,
910 int other_trace_count,
911 int print_out_comparisons) {
912 if (trace_count != other_trace_count) {
913 fprintf(stderr, "Trace count not the same!\n %d %d",
914 trace_count, other_trace_count);
915 return FALSE;
916 }
917
918 int i;
919 for (i = 0; i < trace_count; i++) {
920 jvmtiAllocTraceInfo* trace = traces + i;
921 jvmtiAllocTraceInfo* other_trace = other_traces + i;
922
923 jvmtiStackInfo* stack_info = trace->stack_info;
924 jvmtiStackInfo* other_stack_info = trace->stack_info;
925
926 if (stack_info->frame_count != other_stack_info->frame_count) {
927 fprintf(stderr, "Frame count not the same!\n");
928 return FALSE;
929 }
930
931 if (trace->size != other_trace->size) {
932 fprintf(stderr, "Size not the same!\n");
933 return FALSE;
934 }
935
936 if (trace->thread_id != other_trace->thread_id) {
937 fprintf(stderr, "Thread id not the same!\n");
938 return FALSE;
939 }
940
941 jvmtiFrameInfo* frames = stack_info->frame_buffer;
942 jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer;
943 if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) {
944 fprintf(stderr, "memcmp not the same!\n");
945 return FALSE;
946 }
947 }
948
949 return TRUE;
950 }
951
952 JNIEXPORT jboolean JNICALL
953 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
954 jclass cls) {
955 // Get cached first, then get live (since live performs a GC).
956 jvmtiAllocTraceInfo* cached_traces;
957 jint cached_trace_counter;
958 jvmtiError error =
959 (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces,
960 &cached_trace_counter);
961
962 if (error != JVMTI_ERROR_NONE) {
963 return FALSE;
964 }
968 error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &live_traces,
969 &live_trace_counter);
970
971 if (error != JVMTI_ERROR_NONE) {
972 return FALSE;
973 }
974
975 int result = compare_traces(cached_traces, cached_trace_counter,
976 live_traces, live_trace_counter,
977 PRINT_OUT);
978
979 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
980 return FALSE;
981 }
982 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) live_traces) != JVMTI_ERROR_NONE) {
983 return FALSE;
984 }
985 return result;
986 }
987
988 JNIEXPORT jboolean JNICALL
989 Java_MyPackage_HeapMonitorCachedTest_forceGC(JNIEnv *env, jclass cls) {
990 jvmtiError error = (*jvmti)->ForceGarbageCollection(jvmti);
991
992 if (error != JVMTI_ERROR_NONE) {
993 return FALSE;
994 }
995 return TRUE;
996 }
997
998 static long hash(long hash_code, long value) {
999 return hash_code * 31 + value;
1000 }
1001
1002 static long get_hash_code(jvmtiAllocTraceInfo* traces, jint trace_counter) {
1003 int hash_code = 17;
1004 int i, j;
1005
1006 hash_code = hash(hash_code, trace_counter);
1007 for (i = 0; i < trace_counter; i++) {
1008 jvmtiAllocTraceInfo* trace = traces + i;
1009
1010 hash_code = hash(hash_code, trace->size);
1011 hash_code = hash(hash_code, trace->thread_id);
1012
1013 jvmtiStackInfo* stack_info = trace->stack_info;
1014 hash_code = hash(hash_code, stack_info->frame_count);
1015
1016 int frame_count = stack_info->frame_count;
1017 jvmtiFrameInfo* frames = stack_info->frame_buffer;
1036 &cached_trace_counter);
1037
1038 if (error != JVMTI_ERROR_NONE) {
1039 return 0;
1040 }
1041
1042 long hash_code = get_hash_code(cached_traces, cached_trace_counter);
1043
1044 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
1045 return FALSE;
1046 }
1047
1048 return hash_code;
1049 }
1050
1051 JNIEXPORT jboolean JNICALL
1052 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
1053 jclass cls,
1054 jobjectArray frames) {
1055 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
1056 }
1057
1058 JNIEXPORT jboolean JNICALL
1059 Java_MyPackage_HeapMonitorEventNoCapabilityTest_eventSamplingFail(JNIEnv *env,
1060 jclass cls) {
1061 jvmtiCapabilities caps;
1062 memset(&caps, 0, sizeof(caps));
1063 caps.can_generate_sampled_object_alloc_events = 1;
1064 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
1065 "Add capabilities\n")){
1066 return FALSE;
1067 }
1068
1069 if (check_capability_error(
1070 (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
1071 "Set Tlab Heap Sampling")) {
1072 return FALSE;
1073 }
1074 return TRUE;
1075 }
1076
1077 JNIEXPORT jboolean JNICALL
1078 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
1079 return event_storage_get_count(&global_event_storage) == 0;
1080 }
1081
1082 JNIEXPORT jboolean JNICALL
1083 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
1084 jsize size = (*env)->GetArrayLength(env, frames);
1085 ExpectedContentFrame native_frames[size];
1086 fill_native_frames(env, frames, native_frames, size);
1087 return event_storage_contains(env, &global_event_storage, native_frames, size);
1088 }
1089
1090 JNIEXPORT void JNICALL
1091 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
1092 return event_storage_reset(&global_event_storage);
1093 }
1094
1095 #ifdef __cplusplus
1096 }
1097 #endif
|