Commit | Line | Data |
---|---|---|
016e92fb FW |
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 | ||
d8f66248 ACM |
11 | static int process_event_stub(event_t *event __used, |
12 | struct perf_session *session __used) | |
016e92fb | 13 | { |
62daacb5 | 14 | dump_printf(": unhandled!\n"); |
016e92fb FW |
15 | return 0; |
16 | } | |
17 | ||
18 | void register_perf_file_handler(struct perf_file_handler *handler) | |
19 | { | |
20 | if (!handler->process_sample_event) | |
21 | handler->process_sample_event = process_event_stub; | |
22 | if (!handler->process_mmap_event) | |
23 | handler->process_mmap_event = process_event_stub; | |
24 | if (!handler->process_comm_event) | |
25 | handler->process_comm_event = process_event_stub; | |
26 | if (!handler->process_fork_event) | |
27 | handler->process_fork_event = process_event_stub; | |
28 | if (!handler->process_exit_event) | |
29 | handler->process_exit_event = process_event_stub; | |
30 | if (!handler->process_lost_event) | |
31 | handler->process_lost_event = process_event_stub; | |
32 | if (!handler->process_read_event) | |
33 | handler->process_read_event = process_event_stub; | |
34 | if (!handler->process_throttle_event) | |
35 | handler->process_throttle_event = process_event_stub; | |
36 | if (!handler->process_unthrottle_event) | |
37 | handler->process_unthrottle_event = process_event_stub; | |
38 | ||
39 | curr_handler = handler; | |
40 | } | |
41 | ||
62daacb5 ACM |
42 | static const char *event__name[] = { |
43 | [0] = "TOTAL", | |
44 | [PERF_RECORD_MMAP] = "MMAP", | |
45 | [PERF_RECORD_LOST] = "LOST", | |
46 | [PERF_RECORD_COMM] = "COMM", | |
47 | [PERF_RECORD_EXIT] = "EXIT", | |
48 | [PERF_RECORD_THROTTLE] = "THROTTLE", | |
49 | [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", | |
50 | [PERF_RECORD_FORK] = "FORK", | |
51 | [PERF_RECORD_READ] = "READ", | |
52 | [PERF_RECORD_SAMPLE] = "SAMPLE", | |
53 | }; | |
54 | ||
55 | unsigned long event__total[PERF_RECORD_MAX]; | |
56 | ||
57 | void event__print_totals(void) | |
58 | { | |
59 | int i; | |
60 | for (i = 0; i < PERF_RECORD_MAX; ++i) | |
61 | pr_info("%10s events: %10ld\n", | |
62 | event__name[i], event__total[i]); | |
63 | } | |
64 | ||
d8f66248 ACM |
65 | static int process_event(event_t *event, struct perf_session *session, |
66 | unsigned long offset, unsigned long head) | |
016e92fb FW |
67 | { |
68 | trace_event(event); | |
69 | ||
62daacb5 ACM |
70 | if (event->header.type < PERF_RECORD_MAX) { |
71 | dump_printf("%p [%p]: PERF_RECORD_%s", | |
72 | (void *)(offset + head), | |
73 | (void *)(long)(event->header.size), | |
74 | event__name[event->header.type]); | |
75 | ++event__total[0]; | |
76 | ++event__total[event->header.type]; | |
77 | } | |
78 | ||
016e92fb FW |
79 | switch (event->header.type) { |
80 | case PERF_RECORD_SAMPLE: | |
d8f66248 | 81 | return curr_handler->process_sample_event(event, session); |
016e92fb | 82 | case PERF_RECORD_MMAP: |
d8f66248 | 83 | return curr_handler->process_mmap_event(event, session); |
016e92fb | 84 | case PERF_RECORD_COMM: |
d8f66248 | 85 | return curr_handler->process_comm_event(event, session); |
016e92fb | 86 | case PERF_RECORD_FORK: |
d8f66248 | 87 | return curr_handler->process_fork_event(event, session); |
016e92fb | 88 | case PERF_RECORD_EXIT: |
d8f66248 | 89 | return curr_handler->process_exit_event(event, session); |
016e92fb | 90 | case PERF_RECORD_LOST: |
d8f66248 | 91 | return curr_handler->process_lost_event(event, session); |
016e92fb | 92 | case PERF_RECORD_READ: |
d8f66248 | 93 | return curr_handler->process_read_event(event, session); |
016e92fb | 94 | case PERF_RECORD_THROTTLE: |
d8f66248 | 95 | return curr_handler->process_throttle_event(event, session); |
016e92fb | 96 | case PERF_RECORD_UNTHROTTLE: |
d8f66248 | 97 | return curr_handler->process_unthrottle_event(event, session); |
016e92fb FW |
98 | default: |
99 | curr_handler->total_unknown++; | |
100 | return -1; | |
101 | } | |
102 | } | |
103 | ||
716d69e4 | 104 | int perf_header__read_build_ids(int input, u64 offset, u64 size) |
8d06367f | 105 | { |
8d06367f ACM |
106 | struct build_id_event bev; |
107 | char filename[PATH_MAX]; | |
716d69e4 | 108 | u64 limit = offset + size; |
8d06367f ACM |
109 | int err = -1; |
110 | ||
9e827dd0 | 111 | while (offset < limit) { |
8d06367f ACM |
112 | struct dso *dso; |
113 | ssize_t len; | |
114 | ||
115 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | |
116 | goto out; | |
117 | ||
118 | len = bev.header.size - sizeof(bev); | |
119 | if (read(input, filename, len) != len) | |
120 | goto out; | |
121 | ||
122 | dso = dsos__findnew(filename); | |
123 | if (dso != NULL) | |
124 | dso__set_build_id(dso, &bev.build_id); | |
125 | ||
126 | offset += bev.header.size; | |
127 | } | |
128 | err = 0; | |
129 | out: | |
130 | return err; | |
131 | } | |
132 | ||
94c744b6 ACM |
133 | int perf_session__process_events(struct perf_session *self, |
134 | int full_paths, int *cwdlen, char **cwd) | |
016e92fb | 135 | { |
6b0cb5f9 | 136 | int err; |
016e92fb FW |
137 | unsigned long head, shift; |
138 | unsigned long offset = 0; | |
016e92fb FW |
139 | size_t page_size; |
140 | u64 sample_type; | |
141 | event_t *event; | |
142 | uint32_t size; | |
016e92fb FW |
143 | char *buf; |
144 | ||
6b0cb5f9 ACM |
145 | if (curr_handler == NULL) { |
146 | pr_debug("Forgot to register perf file handler\n"); | |
147 | return -EINVAL; | |
148 | } | |
016e92fb FW |
149 | |
150 | page_size = getpagesize(); | |
151 | ||
94c744b6 ACM |
152 | head = self->header.data_offset; |
153 | sample_type = perf_header__sample_type(&self->header); | |
016e92fb | 154 | |
6b0cb5f9 ACM |
155 | err = -EINVAL; |
156 | if (curr_handler->sample_type_check && | |
157 | curr_handler->sample_type_check(sample_type) < 0) | |
94c744b6 | 158 | goto out_err; |
016e92fb | 159 | |
016e92fb FW |
160 | if (!full_paths) { |
161 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { | |
6b0cb5f9 ACM |
162 | pr_err("failed to get the current directory\n"); |
163 | err = -errno; | |
94c744b6 | 164 | goto out_err; |
016e92fb FW |
165 | } |
166 | *cwd = __cwd; | |
167 | *cwdlen = strlen(*cwd); | |
168 | } else { | |
169 | *cwd = NULL; | |
170 | *cwdlen = 0; | |
171 | } | |
172 | ||
173 | shift = page_size * (head / page_size); | |
174 | offset += shift; | |
175 | head -= shift; | |
176 | ||
177 | remap: | |
6b0cb5f9 | 178 | buf = mmap(NULL, page_size * mmap_window, PROT_READ, |
94c744b6 | 179 | MAP_SHARED, self->fd, offset); |
016e92fb | 180 | if (buf == MAP_FAILED) { |
6b0cb5f9 ACM |
181 | pr_err("failed to mmap file\n"); |
182 | err = -errno; | |
94c744b6 | 183 | goto out_err; |
016e92fb FW |
184 | } |
185 | ||
186 | more: | |
187 | event = (event_t *)(buf + head); | |
188 | ||
189 | size = event->header.size; | |
190 | if (!size) | |
191 | size = 8; | |
192 | ||
193 | if (head + event->header.size >= page_size * mmap_window) { | |
194 | int munmap_ret; | |
195 | ||
196 | shift = page_size * (head / page_size); | |
197 | ||
198 | munmap_ret = munmap(buf, page_size * mmap_window); | |
199 | assert(munmap_ret == 0); | |
200 | ||
201 | offset += shift; | |
202 | head -= shift; | |
203 | goto remap; | |
204 | } | |
205 | ||
206 | size = event->header.size; | |
207 | ||
208 | dump_printf("\n%p [%p]: event: %d\n", | |
209 | (void *)(offset + head), | |
210 | (void *)(long)event->header.size, | |
211 | event->header.type); | |
212 | ||
d8f66248 | 213 | if (!size || process_event(event, self, offset, head) < 0) { |
016e92fb FW |
214 | |
215 | dump_printf("%p [%p]: skipping unknown header type: %d\n", | |
216 | (void *)(offset + head), | |
217 | (void *)(long)(event->header.size), | |
218 | event->header.type); | |
219 | ||
220 | /* | |
221 | * assume we lost track of the stream, check alignment, and | |
222 | * increment a single u64 in the hope to catch on again 'soon'. | |
223 | */ | |
224 | ||
225 | if (unlikely(head & 7)) | |
226 | head &= ~7ULL; | |
227 | ||
228 | size = 8; | |
229 | } | |
230 | ||
231 | head += size; | |
232 | ||
94c744b6 | 233 | if (offset + head >= self->header.data_offset + self->header.data_size) |
016e92fb FW |
234 | goto done; |
235 | ||
94c744b6 | 236 | if (offset + head < self->size) |
016e92fb FW |
237 | goto more; |
238 | ||
239 | done: | |
6b0cb5f9 | 240 | err = 0; |
94c744b6 | 241 | out_err: |
6b0cb5f9 | 242 | return err; |
016e92fb | 243 | } |