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