aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-report.c211
-rw-r--r--tools/perf/builtin-sched.c140
-rw-r--r--tools/perf/builtin-trace.c129
-rw-r--r--tools/perf/util/data_map.c222
-rw-r--r--tools/perf/util/data_map.h31
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
342LIB_H += util/sort.h 342LIB_H += util/sort.h
343LIB_H += util/hist.h 343LIB_H += util/hist.h
344LIB_H += util/thread.h 344LIB_H += util/thread.h
345LIB_H += util/data_map.h
345 346
346LIB_OBJS += util/abspath.o 347LIB_OBJS += util/abspath.o
347LIB_OBJS += util/alias.o 348LIB_OBJS += util/alias.o
@@ -378,6 +379,7 @@ LIB_OBJS += util/trace-event-info.o
378LIB_OBJS += util/svghelper.o 379LIB_OBJS += util/svghelper.o
379LIB_OBJS += util/sort.o 380LIB_OBJS += util/sort.o
380LIB_OBJS += util/hist.o 381LIB_OBJS += util/hist.o
382LIB_OBJS += util/data_map.o
381 383
382BUILTIN_OBJS += builtin-annotate.o 384BUILTIN_OBJS += builtin-annotate.o
383BUILTIN_OBJS += builtin-help.o 385BUILTIN_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,
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
38 39
39static int force; 40static int force;
40static int input;
41 41
42static int full_paths; 42static int full_paths;
43static int show_nr_samples; 43static int show_nr_samples;
@@ -48,15 +48,11 @@ static struct perf_read_values show_threads_values;
48static char default_pretty_printing_style[] = "normal"; 48static char default_pretty_printing_style[] = "normal";
49static char *pretty_printing_style = default_pretty_printing_style; 49static char *pretty_printing_style = default_pretty_printing_style;
50 50
51static unsigned long page_size;
52static unsigned long mmap_window = 32;
53
54static int exclude_other = 1; 51static int exclude_other = 1;
55 52
56static char callchain_default_opt[] = "fractal,0.5"; 53static char callchain_default_opt[] = "fractal,0.5";
57 54
58static char __cwd[PATH_MAX]; 55static char *cwd;
59static char *cwd = __cwd;
60static int cwdlen; 56static int cwdlen;
61 57
62static struct rb_root threads; 58static 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
818static int 814static int sample_type_check(u64 type)
819process_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
858static 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
947remap:
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
955more:
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 /* 843static 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; 855static 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
1010done: 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
1040static int 899static 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
22static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26 24
27static unsigned long total_comm = 0; 25static unsigned long total_comm = 0;
28 26
@@ -35,6 +33,9 @@ static u64 sample_type;
35static char default_sort_order[] = "avg, max, switch, runtime"; 33static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order; 34static char *sort_order = default_sort_order;
37 35
36static char *cwd;
37static 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
1596static int 1597static int
1597process_event(event_t *event, unsigned long offset, unsigned long head) 1598process_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: 1608static 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
1622static 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
1627static int read_events(void) 1629static 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
1668remap:
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
1676more:
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
1722static void print_bad_events(void) 1637static void print_bad_events(void)
@@ -1934,7 +1849,6 @@ static int __cmd_record(int argc, const char **argv)
1934int cmd_sched(int argc, const char **argv, const char *prefix __used) 1849int 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
16static char const *input_name = "perf.data"; 17static char const *input_name = "perf.data";
17static int input;
18static unsigned long page_size;
19static unsigned long mmap_window = 32;
20 18
21static unsigned long total = 0; 19static unsigned long total = 0;
22static unsigned long total_comm = 0; 20static unsigned long total_comm = 0;
@@ -27,6 +25,9 @@ static struct thread *last_match;
27static struct perf_header *header; 25static struct perf_header *header;
28static u64 sample_type; 26static u64 sample_type;
29 27
28static char *cwd;
29static int cwdlen;
30
30 31
31static int 32static int
32process_comm_event(event_t *event, unsigned long offset, unsigned long head) 33process_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
115static int 116static int sample_type_check(u64 type)
116process_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
130static 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
141static int __cmd_trace(void) 136static 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
187remap:
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
195more:
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
236static const char * const annotate_usage[] = { 144static const char * const annotate_usage[] = {
@@ -249,7 +157,6 @@ static const struct option options[] = {
249int cmd_trace(int argc, const char **argv, const char *prefix __used) 157int 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
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int
12process_event_stub(event_t *event __used,
13 unsigned long offset __used,
14 unsigned long head __used)
15{
16 return 0;
17}
18
19void 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
43static int
44process_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
73int 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
154remap:
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
162more:
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
215done:
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
7typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
8
9struct 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
23void register_perf_file_handler(struct perf_file_handler *handler);
24int 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