diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 211 |
1 files changed, 34 insertions, 177 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 12f8c868fcd7..87c4582303bf 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "util/parse-options.h" | 26 | #include "util/parse-options.h" |
27 | #include "util/parse-events.h" | 27 | #include "util/parse-events.h" |
28 | 28 | ||
29 | #include "util/data_map.h" | ||
29 | #include "util/thread.h" | 30 | #include "util/thread.h" |
30 | #include "util/sort.h" | 31 | #include "util/sort.h" |
31 | #include "util/hist.h" | 32 | #include "util/hist.h" |
@@ -37,7 +38,6 @@ static char *dso_list_str, *comm_list_str, *sym_list_str, | |||
37 | static struct strlist *dso_list, *comm_list, *sym_list; | 38 | static struct strlist *dso_list, *comm_list, *sym_list; |
38 | 39 | ||
39 | static int force; | 40 | static int force; |
40 | static int input; | ||
41 | 41 | ||
42 | static int full_paths; | 42 | static int full_paths; |
43 | static int show_nr_samples; | 43 | static int show_nr_samples; |
@@ -48,15 +48,11 @@ static struct perf_read_values show_threads_values; | |||
48 | static char default_pretty_printing_style[] = "normal"; | 48 | static char default_pretty_printing_style[] = "normal"; |
49 | static char *pretty_printing_style = default_pretty_printing_style; | 49 | static char *pretty_printing_style = default_pretty_printing_style; |
50 | 50 | ||
51 | static unsigned long page_size; | ||
52 | static unsigned long mmap_window = 32; | ||
53 | |||
54 | static int exclude_other = 1; | 51 | static int exclude_other = 1; |
55 | 52 | ||
56 | static char callchain_default_opt[] = "fractal,0.5"; | 53 | static char callchain_default_opt[] = "fractal,0.5"; |
57 | 54 | ||
58 | static char __cwd[PATH_MAX]; | 55 | static char *cwd; |
59 | static char *cwd = __cwd; | ||
60 | static int cwdlen; | 56 | static int cwdlen; |
61 | 57 | ||
62 | static struct rb_root threads; | 58 | static struct rb_root threads; |
@@ -815,208 +811,71 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head) | |||
815 | return 0; | 811 | return 0; |
816 | } | 812 | } |
817 | 813 | ||
818 | static int | 814 | static int sample_type_check(u64 type) |
819 | process_event(event_t *event, unsigned long offset, unsigned long head) | ||
820 | { | ||
821 | trace_event(event); | ||
822 | |||
823 | switch (event->header.type) { | ||
824 | case PERF_RECORD_SAMPLE: | ||
825 | return process_sample_event(event, offset, head); | ||
826 | |||
827 | case PERF_RECORD_MMAP: | ||
828 | return process_mmap_event(event, offset, head); | ||
829 | |||
830 | case PERF_RECORD_COMM: | ||
831 | return process_comm_event(event, offset, head); | ||
832 | |||
833 | case PERF_RECORD_FORK: | ||
834 | case PERF_RECORD_EXIT: | ||
835 | return process_task_event(event, offset, head); | ||
836 | |||
837 | case PERF_RECORD_LOST: | ||
838 | return process_lost_event(event, offset, head); | ||
839 | |||
840 | case PERF_RECORD_READ: | ||
841 | return process_read_event(event, offset, head); | ||
842 | |||
843 | /* | ||
844 | * We dont process them right now but they are fine: | ||
845 | */ | ||
846 | |||
847 | case PERF_RECORD_THROTTLE: | ||
848 | case PERF_RECORD_UNTHROTTLE: | ||
849 | return 0; | ||
850 | |||
851 | default: | ||
852 | return -1; | ||
853 | } | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static int __cmd_report(void) | ||
859 | { | 815 | { |
860 | int ret, rc = EXIT_FAILURE; | 816 | sample_type = type; |
861 | unsigned long offset = 0; | ||
862 | unsigned long head, shift; | ||
863 | struct stat input_stat; | ||
864 | struct thread *idle; | ||
865 | event_t *event; | ||
866 | uint32_t size; | ||
867 | char *buf; | ||
868 | |||
869 | idle = register_idle_thread(&threads, &last_match); | ||
870 | thread__comm_adjust(idle); | ||
871 | |||
872 | if (show_threads) | ||
873 | perf_read_values_init(&show_threads_values); | ||
874 | |||
875 | input = open(input_name, O_RDONLY); | ||
876 | if (input < 0) { | ||
877 | fprintf(stderr, " failed to open file: %s", input_name); | ||
878 | if (!strcmp(input_name, "perf.data")) | ||
879 | fprintf(stderr, " (try 'perf record' first)"); | ||
880 | fprintf(stderr, "\n"); | ||
881 | exit(-1); | ||
882 | } | ||
883 | |||
884 | ret = fstat(input, &input_stat); | ||
885 | if (ret < 0) { | ||
886 | perror("failed to stat file"); | ||
887 | exit(-1); | ||
888 | } | ||
889 | |||
890 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { | ||
891 | fprintf(stderr, "file: %s not owned by current user or root\n", input_name); | ||
892 | exit(-1); | ||
893 | } | ||
894 | |||
895 | if (!input_stat.st_size) { | ||
896 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
897 | exit(0); | ||
898 | } | ||
899 | |||
900 | header = perf_header__read(input); | ||
901 | head = header->data_offset; | ||
902 | |||
903 | sample_type = perf_header__sample_type(header); | ||
904 | 817 | ||
905 | if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 818 | if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
906 | if (sort__has_parent) { | 819 | if (sort__has_parent) { |
907 | fprintf(stderr, "selected --sort parent, but no" | 820 | fprintf(stderr, "selected --sort parent, but no" |
908 | " callchain data. Did you call" | 821 | " callchain data. Did you call" |
909 | " perf record without -g?\n"); | 822 | " perf record without -g?\n"); |
910 | exit(-1); | 823 | return -1; |
911 | } | 824 | } |
912 | if (callchain) { | 825 | if (callchain) { |
913 | fprintf(stderr, "selected -g but no callchain data." | 826 | fprintf(stderr, "selected -g but no callchain data." |
914 | " Did you call perf record without" | 827 | " Did you call perf record without" |
915 | " -g?\n"); | 828 | " -g?\n"); |
916 | exit(-1); | 829 | return -1; |
917 | } | 830 | } |
918 | } else if (callchain_param.mode != CHAIN_NONE && !callchain) { | 831 | } else if (callchain_param.mode != CHAIN_NONE && !callchain) { |
919 | callchain = 1; | 832 | callchain = 1; |
920 | if (register_callchain_param(&callchain_param) < 0) { | 833 | if (register_callchain_param(&callchain_param) < 0) { |
921 | fprintf(stderr, "Can't register callchain" | 834 | fprintf(stderr, "Can't register callchain" |
922 | " params\n"); | 835 | " params\n"); |
923 | exit(-1); | 836 | return -1; |
924 | } | 837 | } |
925 | } | 838 | } |
926 | 839 | ||
927 | if (load_kernel() < 0) { | 840 | return 0; |
928 | perror("failed to load kernel symbols"); | 841 | } |
929 | return EXIT_FAILURE; | ||
930 | } | ||
931 | |||
932 | if (!full_paths) { | ||
933 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { | ||
934 | perror("failed to get the current directory"); | ||
935 | return EXIT_FAILURE; | ||
936 | } | ||
937 | cwdlen = strlen(cwd); | ||
938 | } else { | ||
939 | cwd = NULL; | ||
940 | cwdlen = 0; | ||
941 | } | ||
942 | |||
943 | shift = page_size * (head / page_size); | ||
944 | offset += shift; | ||
945 | head -= shift; | ||
946 | |||
947 | remap: | ||
948 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
949 | MAP_SHARED, input, offset); | ||
950 | if (buf == MAP_FAILED) { | ||
951 | perror("failed to mmap file"); | ||
952 | exit(-1); | ||
953 | } | ||
954 | |||
955 | more: | ||
956 | event = (event_t *)(buf + head); | ||
957 | |||
958 | size = event->header.size; | ||
959 | if (!size) | ||
960 | size = 8; | ||
961 | |||
962 | if (head + event->header.size >= page_size * mmap_window) { | ||
963 | int munmap_ret; | ||
964 | |||
965 | shift = page_size * (head / page_size); | ||
966 | |||
967 | munmap_ret = munmap(buf, page_size * mmap_window); | ||
968 | assert(munmap_ret == 0); | ||
969 | |||
970 | offset += shift; | ||
971 | head -= shift; | ||
972 | goto remap; | ||
973 | } | ||
974 | |||
975 | size = event->header.size; | ||
976 | |||
977 | dump_printf("\n%p [%p]: event: %d\n", | ||
978 | (void *)(offset + head), | ||
979 | (void *)(long)event->header.size, | ||
980 | event->header.type); | ||
981 | |||
982 | if (!size || process_event(event, offset, head) < 0) { | ||
983 | |||
984 | dump_printf("%p [%p]: skipping unknown header type: %d\n", | ||
985 | (void *)(offset + head), | ||
986 | (void *)(long)(event->header.size), | ||
987 | event->header.type); | ||
988 | |||
989 | total_unknown++; | ||
990 | 842 | ||
991 | /* | 843 | static struct perf_file_handler file_handler = { |
992 | * assume we lost track of the stream, check alignment, and | 844 | .process_sample_event = process_sample_event, |
993 | * increment a single u64 in the hope to catch on again 'soon'. | 845 | .process_mmap_event = process_mmap_event, |
994 | */ | 846 | .process_comm_event = process_comm_event, |
847 | .process_exit_event = process_task_event, | ||
848 | .process_fork_event = process_task_event, | ||
849 | .process_lost_event = process_lost_event, | ||
850 | .process_read_event = process_read_event, | ||
851 | .sample_type_check = sample_type_check, | ||
852 | }; | ||
995 | 853 | ||
996 | if (unlikely(head & 7)) | ||
997 | head &= ~7ULL; | ||
998 | 854 | ||
999 | size = 8; | 855 | static int __cmd_report(void) |
1000 | } | 856 | { |
857 | struct thread *idle; | ||
858 | int ret; | ||
1001 | 859 | ||
1002 | head += size; | 860 | idle = register_idle_thread(&threads, &last_match); |
861 | thread__comm_adjust(idle); | ||
1003 | 862 | ||
1004 | if (offset + head >= header->data_offset + header->data_size) | 863 | if (show_threads) |
1005 | goto done; | 864 | perf_read_values_init(&show_threads_values); |
1006 | 865 | ||
1007 | if (offset + head < (unsigned long)input_stat.st_size) | 866 | register_perf_file_handler(&file_handler); |
1008 | goto more; | ||
1009 | 867 | ||
1010 | done: | 868 | ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths, |
1011 | rc = EXIT_SUCCESS; | 869 | &cwdlen, &cwd); |
1012 | close(input); | 870 | if (ret) |
871 | return ret; | ||
1013 | 872 | ||
1014 | dump_printf(" IP events: %10ld\n", total); | 873 | dump_printf(" IP events: %10ld\n", total); |
1015 | dump_printf(" mmap events: %10ld\n", total_mmap); | 874 | dump_printf(" mmap events: %10ld\n", total_mmap); |
1016 | dump_printf(" comm events: %10ld\n", total_comm); | 875 | dump_printf(" comm events: %10ld\n", total_comm); |
1017 | dump_printf(" fork events: %10ld\n", total_fork); | 876 | dump_printf(" fork events: %10ld\n", total_fork); |
1018 | dump_printf(" lost events: %10ld\n", total_lost); | 877 | dump_printf(" lost events: %10ld\n", total_lost); |
1019 | dump_printf(" unknown events: %10ld\n", total_unknown); | 878 | dump_printf(" unknown events: %10ld\n", file_handler.total_unknown); |
1020 | 879 | ||
1021 | if (dump_trace) | 880 | if (dump_trace) |
1022 | return 0; | 881 | return 0; |
@@ -1034,7 +893,7 @@ done: | |||
1034 | if (show_threads) | 893 | if (show_threads) |
1035 | perf_read_values_destroy(&show_threads_values); | 894 | perf_read_values_destroy(&show_threads_values); |
1036 | 895 | ||
1037 | return rc; | 896 | return ret; |
1038 | } | 897 | } |
1039 | 898 | ||
1040 | static int | 899 | static int |
@@ -1177,8 +1036,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
1177 | { | 1036 | { |
1178 | symbol__init(); | 1037 | symbol__init(); |
1179 | 1038 | ||
1180 | page_size = getpagesize(); | ||
1181 | |||
1182 | argc = parse_options(argc, argv, options, report_usage, 0); | 1039 | argc = parse_options(argc, argv, options, report_usage, 0); |
1183 | 1040 | ||
1184 | setup_sorting(); | 1041 | setup_sorting(); |