aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-10-07 06:47:31 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-08 10:56:32 -0400
commit016e92fbc9ef33689cf654f343a94383d43235e7 (patch)
treeedf9dc21d037ea138300b7e7e32574e6f6f17fb2
parent03456a158d9067d2f657bec170506009db81756d (diff)
perf tools: Unify perf.data mapping and events handling
This librarizes the perf.data file mapping and handling in various perf tools, roughly reducing the amount of code and fixing the places that mmap from beginning of the file whereas we want to mmap from the beginning of the data, leading to page fault because the mmap window is too small since the trace info are written in the file too. TODO: - convert perf timechart too Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arjan van de Ven <arjan@infradead.org> LKML-Reference: <20091007104729.GD5043@nowhere> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-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