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 jvmtiStackTrace *trace,
182 ExpectedContentFrame *expected,
183 int expected_count,
184 int print_out_comparisons) {
185 int i;
186
187 if (expected_count > trace->frame_count) {
188 return FALSE;
189 }
190
191 for (i = 0; i < expected_count; i++) {
192 // Get basic information out of the trace.
193 int bci = trace->frames[i].location;
194 jmethodID methodid = trace->frames[i].method;
195 char *name = NULL, *signature = NULL, *file_name = NULL;
196
197 if (bci < 0) {
198 return FALSE;
199 }
200
201 // Transform into usable information.
202 int line_number = get_line_number(jvmti, methodid, bci);
203 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
204
205 jclass declaring_class;
206 if (JVMTI_ERROR_NONE !=
207 (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
208 return FALSE;
209 }
210
211 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
212 &file_name);
213 if (err != JVMTI_ERROR_NONE) {
214 return FALSE;
215 }
216
217 // Compare now, none should be NULL.
218 if (name == NULL) {
219 return FALSE;
220 }
221
222 if (file_name == NULL) {
223 return FALSE;
224 }
225
226 if (signature == NULL) {
227 return FALSE;
228 }
229
230 if (print_out_comparisons) {
231 fprintf(stderr, "Comparing:\n");
232 fprintf(stderr, "\tNames: %s and %s\n", name, expected[i].name);
233 fprintf(stderr, "\tSignatures: %s and %s\n", signature, expected[i].signature);
234 fprintf(stderr, "\tFile name: %s and %s\n", file_name, expected[i].file_name);
235 fprintf(stderr, "\tLines: %d and %d\n", line_number, expected[i].line_number);
236 fprintf(stderr, "\tResult is %d\n",
237 (strcmp(name, expected[i].name) ||
238 strcmp(signature, expected[i].signature) ||
239 strcmp(file_name, expected[i].file_name) ||
240 line_number != expected[i].line_number));
241 }
242
243 if (strcmp(name, expected[i].name) ||
244 strcmp(signature, expected[i].signature) ||
245 strcmp(file_name, expected[i].file_name) ||
246 line_number != expected[i].line_number) {
247 return FALSE;
248 }
249 }
250
251 return TRUE;
252 }
253
254 static jboolean compare_samples(JNIEnv* env, jvmtiStackTrace* traces,
255 int trace_count,
256 ExpectedContentFrame* expected_content,
257 size_t size,
258 int print_out_comparisons) {
259 // We expect the code to record correctly the bci, retrieve the line
260 // number, have the right method and the class name of the first frames.
261 int i;
262 for (i = 0; i < trace_count; i++) {
263 jvmtiStackTrace *trace = traces + i;
264 if (check_sample_content(env, trace, expected_content, size,
265 print_out_comparisons)) {
266 // At least one frame matched what we were looking for.
267 return TRUE;
268 }
269 }
270
271 return FALSE;
272 }
273
274 static jboolean
275 check_samples(JNIEnv* env,
276 ExpectedContentFrame* expected,
277 size_t size,
278 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*),
279 int print_out_comparisons) {
280 jvmtiStackTraces traces;
281 jvmtiError error = get_traces(jvmti, &traces);
282
283 if (error != JVMTI_ERROR_NONE) {
284 return FALSE;
285 }
286
287 int result = compare_samples(env, traces.stack_traces, traces.trace_count,
288 expected, size, print_out_comparisons);
289 (*jvmti)->ReleaseTraces(jvmti, &traces);
290 return result;
291 }
292
293 static jboolean frames_exist_live(JNIEnv* env,
294 ExpectedContentFrame* expected,
295 size_t size,
296 int print_out_comparisons) {
297 return check_samples(env, expected, size, (*jvmti)->GetLiveTraces,
298 print_out_comparisons);
299 }
300
301 static jboolean frames_exist_recent(JNIEnv* env,
302 ExpectedContentFrame* expected,
303 size_t size,
304 int print_out_comparisons) {
305 return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces,
306 print_out_comparisons);
307 }
308
309 static jboolean frames_exist_frequent(JNIEnv* env,
310 ExpectedContentFrame* expected,
311 size_t size,
312 int print_out_comparisons) {
313 return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces,
314 print_out_comparisons);
315 }
316
317 // Static native API for various tests.
521 jclass cls) {
522 jvmtiCapabilities caps;
523 memset(&caps, 0, sizeof(caps));
524 caps.can_sample_heap= 1;
525 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
526 "Add capabilities\n")){
527 return FALSE;
528 }
529
530 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
531 MAX_TRACES),
532 "Start Heap Sampling")) {
533 return FALSE;
534 }
535
536 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
537 "Stop Heap Sampling")) {
538 return FALSE;
539 }
540
541 if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL),
542 "Release Traces")) {
543 return FALSE;
544 }
545
546 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
547 "Get Heap Sampling Stats")) {
548 return FALSE;
549 }
550
551 if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL),
552 "Get Garbage Traces")) {
553 return FALSE;
554 }
555
556 if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL),
557 "Get Frequent Garbage Traces")) {
558 return FALSE;
559 }
560
561 if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL),
562 "Get Live Traces")) {
563 return FALSE;
564 }
565 return TRUE;
566 }
567
568 JNIEXPORT jboolean JNICALL
569 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env,
570 jclass cls,
571 int expected,
572 int percent_error) {
573 jvmtiHeapSamplingStats stats;
574 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
575 "Heap Sampling Statistics");
576
577 double diff_ratio = (stats.sample_count - expected);
578 diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
579 diff_ratio /= expected;
580
581 if (diff_ratio * 100 >= percent_error) {
582 fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n",
583 stats.sample_count, expected);
584 }
585 return diff_ratio * 100 < percent_error;
586 }
587
588 JNIEXPORT jdouble JNICALL
589 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
590 jvmtiHeapSamplingStats stats;
591 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
592 "Heap Sampling Statistics");
593 return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
594 }
595
596 static double calculate_average_stack_depth(
597 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) {
598 jvmtiStackTraces traces;
599
600 jvmtiError error = get_traces(jvmti, &traces);;
601
602 if (error != JVMTI_ERROR_NONE) {
603 return 0;
604 }
605
606 int trace_count = traces.trace_count;
607
608 if (trace_count == 0) {
609 return 0;
610 }
611
612 int i;
613 jvmtiStackTrace* stack_traces = traces.stack_traces;
614 double sum = 0;
615 for (i = 0; i < trace_count; i++) {
616 jvmtiStackTrace *stack_trace = stack_traces + i;
617 sum += stack_trace->frame_count;
618 }
619
620 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
621 return 0;
622 }
623
624 return sum / i;
625 }
626
627 JNIEXPORT jdouble JNICALL
628 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env,
629 jclass cls) {
630 double result = calculate_average_stack_depth((*jvmti)->GetLiveTraces);
631
632 if (result != 0) {
633 return result;
634 }
635
636 // It is possible all the live objects got collected, check the garbage traces
637 // in case.
638 return calculate_average_stack_depth((*jvmti)->GetGarbageTraces);
639 }
640
641 typedef struct sThreadsFound {
642 jint *threads;
643 int num_threads;
644 } ThreadsFound;
645
646 static void find_threads_in_traces(jvmtiStackTraces* traces,
647 ThreadsFound* thread_data) {
648 int i;
649 jvmtiStackTrace* stack_traces = traces->stack_traces;
650 int trace_count = traces->trace_count;
651
652 jint *threads = thread_data->threads;
653 int num_threads = thread_data->num_threads;
654
655 // We are looking for at last expected_num_threads different traces.
656 for (i = 0; i < trace_count; i++) {
657 jvmtiStackTrace *stack_trace = stack_traces + i;
658 jlong thread_id = stack_trace->thread_id;
659
660 // Check it is the right frame: only accept helper top framed traces.
661 jmethodID methodid = stack_trace->frames[0].method;
662 char *name = NULL, *signature = NULL, *file_name = NULL;
663 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
664
665 if (strcmp(name, "helper")) {
666 continue;
667 }
668
669 // Really not efficient look-up but it's for a test...
670 int found = 0;
671 int j;
672 for (j = 0; j < num_threads; j++) {
673 if (thread_id == threads[j]) {
674 found = 1;
675 break;
676 }
677 }
678
679 if (!found) {
680 threads[num_threads] = thread_id;
681 num_threads++;
682 }
683 }
684 thread_data->num_threads = num_threads;
685 }
686
687 JNIEXPORT jboolean JNICALL
688 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
689 jintArray threads) {
690 jvmtiStackTraces traces;
691 ThreadsFound thread_data;
692 thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
693 thread_data.num_threads = 0;
694
695 // Get live and garbage traces to ensure we capture all the threads that have
696 // been sampled.
697 if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
698 return FALSE;
699 }
700
701 find_threads_in_traces(&traces, &thread_data);
702
703 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
704 return FALSE;
705 }
706
707 if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
708 return FALSE;
709 }
710
711 find_threads_in_traces(&traces, &thread_data);
712
713 if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
714 return FALSE;
715 }
716
717 (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
718 return TRUE;
719 }
720
721 JNIEXPORT void JNICALL
722 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env,
723 jclass cls) {
724 jvmtiStackTraces live_traces;
725 jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
726
727 if (error != JVMTI_ERROR_NONE) {
728 return;
729 }
730
731 (*jvmti)->ReleaseTraces(jvmti, &live_traces);
732 }
733
734 static jboolean compare_traces(jvmtiStackTraces* traces,
735 jvmtiStackTraces* other_traces,
736 int print_out_comparisons) {
737 int trace_count = traces->trace_count;
738 if (trace_count != other_traces->trace_count) {
739 return FALSE;
740 }
741
742 int i;
743 for (i = 0; i < trace_count; i++) {
744 jvmtiStackTrace* trace = traces->stack_traces + i;
745 jvmtiStackTrace* other_trace = other_traces->stack_traces + i;
746
747 if (trace->frame_count != other_trace->frame_count) {
748 return FALSE;
749 }
750
751 if (trace->size != other_trace->size) {
752 return FALSE;
753 }
754
755 if (trace->thread_id != other_trace->thread_id) {
756 return FALSE;
757 }
758
759 jvmtiFrameInfo* frames = trace->frames;
760 jvmtiFrameInfo* other_frames = other_trace->frames;
761 if (memcmp(frames, other_frames, sizeof(*frames) * trace->frame_count)) {
762 return FALSE;
763 }
764 }
765
766 return TRUE;
767 }
768
769 JNIEXPORT jboolean JNICALL
770 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
771 jclass cls) {
772 // Get cached first, then get live (since live performs a GC).
773 jvmtiStackTraces cached_traces;
774 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
775
776 if (error != JVMTI_ERROR_NONE) {
777 return FALSE;
778 }
779
780 jvmtiStackTraces live_traces;
781 error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
782
783 if (error != JVMTI_ERROR_NONE) {
784 return FALSE;
785 }
786
787 int result = compare_traces(&cached_traces, &live_traces, PRINT_OUT);
788
789 (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
790 (*jvmti)->ReleaseTraces(jvmti, &live_traces);
791 return result;
792 }
793
794 static long hash(long hash_code, long value) {
795 return hash_code * 31 + value;
796 }
797
798 static long get_hash_code(jvmtiStackTraces* traces) {
799 int trace_count = traces->trace_count;
800 int hash_code = 17;
801
802 int i;
803 hash_code = hash(hash_code, trace_count);
804 for (i = 0; i < trace_count; i++) {
805 jvmtiStackTrace* trace = traces->stack_traces + i;
806 hash_code = hash(hash_code, trace->frame_count);
807 hash_code = hash(hash_code, trace->size);
808 hash_code = hash(hash_code, trace->thread_id);
809
810 int j;
811 int frame_count = trace->frame_count;
812 jvmtiFrameInfo* frames = trace->frames;
813 hash_code = hash(hash_code, frame_count);
814 for (j = 0; j < frame_count; j++) {
815 hash_code = hash(hash_code, (long) frames[i].method);
816 hash_code = hash(hash_code, frames[i].location);
817 }
818 }
819
820 return TRUE;
821 }
822
823 JNIEXPORT jlong JNICALL
824 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env,
825 jclass cls) {
826 // Get cached first, then get live.
827 jvmtiStackTraces cached_traces;
828 jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
829
830 if (error != JVMTI_ERROR_NONE) {
831 return 0;
832 }
833
834 long hash_code = get_hash_code(&cached_traces);
835 (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
836
837 return hash_code;
838 }
839
840 JNIEXPORT jboolean JNICALL
841 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
842 jclass cls,
843 jobjectArray frames) {
844 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
845 }
846
847 #ifdef __cplusplus
848 }
849 #endif
|
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
215 jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
216 &file_name);
217 if (err != JVMTI_ERROR_NONE) {
218 return FALSE;
219 }
220
221 // Compare now, none should be NULL.
222 if (name == NULL) {
223 return FALSE;
224 }
225
226 if (file_name == NULL) {
227 return FALSE;
228 }
229
230 if (signature == NULL) {
231 return FALSE;
232 }
233
234 if (print_out_comparisons) {
235 fprintf(stderr, "\tComparing:\n");
236 fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
237 fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
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 }
278
279 return FALSE;
280 }
281
282 static jboolean
283 check_samples(JNIEnv* env,
284 ExpectedContentFrame* expected,
285 size_t size,
286 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*),
287 int print_out_comparisons) {
288 jvmtiAllocTraceInfo *traces;
289 jint trace_counter;
290 jvmtiError error = get_traces(jvmti, &traces, &trace_counter);
291
292 if (error != JVMTI_ERROR_NONE) {
293 return FALSE;
294 }
295
296 int result = compare_samples(env, traces, trace_counter,
297 expected, size, print_out_comparisons);
298
299 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
300 return FALSE;
301 }
302
303 return result;
304 }
305
306 static jboolean frames_exist_live(JNIEnv* env,
307 ExpectedContentFrame* expected,
308 size_t size,
309 int print_out_comparisons) {
310 return check_samples(env, expected, size, (*jvmti)->GetObjectAllocTraces,
311 print_out_comparisons);
312 }
313
314 static jboolean frames_exist_recent(JNIEnv* env,
315 ExpectedContentFrame* expected,
316 size_t size,
317 int print_out_comparisons) {
318 return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces,
319 print_out_comparisons);
320 }
321
322 static jboolean frames_exist_frequent(JNIEnv* env,
323 ExpectedContentFrame* expected,
324 size_t size,
325 int print_out_comparisons) {
326 return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces,
327 print_out_comparisons);
328 }
329
330 // Static native API for various tests.
534 jclass cls) {
535 jvmtiCapabilities caps;
536 memset(&caps, 0, sizeof(caps));
537 caps.can_sample_heap= 1;
538 if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
539 "Add capabilities\n")){
540 return FALSE;
541 }
542
543 if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
544 MAX_TRACES),
545 "Start Heap Sampling")) {
546 return FALSE;
547 }
548
549 if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
550 "Stop Heap Sampling")) {
551 return FALSE;
552 }
553
554 if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
555 "Get Heap Sampling Stats")) {
556 return FALSE;
557 }
558
559 if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL, NULL),
560 "Get Garbage Traces")) {
561 return FALSE;
562 }
563
564 if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL, NULL),
565 "Get Frequent Garbage Traces")) {
566 return FALSE;
567 }
568
569 if (check_capability_error((*jvmti)->GetObjectAllocTraces(jvmti, NULL, NULL),
570 "Get Object Allocated Traces")) {
571 return FALSE;
572 }
573
574 if (check_capability_error((*jvmti)->GetObjectAllocTraces(jvmti, NULL, NULL),
575 "Get Cached Object Allocated Traces")) {
576 return FALSE;
577 }
578 return TRUE;
579 }
580
581 JNIEXPORT jboolean JNICALL
582 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env,
583 jclass cls,
584 int expected,
585 int percent_error) {
586 jvmtiHeapSamplingStats stats;
587 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
588 "Heap Sampling Statistics");
589
590 double diff_ratio = (stats.sample_count - expected);
591 diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
592 diff_ratio /= expected;
593
594 if (diff_ratio * 100 >= percent_error) {
595 fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n",
596 stats.sample_count, expected);
597 }
598 return diff_ratio * 100 < percent_error;
599 }
600
601 JNIEXPORT jdouble JNICALL
602 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
603 jvmtiHeapSamplingStats stats;
604 check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
605 "Heap Sampling Statistics");
606 return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
607 }
608
609 static double calculate_average_stack_depth(
610 jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*)) {
611 jvmtiAllocTraceInfo* traces = NULL;
612 jint trace_counter;
613
614 jvmtiError error = get_traces(jvmti, &traces, &trace_counter);;
615
616 if (error != JVMTI_ERROR_NONE) {
617 return 0;
618 }
619
620 if (trace_counter == 0) {
621 return 0;
622 }
623
624 int i;
625 double sum = 0;
626 for (i = 0; i < trace_counter; i++) {
627 jvmtiAllocTraceInfo* trace = traces + i;
628 jvmtiStackInfo* stack_info = trace->stack_info;
629 sum += stack_info->frame_count;
630 }
631
632 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
633 return 0;
634 }
635
636 return sum / i;
637 }
638
639 JNIEXPORT jdouble JNICALL
640 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env,
641 jclass cls) {
642 double result = calculate_average_stack_depth((*jvmti)->GetObjectAllocTraces);
643
644 if (result != 0) {
645 return result;
646 }
647
648 // It is possible all the live objects got collected, check the garbage traces
649 // in case.
650 return calculate_average_stack_depth((*jvmti)->GetGarbageTraces);
651 }
652
653 typedef struct sThreadsFound {
654 jint* threads;
655 int num_threads;
656 } ThreadsFound;
657
658 static void find_threads_in_traces(jvmtiAllocTraceInfo* traces,
659 jint trace_counter,
660 ThreadsFound* thread_data) {
661 int i;
662 jint* threads = thread_data->threads;
663 int num_threads = thread_data->num_threads;
664
665 // We are looking for at last expected_num_threads different traces.
666 for (i = 0; i < trace_counter; i++) {
667 jvmtiAllocTraceInfo* trace = traces + i;
668 jvmtiStackInfo* stack_info = trace->stack_info;
669 jint thread_id = trace->thread_id;
670
671 // Check it is the right frame: only accept helper top framed traces.
672 if (stack_info->frame_count == 0) {
673 continue;
674 }
675
676 jmethodID methodid = stack_info->frame_buffer[0].method;
677 char *name = NULL, *signature = NULL, *file_name = NULL;
678 (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
679
680 if (strcmp(name, "helper")) {
681 continue;
682 }
683
684 // Really not efficient look-up but it's for a test...
685 int found = 0;
686 int j;
687 for (j = 0; j < num_threads; j++) {
688 if (thread_id == threads[j]) {
689 found = 1;
690 break;
691 }
692 }
693
694 if (!found) {
695 threads[num_threads] = thread_id;
696 num_threads++;
697 }
698 }
699 thread_data->num_threads = num_threads;
700 }
701
702 JNIEXPORT jboolean JNICALL
703 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
704 jintArray threads) {
705 jvmtiAllocTraceInfo* traces;
706 jint trace_counter;
707
708 ThreadsFound thread_data;
709 thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
710 thread_data.num_threads = 0;
711
712 // Get live and garbage traces to ensure we capture all the threads that have
713 // been sampled.
714 if ((*jvmti)->GetObjectAllocTraces(jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) {
715 return FALSE;
716 }
717
718 find_threads_in_traces(traces, trace_counter, &thread_data);
719
720 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
721 return FALSE;
722 }
723
724 if ((*jvmti)->GetGarbageTraces(jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) {
725 return FALSE;
726 }
727
728 find_threads_in_traces(traces, trace_counter, &thread_data);
729
730 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
731 return FALSE;
732 }
733
734 (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
735 return TRUE;
736 }
737
738 JNIEXPORT void JNICALL
739 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env,
740 jclass cls) {
741 jvmtiAllocTraceInfo* traces;
742 jint trace_counter;
743
744 jvmtiError error = (*jvmti)->GetObjectAllocTraces(jvmti, &traces,
745 &trace_counter);
746
747 if (error != JVMTI_ERROR_NONE) {
748 return;
749 }
750
751 (*jvmti)->Deallocate(jvmti, (unsigned char*) traces);
752 }
753
754 static jboolean compare_traces(jvmtiAllocTraceInfo* traces,
755 int trace_count,
756 jvmtiAllocTraceInfo* other_traces,
757 int other_trace_count,
758 int print_out_comparisons) {
759 if (trace_count != other_trace_count) {
760 return FALSE;
761 }
762
763 int i;
764 for (i = 0; i < trace_count; i++) {
765 jvmtiAllocTraceInfo* trace = traces + i;
766 jvmtiAllocTraceInfo* other_trace = other_traces + i;
767
768 jvmtiStackInfo* stack_info = trace->stack_info;
769 jvmtiStackInfo* other_stack_info = trace->stack_info;
770
771 if (stack_info->frame_count != other_stack_info->frame_count) {
772 return FALSE;
773 }
774
775 if (trace->size != other_trace->size) {
776 return FALSE;
777 }
778
779 if (trace->thread_id != other_trace->thread_id) {
780 return FALSE;
781 }
782
783 jvmtiFrameInfo* frames = stack_info->frame_buffer;
784 jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer;
785 if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) {
786 return FALSE;
787 }
788 }
789
790 return TRUE;
791 }
792
793 JNIEXPORT jboolean JNICALL
794 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
795 jclass cls) {
796 // Get cached first, then get live (since live performs a GC).
797 jvmtiAllocTraceInfo* cached_traces;
798 jint cached_trace_counter;
799 jvmtiError error = (*jvmti)->GetCachedObjectAllocTraces(jvmti, &cached_traces,
800 &cached_trace_counter);
801
802 if (error != JVMTI_ERROR_NONE) {
803 return FALSE;
804 }
805
806 jvmtiAllocTraceInfo* live_traces;
807 jint live_trace_counter;
808 error = (*jvmti)->GetObjectAllocTraces(jvmti, &live_traces,
809 &live_trace_counter);
810
811 if (error != JVMTI_ERROR_NONE) {
812 return FALSE;
813 }
814
815 int result = compare_traces(cached_traces, cached_trace_counter,
816 live_traces, live_trace_counter,
817 PRINT_OUT);
818
819 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
820 return FALSE;
821 }
822 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) live_traces) != JVMTI_ERROR_NONE) {
823 return FALSE;
824 }
825 return result;
826 }
827
828 static long hash(long hash_code, long value) {
829 return hash_code * 31 + value;
830 }
831
832 static long get_hash_code(jvmtiAllocTraceInfo* traces, jint trace_counter) {
833 int hash_code = 17;
834 int i, j;
835
836 hash_code = hash(hash_code, trace_counter);
837 for (i = 0; i < trace_counter; i++) {
838 jvmtiAllocTraceInfo* trace = traces + i;
839
840 hash_code = hash(hash_code, trace->size);
841 hash_code = hash(hash_code, trace->thread_id);
842
843 jvmtiStackInfo* stack_info = trace->stack_info;
844 hash_code = hash(hash_code, stack_info->frame_count);
845
846 int frame_count = stack_info->frame_count;
847 jvmtiFrameInfo* frames = stack_info->frame_buffer;
848 hash_code = hash(hash_code, frame_count);
849 for (j = 0; j < frame_count; j++) {
850 hash_code = hash(hash_code, (long) frames[i].method);
851 hash_code = hash(hash_code, frames[i].location);
852 }
853 }
854
855 return TRUE;
856 }
857
858 JNIEXPORT jlong JNICALL
859 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env,
860 jclass cls) {
861 // Get cached first, then get live.
862 jvmtiAllocTraceInfo* cached_traces;
863 jint cached_trace_counter;
864 jvmtiError error = (*jvmti)->GetCachedObjectAllocTraces(jvmti, &cached_traces,
865 &cached_trace_counter);
866
867 if (error != JVMTI_ERROR_NONE) {
868 return 0;
869 }
870
871 long hash_code = get_hash_code(cached_traces, cached_trace_counter);
872
873 if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
874 return FALSE;
875 }
876
877 return hash_code;
878 }
879
880 JNIEXPORT jboolean JNICALL
881 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
882 jclass cls,
883 jobjectArray frames) {
884 return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
885 }
886
887 #ifdef __cplusplus
888 }
889 #endif
|