684 JNIEXPORT
685 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
686 return Agent_Initialize(jvm, options, reserved);
687 }
688
689 JNIEXPORT
690 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
691 return Agent_Initialize(jvm, options, reserved);
692 }
693
694 JNIEXPORT
695 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
696 return JNI_VERSION_1_8;
697 }
698
699 #define MAX_THREADS 500
700
701 typedef struct ThreadStats {
702 int number_threads;
703 int counts[MAX_THREADS];
704 int not_helper_counts[MAX_THREADS];
705 int index[MAX_THREADS];
706 jthread threads[MAX_THREADS];
707
708 int method_resolution_problem;
709 } ThreadStats;
710
711 static ThreadStats thread_stats;
712
713 static void add_thread_count(jthread thread, int lock, int helper) {
714 int i;
715 jvmtiThreadInfo info;
716 const char* name;
717 char* end;
718 int idx;
719 int err;
720
721 if (lock) {
722 event_storage_lock(&global_event_storage);
723 }
724
725 for (i = 0; i < thread_stats.number_threads; i++) {
726 if (thread_stats.threads[i] == thread) {
727 if (helper) {
728 thread_stats.counts[i]++;
729 } else {
730 thread_stats.not_helper_counts[i]++;
731 }
732
733 if (lock) {
734 event_storage_unlock(&global_event_storage);
735 }
736 return;
737 }
738 }
739
740 thread_stats.threads[thread_stats.number_threads] = thread;
741
742 err = (*jvmti)->GetThreadInfo(jvmti, thread, &info);
743 if (err != JVMTI_ERROR_NONE) {
744 if (lock) {
745 event_storage_unlock(&global_event_storage);
746 }
747
748 // Just to have it accounted as an error...
749 info.name = "Allocator99";
750 }
751
752 if (!strstr(info.name, "Allocator")) {
753 if (lock) {
754 event_storage_unlock(&global_event_storage);
755 }
756
757 // Just to have it accounted as an error...
758 info.name = "Allocator98";
759 }
760
761 name = info.name + 9;
762 end = NULL;
763 idx = strtol(name, &end, 0);
764
765 if (*end == '\0') {
766 if (helper) {
767 thread_stats.counts[thread_stats.number_threads]++;
768 } else {
769 thread_stats.not_helper_counts[thread_stats.number_threads]++;
770 }
771
772 thread_stats.index[thread_stats.number_threads] = idx;
773 thread_stats.number_threads++;
774 } else {
775 fprintf(stderr, "Problem with thread name...: %p %s\n", thread, name);
776 }
777
778 if (PRINT_OUT) {
779 fprintf(stderr, "Added %s - %p - %d - lock: %d\n", info.name, thread, idx, lock);
780 }
781
782 if (lock) {
783 event_storage_unlock(&global_event_storage);
784 }
785 }
786
787 static void print_thread_stats() {
788 int i;
789 event_storage_lock(&global_event_storage);
790 fprintf(stderr, "Method resolution problem: %d\n", thread_stats.method_resolution_problem);
791 fprintf(stderr, "Thread count:\n");
792 for (i = 0; i < thread_stats.number_threads; i++) {
793 fprintf(stderr, "\t%p: %d: %d - %d\n", thread_stats.threads[i],
794 thread_stats.index[i],
795 thread_stats.counts[i],
796 thread_stats.not_helper_counts[i]);
797 }
798 event_storage_unlock(&global_event_storage);
799 }
800
801 JNIEXPORT
802 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
803 JNIEnv* jni_env,
804 jthread thread,
805 jobject object,
806 jclass object_klass,
807 jlong size) {
808 add_thread_count(thread, 1, 1);
809
810 if (event_storage_get_compaction_required(&global_event_storage)) {
811 event_storage_compact(&global_event_storage, jni_env);
812 }
813
814 event_storage_add(&global_event_storage, jni_env, thread, object,
815 object_klass, size);
816 }
817
818 JNIEXPORT
819 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
820 JNIEnv* jni_env,
821 jthread thread,
822 jobject object,
823 jclass object_klass,
824 jlong size) {
825 event_storage_add(&second_global_event_storage, jni_env, thread, object,
826 object_klass, size);
827 }
828
829 JNIEXPORT
830 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
831 event_storage_set_compaction_required(&global_event_storage);
832 }
833
834 static int enable_notifications() {
835 if (check_error((*jvmti)->SetEventNotificationMode(
836 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
837 "Set event notifications")) {
838 return 1;
839 }
840
841 return check_error((*jvmti)->SetEventNotificationMode(
842 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
843 "Set event notifications");
844 }
845
846 static int enable_notifications_for_two_threads(jthread first, jthread second) {
847 if (check_error((*jvmti)->SetEventNotificationMode(
848 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
849 "Set event notifications")) {
850 return 0;
851 }
852
853 if (check_error((*jvmti)->SetEventNotificationMode(
854 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, first),
855 "Set event notifications")) {
856 return 0;
857 }
858
859 // Second thread should fail.
860 if (check_error((*jvmti)->SetEventNotificationMode(
861 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, second),
862 "Set event notifications")) {
863 return 0;
864 }
865
866 return 1;
867 }
868
869 static
870 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
871 jint res;
872 jvmtiEventCallbacks callbacks;
873 jvmtiCapabilities caps;
874
875 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &jvmti,
876 JVMTI_VERSION_9));
877 if (res != JNI_OK || jvmti == NULL) {
878 fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
879 return JNI_ERR;
880 }
881
882 // Get second jvmti environment.
883 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &second_jvmti,
884 JVMTI_VERSION_9));
885 if (res != JNI_OK || second_jvmti == NULL) {
886 fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
887 return JNI_ERR;
888 }
932 JNIEXPORT void JNICALL
933 Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
934 (*jvmti)->SetHeapSamplingInterval(jvmti, value);
935 }
936
937 JNIEXPORT jboolean JNICALL
938 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
939 return event_storage_get_count(&global_event_storage) == 0;
940 }
941
942 JNIEXPORT jint JNICALL
943 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
944 return event_storage_get_count(&global_event_storage);
945 }
946
947 JNIEXPORT void JNICALL
948 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
949 enable_notifications();
950 }
951
952 JNIEXPORT jboolean JNICALL
953 Java_MyPackage_HeapMonitor_enableSamplingEventsForTwoThreads(JNIEnv* env,
954 jclass cls,
955 jthread first,
956 jthread second) {
957 return enable_notifications_for_two_threads(first, second);
958 }
959
960 JNIEXPORT void JNICALL
961 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
962 check_error((*jvmti)->SetEventNotificationMode(
963 jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
964 "Set event notifications");
965
966 check_error((*jvmti)->SetEventNotificationMode(
967 jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
968 "Garbage Collection Finish");
969 }
970
971 JNIEXPORT jboolean JNICALL
972 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
973 jobjectArray frames,
974 jboolean check_lines) {
975 jboolean result;
976 jsize size = JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG2(env, frames));
977 ExpectedContentFrame *native_frames;
978
979 if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
1082 "Sampling interval -1024 passed\n")){
1083 return FALSE;
1084 }
1085
1086 return TRUE;
1087 }
1088
1089 JNIEXPORT jdouble JNICALL
1090 Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1091 return event_storage_get_average_size(&global_event_storage);
1092 }
1093
1094 typedef struct sThreadsFound {
1095 jthread* threads;
1096 int num_threads;
1097 } ThreadsFound;
1098
1099 JNIEXPORT jboolean JNICALL
1100 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1101 jint num_threads) {
1102
1103 print_thread_stats();
1104 // Ensure we got stacks from at least num_threads.
1105 return thread_stats.number_threads >= num_threads;
1106 }
1107
1108 JNIEXPORT
1109 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1110 JNIEnv* jni_env,
1111 jthread thread,
1112 jobject object,
1113 jclass object_klass,
1114 jlong size) {
1115 // Nop for now, two agents are not yet implemented.
1116 assert(0);
1117 }
1118
1119 JNIEXPORT jboolean JNICALL
1120 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1121 JNIEnv* env, jclass cls) {
1122 // Currently this method should be failing directly at the AddCapability step
|
684 JNIEXPORT
685 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
686 return Agent_Initialize(jvm, options, reserved);
687 }
688
689 JNIEXPORT
690 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
691 return Agent_Initialize(jvm, options, reserved);
692 }
693
694 JNIEXPORT
695 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
696 return JNI_VERSION_1_8;
697 }
698
699 #define MAX_THREADS 500
700
701 typedef struct ThreadStats {
702 int number_threads;
703 int counts[MAX_THREADS];
704 char* threads[MAX_THREADS];
705 } ThreadStats;
706
707 static ThreadStats thread_stats;
708
709 JNIEXPORT jboolean JNICALL
710 Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(
711 JNIEnv* env, jclass cls, jthread thread) {
712 int i;
713 jvmtiThreadInfo info;
714 jvmtiError err;
715 char* expected_name;
716 int found_thread = FALSE;
717
718 err = (*jvmti)->GetThreadInfo(jvmti, thread, &info);
719 expected_name = info.name;
720
721 if (err != JVMTI_ERROR_NONE) {
722 fprintf(stderr, "Failed to get thread information\n");
723 return FALSE;
724 }
725
726 for (i = 0; i < thread_stats.number_threads; i++) {
727 if (strcmp(expected_name, thread_stats.threads[i])) {
728 return FALSE;
729 } else {
730 found_thread = TRUE;
731 }
732 }
733 return found_thread;
734 }
735
736 static void add_thread_count(jthread thread) {
737 int i;
738 jvmtiThreadInfo info;
739 const char* name;
740 char* end;
741 int idx;
742 jvmtiError err;
743
744 err = (*jvmti)->GetThreadInfo(jvmti, thread, &info);
745 if (err != JVMTI_ERROR_NONE) {
746 fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",
747 thread);
748 return;
749 }
750
751 event_storage_lock(&global_event_storage);
752 for (i = 0; i < thread_stats.number_threads; i++) {
753 if (!strcmp(thread_stats.threads[i], info.name)) {
754 thread_stats.counts[i]++;
755 event_storage_unlock(&global_event_storage);
756 return;
757 }
758 }
759
760 thread_stats.threads[thread_stats.number_threads] = info.name;
761 thread_stats.counts[thread_stats.number_threads]++;
762 thread_stats.number_threads++;
763 event_storage_unlock(&global_event_storage);
764 }
765
766 JNIEXPORT void JNICALL
767 Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(
768 JNIEnv* env, jclass cls, jthread thread) {
769 fprintf(stderr, "Enabling for %p\n", thread);
770 check_error((*jvmti)->SetEventNotificationMode(
771 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),
772 "Set event notifications for a single thread");
773 }
774
775 static void print_thread_stats() {
776 int i;
777 event_storage_lock(&global_event_storage);
778 fprintf(stderr, "Thread count:\n");
779 for (i = 0; i < thread_stats.number_threads; i++) {
780 fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);
781 }
782 event_storage_unlock(&global_event_storage);
783 }
784
785 JNIEXPORT
786 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
787 JNIEnv* jni_env,
788 jthread thread,
789 jobject object,
790 jclass object_klass,
791 jlong size) {
792 add_thread_count(thread);
793
794 if (event_storage_get_compaction_required(&global_event_storage)) {
795 event_storage_compact(&global_event_storage, jni_env);
796 }
797
798 event_storage_add(&global_event_storage, jni_env, thread, object,
799 object_klass, size);
800 }
801
802 JNIEXPORT
803 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
804 JNIEnv* jni_env,
805 jthread thread,
806 jobject object,
807 jclass object_klass,
808 jlong size) {
809 event_storage_add(&second_global_event_storage, jni_env, thread, object,
810 object_klass, size);
811 }
812
813 JNIEXPORT
814 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
815 event_storage_set_compaction_required(&global_event_storage);
816 }
817
818 static int enable_notifications() {
819 if (check_error((*jvmti)->SetEventNotificationMode(
820 jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
821 "Set event notifications")) {
822 return 1;
823 }
824
825 return check_error((*jvmti)->SetEventNotificationMode(
826 jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
827 "Set event notifications");
828 }
829
830 static
831 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
832 jint res;
833 jvmtiEventCallbacks callbacks;
834 jvmtiCapabilities caps;
835
836 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &jvmti,
837 JVMTI_VERSION_9));
838 if (res != JNI_OK || jvmti == NULL) {
839 fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
840 return JNI_ERR;
841 }
842
843 // Get second jvmti environment.
844 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &second_jvmti,
845 JVMTI_VERSION_9));
846 if (res != JNI_OK || second_jvmti == NULL) {
847 fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
848 return JNI_ERR;
849 }
893 JNIEXPORT void JNICALL
894 Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
895 (*jvmti)->SetHeapSamplingInterval(jvmti, value);
896 }
897
898 JNIEXPORT jboolean JNICALL
899 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
900 return event_storage_get_count(&global_event_storage) == 0;
901 }
902
903 JNIEXPORT jint JNICALL
904 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
905 return event_storage_get_count(&global_event_storage);
906 }
907
908 JNIEXPORT void JNICALL
909 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
910 enable_notifications();
911 }
912
913 JNIEXPORT void JNICALL
914 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
915 check_error((*jvmti)->SetEventNotificationMode(
916 jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
917 "Set event notifications");
918
919 check_error((*jvmti)->SetEventNotificationMode(
920 jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
921 "Garbage Collection Finish");
922 }
923
924 JNIEXPORT jboolean JNICALL
925 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
926 jobjectArray frames,
927 jboolean check_lines) {
928 jboolean result;
929 jsize size = JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG2(env, frames));
930 ExpectedContentFrame *native_frames;
931
932 if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
1035 "Sampling interval -1024 passed\n")){
1036 return FALSE;
1037 }
1038
1039 return TRUE;
1040 }
1041
1042 JNIEXPORT jdouble JNICALL
1043 Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1044 return event_storage_get_average_size(&global_event_storage);
1045 }
1046
1047 typedef struct sThreadsFound {
1048 jthread* threads;
1049 int num_threads;
1050 } ThreadsFound;
1051
1052 JNIEXPORT jboolean JNICALL
1053 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1054 jint num_threads) {
1055 print_thread_stats();
1056 // Ensure we got stacks from at least num_threads.
1057 return thread_stats.number_threads >= num_threads;
1058 }
1059
1060 JNIEXPORT
1061 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1062 JNIEnv* jni_env,
1063 jthread thread,
1064 jobject object,
1065 jclass object_klass,
1066 jlong size) {
1067 // Nop for now, two agents are not yet implemented.
1068 assert(0);
1069 }
1070
1071 JNIEXPORT jboolean JNICALL
1072 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1073 JNIEnv* env, jclass cls) {
1074 // Currently this method should be failing directly at the AddCapability step
|