diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 211 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 140 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 129 | ||||
-rw-r--r-- | tools/perf/util/data_map.c | 222 | ||||
-rw-r--r-- | tools/perf/util/data_map.h | 31 |
6 files changed, 334 insertions, 401 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 5a429966c995..495eb6d97fa0 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -342,6 +342,7 @@ LIB_H += util/values.h | |||
342 | LIB_H += util/sort.h | 342 | LIB_H += util/sort.h |
343 | LIB_H += util/hist.h | 343 | LIB_H += util/hist.h |
344 | LIB_H += util/thread.h | 344 | LIB_H += util/thread.h |
345 | LIB_H += util/data_map.h | ||
345 | 346 | ||
346 | LIB_OBJS += util/abspath.o | 347 | LIB_OBJS += util/abspath.o |
347 | LIB_OBJS += util/alias.o | 348 | LIB_OBJS += util/alias.o |
@@ -378,6 +379,7 @@ LIB_OBJS += util/trace-event-info.o | |||
378 | LIB_OBJS += util/svghelper.o | 379 | LIB_OBJS += util/svghelper.o |
379 | LIB_OBJS += util/sort.o | 380 | LIB_OBJS += util/sort.o |
380 | LIB_OBJS += util/hist.o | 381 | LIB_OBJS += util/hist.o |
382 | LIB_OBJS += util/data_map.o | ||
381 | 383 | ||
382 | BUILTIN_OBJS += builtin-annotate.o | 384 | BUILTIN_OBJS += builtin-annotate.o |
383 | BUILTIN_OBJS += builtin-help.o | 385 | BUILTIN_OBJS += builtin-help.o |
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(); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 18871380b015..e1df7055ab82 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "util/trace-event.h" | 11 | #include "util/trace-event.h" |
12 | 12 | ||
13 | #include "util/debug.h" | 13 | #include "util/debug.h" |
14 | #include "util/data_map.h" | ||
14 | 15 | ||
15 | #include <sys/types.h> | 16 | #include <sys/types.h> |
16 | #include <sys/prctl.h> | 17 | #include <sys/prctl.h> |
@@ -20,9 +21,6 @@ | |||
20 | #include <math.h> | 21 | #include <math.h> |
21 | 22 | ||
22 | static char const *input_name = "perf.data"; | 23 | static char const *input_name = "perf.data"; |
23 | static int input; | ||
24 | static unsigned long page_size; | ||
25 | static unsigned long mmap_window = 32; | ||
26 | 24 | ||
27 | static unsigned long total_comm = 0; | 25 | static unsigned long total_comm = 0; |
28 | 26 | ||
@@ -35,6 +33,9 @@ static u64 sample_type; | |||
35 | static char default_sort_order[] = "avg, max, switch, runtime"; | 33 | static char default_sort_order[] = "avg, max, switch, runtime"; |
36 | static char *sort_order = default_sort_order; | 34 | static char *sort_order = default_sort_order; |
37 | 35 | ||
36 | static char *cwd; | ||
37 | static int cwdlen; | ||
38 | |||
38 | #define PR_SET_NAME 15 /* Set process name */ | 39 | #define PR_SET_NAME 15 /* Set process name */ |
39 | #define MAX_CPUS 4096 | 40 | #define MAX_CPUS 4096 |
40 | 41 | ||
@@ -1594,129 +1595,43 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
1594 | } | 1595 | } |
1595 | 1596 | ||
1596 | static int | 1597 | static int |
1597 | process_event(event_t *event, unsigned long offset, unsigned long head) | 1598 | process_lost_event(event_t *event __used, |
1599 | unsigned long offset __used, | ||
1600 | unsigned long head __used) | ||
1598 | { | 1601 | { |
1599 | trace_event(event); | 1602 | nr_lost_chunks++; |
1600 | 1603 | nr_lost_events += event->lost.lost; | |
1601 | nr_events++; | ||
1602 | switch (event->header.type) { | ||
1603 | case PERF_RECORD_MMAP: | ||
1604 | return 0; | ||
1605 | case PERF_RECORD_LOST: | ||
1606 | nr_lost_chunks++; | ||
1607 | nr_lost_events += event->lost.lost; | ||
1608 | return 0; | ||
1609 | |||
1610 | case PERF_RECORD_COMM: | ||
1611 | return process_comm_event(event, offset, head); | ||
1612 | 1604 | ||
1613 | case PERF_RECORD_EXIT ... PERF_RECORD_READ: | 1605 | return 0; |
1614 | return 0; | 1606 | } |
1615 | 1607 | ||
1616 | case PERF_RECORD_SAMPLE: | 1608 | static int sample_type_check(u64 type) |
1617 | return process_sample_event(event, offset, head); | 1609 | { |
1610 | sample_type = type; | ||
1618 | 1611 | ||
1619 | case PERF_RECORD_MAX: | 1612 | if (!(sample_type & PERF_SAMPLE_RAW)) { |
1620 | default: | 1613 | fprintf(stderr, |
1614 | "No trace sample to read. Did you call perf record " | ||
1615 | "without -R?"); | ||
1621 | return -1; | 1616 | return -1; |
1622 | } | 1617 | } |
1623 | 1618 | ||
1624 | return 0; | 1619 | return 0; |
1625 | } | 1620 | } |
1626 | 1621 | ||
1622 | static struct perf_file_handler file_handler = { | ||
1623 | .process_sample_event = process_sample_event, | ||
1624 | .process_comm_event = process_comm_event, | ||
1625 | .process_lost_event = process_lost_event, | ||
1626 | .sample_type_check = sample_type_check, | ||
1627 | }; | ||
1628 | |||
1627 | static int read_events(void) | 1629 | static int read_events(void) |
1628 | { | 1630 | { |
1629 | int ret, rc = EXIT_FAILURE; | ||
1630 | unsigned long offset = 0; | ||
1631 | unsigned long head = 0; | ||
1632 | struct stat perf_stat; | ||
1633 | event_t *event; | ||
1634 | uint32_t size; | ||
1635 | char *buf; | ||
1636 | |||
1637 | register_idle_thread(&threads, &last_match); | 1631 | register_idle_thread(&threads, &last_match); |
1632 | register_perf_file_handler(&file_handler); | ||
1638 | 1633 | ||
1639 | input = open(input_name, O_RDONLY); | 1634 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); |
1640 | if (input < 0) { | ||
1641 | perror("failed to open file"); | ||
1642 | exit(-1); | ||
1643 | } | ||
1644 | |||
1645 | ret = fstat(input, &perf_stat); | ||
1646 | if (ret < 0) { | ||
1647 | perror("failed to stat file"); | ||
1648 | exit(-1); | ||
1649 | } | ||
1650 | |||
1651 | if (!perf_stat.st_size) { | ||
1652 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
1653 | exit(0); | ||
1654 | } | ||
1655 | header = perf_header__read(input); | ||
1656 | head = header->data_offset; | ||
1657 | sample_type = perf_header__sample_type(header); | ||
1658 | |||
1659 | if (!(sample_type & PERF_SAMPLE_RAW)) | ||
1660 | die("No trace sample to read. Did you call perf record " | ||
1661 | "without -R?"); | ||
1662 | |||
1663 | if (load_kernel() < 0) { | ||
1664 | perror("failed to load kernel symbols"); | ||
1665 | return EXIT_FAILURE; | ||
1666 | } | ||
1667 | |||
1668 | remap: | ||
1669 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
1670 | MAP_SHARED, input, offset); | ||
1671 | if (buf == MAP_FAILED) { | ||
1672 | perror("failed to mmap file"); | ||
1673 | exit(-1); | ||
1674 | } | ||
1675 | |||
1676 | more: | ||
1677 | event = (event_t *)(buf + head); | ||
1678 | |||
1679 | size = event->header.size; | ||
1680 | if (!size) | ||
1681 | size = 8; | ||
1682 | |||
1683 | if (head + event->header.size >= page_size * mmap_window) { | ||
1684 | unsigned long shift = page_size * (head / page_size); | ||
1685 | int res; | ||
1686 | |||
1687 | res = munmap(buf, page_size * mmap_window); | ||
1688 | assert(res == 0); | ||
1689 | |||
1690 | offset += shift; | ||
1691 | head -= shift; | ||
1692 | goto remap; | ||
1693 | } | ||
1694 | |||
1695 | size = event->header.size; | ||
1696 | |||
1697 | |||
1698 | if (!size || process_event(event, offset, head) < 0) { | ||
1699 | |||
1700 | /* | ||
1701 | * assume we lost track of the stream, check alignment, and | ||
1702 | * increment a single u64 in the hope to catch on again 'soon'. | ||
1703 | */ | ||
1704 | |||
1705 | if (unlikely(head & 7)) | ||
1706 | head &= ~7ULL; | ||
1707 | |||
1708 | size = 8; | ||
1709 | } | ||
1710 | |||
1711 | head += size; | ||
1712 | |||
1713 | if (offset + head < (unsigned long)perf_stat.st_size) | ||
1714 | goto more; | ||
1715 | |||
1716 | rc = EXIT_SUCCESS; | ||
1717 | close(input); | ||
1718 | |||
1719 | return rc; | ||
1720 | } | 1635 | } |
1721 | 1636 | ||
1722 | static void print_bad_events(void) | 1637 | static void print_bad_events(void) |
@@ -1934,7 +1849,6 @@ static int __cmd_record(int argc, const char **argv) | |||
1934 | int cmd_sched(int argc, const char **argv, const char *prefix __used) | 1849 | int cmd_sched(int argc, const char **argv, const char *prefix __used) |
1935 | { | 1850 | { |
1936 | symbol__init(); | 1851 | symbol__init(); |
1937 | page_size = getpagesize(); | ||
1938 | 1852 | ||
1939 | argc = parse_options(argc, argv, sched_options, sched_usage, | 1853 | argc = parse_options(argc, argv, sched_options, sched_usage, |
1940 | PARSE_OPT_STOP_AT_NON_OPTION); | 1854 | PARSE_OPT_STOP_AT_NON_OPTION); |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d9abb4ae5f79..fb3f3c220211 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -12,11 +12,9 @@ | |||
12 | #include "util/debug.h" | 12 | #include "util/debug.h" |
13 | 13 | ||
14 | #include "util/trace-event.h" | 14 | #include "util/trace-event.h" |
15 | #include "util/data_map.h" | ||
15 | 16 | ||
16 | static char const *input_name = "perf.data"; | 17 | static char const *input_name = "perf.data"; |
17 | static int input; | ||
18 | static unsigned long page_size; | ||
19 | static unsigned long mmap_window = 32; | ||
20 | 18 | ||
21 | static unsigned long total = 0; | 19 | static unsigned long total = 0; |
22 | static unsigned long total_comm = 0; | 20 | static unsigned long total_comm = 0; |
@@ -27,6 +25,9 @@ static struct thread *last_match; | |||
27 | static struct perf_header *header; | 25 | static struct perf_header *header; |
28 | static u64 sample_type; | 26 | static u64 sample_type; |
29 | 27 | ||
28 | static char *cwd; | ||
29 | static int cwdlen; | ||
30 | |||
30 | 31 | ||
31 | static int | 32 | static int |
32 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 33 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) |
@@ -112,125 +113,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
112 | return 0; | 113 | return 0; |
113 | } | 114 | } |
114 | 115 | ||
115 | static int | 116 | static int sample_type_check(u64 type) |
116 | process_event(event_t *event, unsigned long offset, unsigned long head) | ||
117 | { | 117 | { |
118 | trace_event(event); | 118 | sample_type = type; |
119 | |||
120 | switch (event->header.type) { | ||
121 | case PERF_RECORD_MMAP ... PERF_RECORD_LOST: | ||
122 | return 0; | ||
123 | |||
124 | case PERF_RECORD_COMM: | ||
125 | return process_comm_event(event, offset, head); | ||
126 | |||
127 | case PERF_RECORD_EXIT ... PERF_RECORD_READ: | ||
128 | return 0; | ||
129 | 119 | ||
130 | case PERF_RECORD_SAMPLE: | 120 | if (!(sample_type & PERF_SAMPLE_RAW)) { |
131 | return process_sample_event(event, offset, head); | 121 | fprintf(stderr, |
132 | 122 | "No trace sample to read. Did you call perf record " | |
133 | case PERF_RECORD_MAX: | 123 | "without -R?"); |
134 | default: | ||
135 | return -1; | 124 | return -1; |
136 | } | 125 | } |
137 | 126 | ||
138 | return 0; | 127 | return 0; |
139 | } | 128 | } |
140 | 129 | ||
130 | static struct perf_file_handler file_handler = { | ||
131 | .process_sample_event = process_sample_event, | ||
132 | .process_comm_event = process_comm_event, | ||
133 | .sample_type_check = sample_type_check, | ||
134 | }; | ||
135 | |||
141 | static int __cmd_trace(void) | 136 | static int __cmd_trace(void) |
142 | { | 137 | { |
143 | int ret, rc = EXIT_FAILURE; | ||
144 | unsigned long offset = 0; | ||
145 | unsigned long head = 0; | ||
146 | unsigned long shift; | ||
147 | struct stat perf_stat; | ||
148 | event_t *event; | ||
149 | uint32_t size; | ||
150 | char *buf; | ||
151 | |||
152 | register_idle_thread(&threads, &last_match); | 138 | register_idle_thread(&threads, &last_match); |
139 | register_perf_file_handler(&file_handler); | ||
153 | 140 | ||
154 | input = open(input_name, O_RDONLY); | 141 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); |
155 | if (input < 0) { | ||
156 | perror("failed to open file"); | ||
157 | exit(-1); | ||
158 | } | ||
159 | |||
160 | ret = fstat(input, &perf_stat); | ||
161 | if (ret < 0) { | ||
162 | perror("failed to stat file"); | ||
163 | exit(-1); | ||
164 | } | ||
165 | |||
166 | if (!perf_stat.st_size) { | ||
167 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
168 | exit(0); | ||
169 | } | ||
170 | header = perf_header__read(input); | ||
171 | head = header->data_offset; | ||
172 | sample_type = perf_header__sample_type(header); | ||
173 | |||
174 | if (!(sample_type & PERF_SAMPLE_RAW)) | ||
175 | die("No trace sample to read. Did you call perf record " | ||
176 | "without -R?"); | ||
177 | |||
178 | if (load_kernel() < 0) { | ||
179 | perror("failed to load kernel symbols"); | ||
180 | return EXIT_FAILURE; | ||
181 | } | ||
182 | |||
183 | shift = page_size * (head / page_size); | ||
184 | offset += shift; | ||
185 | head -= shift; | ||
186 | |||
187 | remap: | ||
188 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
189 | MAP_SHARED, input, offset); | ||
190 | if (buf == MAP_FAILED) { | ||
191 | perror("failed to mmap file"); | ||
192 | exit(-1); | ||
193 | } | ||
194 | |||
195 | more: | ||
196 | event = (event_t *)(buf + head); | ||
197 | |||
198 | if (head + event->header.size >= page_size * mmap_window) { | ||
199 | int res; | ||
200 | |||
201 | shift = page_size * (head / page_size); | ||
202 | res = munmap(buf, page_size * mmap_window); | ||
203 | assert(res == 0); | ||
204 | |||
205 | offset += shift; | ||
206 | head -= shift; | ||
207 | goto remap; | ||
208 | } | ||
209 | |||
210 | size = event->header.size; | ||
211 | |||
212 | if (!size || process_event(event, offset, head) < 0) { | ||
213 | |||
214 | /* | ||
215 | * assume we lost track of the stream, check alignment, and | ||
216 | * increment a single u64 in the hope to catch on again 'soon'. | ||
217 | */ | ||
218 | |||
219 | if (unlikely(head & 7)) | ||
220 | head &= ~7ULL; | ||
221 | |||
222 | size = 8; | ||
223 | } | ||
224 | |||
225 | head += size; | ||
226 | |||
227 | if (offset + head < (unsigned long)perf_stat.st_size) | ||
228 | goto more; | ||
229 | |||
230 | rc = EXIT_SUCCESS; | ||
231 | close(input); | ||
232 | |||
233 | return rc; | ||
234 | } | 142 | } |
235 | 143 | ||
236 | static const char * const annotate_usage[] = { | 144 | static const char * const annotate_usage[] = { |
@@ -249,7 +157,6 @@ static const struct option options[] = { | |||
249 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 157 | int cmd_trace(int argc, const char **argv, const char *prefix __used) |
250 | { | 158 | { |
251 | symbol__init(); | 159 | symbol__init(); |
252 | page_size = getpagesize(); | ||
253 | 160 | ||
254 | argc = parse_options(argc, argv, options, annotate_usage, 0); | 161 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
255 | if (argc) { | 162 | if (argc) { |
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c new file mode 100644 index 000000000000..242b0555ab91 --- /dev/null +++ b/tools/perf/util/data_map.c | |||
@@ -0,0 +1,222 @@ | |||
1 | #include "data_map.h" | ||
2 | #include "symbol.h" | ||
3 | #include "util.h" | ||
4 | #include "debug.h" | ||
5 | |||
6 | |||
7 | static struct perf_file_handler *curr_handler; | ||
8 | static unsigned long mmap_window = 32; | ||
9 | static char __cwd[PATH_MAX]; | ||
10 | |||
11 | static int | ||
12 | process_event_stub(event_t *event __used, | ||
13 | unsigned long offset __used, | ||
14 | unsigned long head __used) | ||
15 | { | ||
16 | return 0; | ||
17 | } | ||
18 | |||
19 | void register_perf_file_handler(struct perf_file_handler *handler) | ||
20 | { | ||
21 | if (!handler->process_sample_event) | ||
22 | handler->process_sample_event = process_event_stub; | ||
23 | if (!handler->process_mmap_event) | ||
24 | handler->process_mmap_event = process_event_stub; | ||
25 | if (!handler->process_comm_event) | ||
26 | handler->process_comm_event = process_event_stub; | ||
27 | if (!handler->process_fork_event) | ||
28 | handler->process_fork_event = process_event_stub; | ||
29 | if (!handler->process_exit_event) | ||
30 | handler->process_exit_event = process_event_stub; | ||
31 | if (!handler->process_lost_event) | ||
32 | handler->process_lost_event = process_event_stub; | ||
33 | if (!handler->process_read_event) | ||
34 | handler->process_read_event = process_event_stub; | ||
35 | if (!handler->process_throttle_event) | ||
36 | handler->process_throttle_event = process_event_stub; | ||
37 | if (!handler->process_unthrottle_event) | ||
38 | handler->process_unthrottle_event = process_event_stub; | ||
39 | |||
40 | curr_handler = handler; | ||
41 | } | ||
42 | |||
43 | static int | ||
44 | process_event(event_t *event, unsigned long offset, unsigned long head) | ||
45 | { | ||
46 | trace_event(event); | ||
47 | |||
48 | switch (event->header.type) { | ||
49 | case PERF_RECORD_SAMPLE: | ||
50 | return curr_handler->process_sample_event(event, offset, head); | ||
51 | case PERF_RECORD_MMAP: | ||
52 | return curr_handler->process_mmap_event(event, offset, head); | ||
53 | case PERF_RECORD_COMM: | ||
54 | return curr_handler->process_comm_event(event, offset, head); | ||
55 | case PERF_RECORD_FORK: | ||
56 | return curr_handler->process_fork_event(event, offset, head); | ||
57 | case PERF_RECORD_EXIT: | ||
58 | return curr_handler->process_exit_event(event, offset, head); | ||
59 | case PERF_RECORD_LOST: | ||
60 | return curr_handler->process_lost_event(event, offset, head); | ||
61 | case PERF_RECORD_READ: | ||
62 | return curr_handler->process_read_event(event, offset, head); | ||
63 | case PERF_RECORD_THROTTLE: | ||
64 | return curr_handler->process_throttle_event(event, offset, head); | ||
65 | case PERF_RECORD_UNTHROTTLE: | ||
66 | return curr_handler->process_unthrottle_event(event, offset, head); | ||
67 | default: | ||
68 | curr_handler->total_unknown++; | ||
69 | return -1; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | int mmap_dispatch_perf_file(struct perf_header **pheader, | ||
74 | const char *input_name, | ||
75 | int force, | ||
76 | int full_paths, | ||
77 | int *cwdlen, | ||
78 | char **cwd) | ||
79 | { | ||
80 | int ret, rc = EXIT_FAILURE; | ||
81 | struct perf_header *header; | ||
82 | unsigned long head, shift; | ||
83 | unsigned long offset = 0; | ||
84 | struct stat input_stat; | ||
85 | size_t page_size; | ||
86 | u64 sample_type; | ||
87 | event_t *event; | ||
88 | uint32_t size; | ||
89 | int input; | ||
90 | char *buf; | ||
91 | |||
92 | if (!curr_handler) | ||
93 | die("Forgot to register perf file handler"); | ||
94 | |||
95 | page_size = getpagesize(); | ||
96 | |||
97 | input = open(input_name, O_RDONLY); | ||
98 | if (input < 0) { | ||
99 | fprintf(stderr, " failed to open file: %s", input_name); | ||
100 | if (!strcmp(input_name, "perf.data")) | ||
101 | fprintf(stderr, " (try 'perf record' first)"); | ||
102 | fprintf(stderr, "\n"); | ||
103 | exit(-1); | ||
104 | } | ||
105 | |||
106 | ret = fstat(input, &input_stat); | ||
107 | if (ret < 0) { | ||
108 | perror("failed to stat file"); | ||
109 | exit(-1); | ||
110 | } | ||
111 | |||
112 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { | ||
113 | fprintf(stderr, "file: %s not owned by current user or root\n", | ||
114 | input_name); | ||
115 | exit(-1); | ||
116 | } | ||
117 | |||
118 | if (!input_stat.st_size) { | ||
119 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
120 | exit(0); | ||
121 | } | ||
122 | |||
123 | *pheader = perf_header__read(input); | ||
124 | header = *pheader; | ||
125 | head = header->data_offset; | ||
126 | |||
127 | sample_type = perf_header__sample_type(header); | ||
128 | |||
129 | if (curr_handler->sample_type_check) | ||
130 | if (curr_handler->sample_type_check(sample_type) < 0) | ||
131 | exit(-1); | ||
132 | |||
133 | if (load_kernel() < 0) { | ||
134 | perror("failed to load kernel symbols"); | ||
135 | return EXIT_FAILURE; | ||
136 | } | ||
137 | |||
138 | if (!full_paths) { | ||
139 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { | ||
140 | perror("failed to get the current directory"); | ||
141 | return EXIT_FAILURE; | ||
142 | } | ||
143 | *cwd = __cwd; | ||
144 | *cwdlen = strlen(*cwd); | ||
145 | } else { | ||
146 | *cwd = NULL; | ||
147 | *cwdlen = 0; | ||
148 | } | ||
149 | |||
150 | shift = page_size * (head / page_size); | ||
151 | offset += shift; | ||
152 | head -= shift; | ||
153 | |||
154 | remap: | ||
155 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
156 | MAP_SHARED, input, offset); | ||
157 | if (buf == MAP_FAILED) { | ||
158 | perror("failed to mmap file"); | ||
159 | exit(-1); | ||
160 | } | ||
161 | |||
162 | more: | ||
163 | event = (event_t *)(buf + head); | ||
164 | |||
165 | size = event->header.size; | ||
166 | if (!size) | ||
167 | size = 8; | ||
168 | |||
169 | if (head + event->header.size >= page_size * mmap_window) { | ||
170 | int munmap_ret; | ||
171 | |||
172 | shift = page_size * (head / page_size); | ||
173 | |||
174 | munmap_ret = munmap(buf, page_size * mmap_window); | ||
175 | assert(munmap_ret == 0); | ||
176 | |||
177 | offset += shift; | ||
178 | head -= shift; | ||
179 | goto remap; | ||
180 | } | ||
181 | |||
182 | size = event->header.size; | ||
183 | |||
184 | dump_printf("\n%p [%p]: event: %d\n", | ||
185 | (void *)(offset + head), | ||
186 | (void *)(long)event->header.size, | ||
187 | event->header.type); | ||
188 | |||
189 | if (!size || process_event(event, offset, head) < 0) { | ||
190 | |||
191 | dump_printf("%p [%p]: skipping unknown header type: %d\n", | ||
192 | (void *)(offset + head), | ||
193 | (void *)(long)(event->header.size), | ||
194 | event->header.type); | ||
195 | |||
196 | /* | ||
197 | * assume we lost track of the stream, check alignment, and | ||
198 | * increment a single u64 in the hope to catch on again 'soon'. | ||
199 | */ | ||
200 | |||
201 | if (unlikely(head & 7)) | ||
202 | head &= ~7ULL; | ||
203 | |||
204 | size = 8; | ||
205 | } | ||
206 | |||
207 | head += size; | ||
208 | |||
209 | if (offset + head >= header->data_offset + header->data_size) | ||
210 | goto done; | ||
211 | |||
212 | if (offset + head < (unsigned long)input_stat.st_size) | ||
213 | goto more; | ||
214 | |||
215 | done: | ||
216 | rc = EXIT_SUCCESS; | ||
217 | close(input); | ||
218 | |||
219 | return rc; | ||
220 | } | ||
221 | |||
222 | |||
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h new file mode 100644 index 000000000000..716d1053b074 --- /dev/null +++ b/tools/perf/util/data_map.h | |||
@@ -0,0 +1,31 @@ | |||
1 | #ifndef __PERF_DATAMAP_H | ||
2 | #define __PERF_DATAMAP_H | ||
3 | |||
4 | #include "event.h" | ||
5 | #include "header.h" | ||
6 | |||
7 | typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long); | ||
8 | |||
9 | struct perf_file_handler { | ||
10 | event_type_handler_t process_sample_event; | ||
11 | event_type_handler_t process_mmap_event; | ||
12 | event_type_handler_t process_comm_event; | ||
13 | event_type_handler_t process_fork_event; | ||
14 | event_type_handler_t process_exit_event; | ||
15 | event_type_handler_t process_lost_event; | ||
16 | event_type_handler_t process_read_event; | ||
17 | event_type_handler_t process_throttle_event; | ||
18 | event_type_handler_t process_unthrottle_event; | ||
19 | int (*sample_type_check)(u64 sample_type); | ||
20 | unsigned long total_unknown; | ||
21 | }; | ||
22 | |||
23 | void register_perf_file_handler(struct perf_file_handler *handler); | ||
24 | int mmap_dispatch_perf_file(struct perf_header **pheader, | ||
25 | const char *input_name, | ||
26 | int force, | ||
27 | int full_paths, | ||
28 | int *cwdlen, | ||
29 | char **cwd); | ||
30 | |||
31 | #endif | ||