diff options
Diffstat (limited to 'tools/perf/util/data_map.c')
-rw-r--r-- | tools/perf/util/data_map.c | 222 |
1 files changed, 222 insertions, 0 deletions
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 | |||