diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 108 |
1 files changed, 98 insertions, 10 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e3ccdb46d6c4..604e14f6a6f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | 2 | ||
3 | #include <byteswap.h> | ||
3 | #include <unistd.h> | 4 | #include <unistd.h> |
4 | #include <sys/types.h> | 5 | #include <sys/types.h> |
5 | 6 | ||
@@ -201,21 +202,88 @@ void event__print_totals(void) | |||
201 | event__name[i], event__total[i]); | 202 | event__name[i], event__total[i]); |
202 | } | 203 | } |
203 | 204 | ||
205 | void mem_bswap_64(void *src, int byte_size) | ||
206 | { | ||
207 | u64 *m = src; | ||
208 | |||
209 | while (byte_size > 0) { | ||
210 | *m = bswap_64(*m); | ||
211 | byte_size -= sizeof(u64); | ||
212 | ++m; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void event__all64_swap(event_t *self) | ||
217 | { | ||
218 | struct perf_event_header *hdr = &self->header; | ||
219 | mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); | ||
220 | } | ||
221 | |||
222 | static void event__comm_swap(event_t *self) | ||
223 | { | ||
224 | self->comm.pid = bswap_32(self->comm.pid); | ||
225 | self->comm.tid = bswap_32(self->comm.tid); | ||
226 | } | ||
227 | |||
228 | static void event__mmap_swap(event_t *self) | ||
229 | { | ||
230 | self->mmap.pid = bswap_32(self->mmap.pid); | ||
231 | self->mmap.tid = bswap_32(self->mmap.tid); | ||
232 | self->mmap.start = bswap_64(self->mmap.start); | ||
233 | self->mmap.len = bswap_64(self->mmap.len); | ||
234 | self->mmap.pgoff = bswap_64(self->mmap.pgoff); | ||
235 | } | ||
236 | |||
237 | static void event__task_swap(event_t *self) | ||
238 | { | ||
239 | self->fork.pid = bswap_32(self->fork.pid); | ||
240 | self->fork.tid = bswap_32(self->fork.tid); | ||
241 | self->fork.ppid = bswap_32(self->fork.ppid); | ||
242 | self->fork.ptid = bswap_32(self->fork.ptid); | ||
243 | self->fork.time = bswap_64(self->fork.time); | ||
244 | } | ||
245 | |||
246 | static void event__read_swap(event_t *self) | ||
247 | { | ||
248 | self->read.pid = bswap_32(self->read.pid); | ||
249 | self->read.tid = bswap_32(self->read.tid); | ||
250 | self->read.value = bswap_64(self->read.value); | ||
251 | self->read.time_enabled = bswap_64(self->read.time_enabled); | ||
252 | self->read.time_running = bswap_64(self->read.time_running); | ||
253 | self->read.id = bswap_64(self->read.id); | ||
254 | } | ||
255 | |||
256 | typedef void (*event__swap_op)(event_t *self); | ||
257 | |||
258 | static event__swap_op event__swap_ops[] = { | ||
259 | [PERF_RECORD_MMAP] = event__mmap_swap, | ||
260 | [PERF_RECORD_COMM] = event__comm_swap, | ||
261 | [PERF_RECORD_FORK] = event__task_swap, | ||
262 | [PERF_RECORD_EXIT] = event__task_swap, | ||
263 | [PERF_RECORD_LOST] = event__all64_swap, | ||
264 | [PERF_RECORD_READ] = event__read_swap, | ||
265 | [PERF_RECORD_SAMPLE] = event__all64_swap, | ||
266 | [PERF_RECORD_MAX] = NULL, | ||
267 | }; | ||
268 | |||
204 | static int perf_session__process_event(struct perf_session *self, | 269 | static int perf_session__process_event(struct perf_session *self, |
205 | event_t *event, | 270 | event_t *event, |
206 | struct perf_event_ops *ops, | 271 | struct perf_event_ops *ops, |
207 | unsigned long offset, unsigned long head) | 272 | u64 offset, u64 head) |
208 | { | 273 | { |
209 | trace_event(event); | 274 | trace_event(event); |
210 | 275 | ||
211 | if (event->header.type < PERF_RECORD_MAX) { | 276 | if (event->header.type < PERF_RECORD_MAX) { |
212 | dump_printf("%#lx [%#x]: PERF_RECORD_%s", | 277 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", |
213 | offset + head, event->header.size, | 278 | offset + head, event->header.size, |
214 | event__name[event->header.type]); | 279 | event__name[event->header.type]); |
215 | ++event__total[0]; | 280 | ++event__total[0]; |
216 | ++event__total[event->header.type]; | 281 | ++event__total[event->header.type]; |
217 | } | 282 | } |
218 | 283 | ||
284 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | ||
285 | event__swap_ops[event->header.type](event); | ||
286 | |||
219 | switch (event->header.type) { | 287 | switch (event->header.type) { |
220 | case PERF_RECORD_SAMPLE: | 288 | case PERF_RECORD_SAMPLE: |
221 | return ops->sample(event, self); | 289 | return ops->sample(event, self); |
@@ -241,7 +309,15 @@ static int perf_session__process_event(struct perf_session *self, | |||
241 | } | 309 | } |
242 | } | 310 | } |
243 | 311 | ||
244 | int perf_header__read_build_ids(int input, u64 offset, u64 size) | 312 | void perf_event_header__bswap(struct perf_event_header *self) |
313 | { | ||
314 | self->type = bswap_32(self->type); | ||
315 | self->misc = bswap_16(self->misc); | ||
316 | self->size = bswap_16(self->size); | ||
317 | } | ||
318 | |||
319 | int perf_header__read_build_ids(struct perf_header *self, | ||
320 | int input, u64 offset, u64 size) | ||
245 | { | 321 | { |
246 | struct build_id_event bev; | 322 | struct build_id_event bev; |
247 | char filename[PATH_MAX]; | 323 | char filename[PATH_MAX]; |
@@ -256,6 +332,9 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size) | |||
256 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 332 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) |
257 | goto out; | 333 | goto out; |
258 | 334 | ||
335 | if (self->needs_swap) | ||
336 | perf_event_header__bswap(&bev.header); | ||
337 | |||
259 | len = bev.header.size - sizeof(bev); | 338 | len = bev.header.size - sizeof(bev); |
260 | if (read(input, filename, len) != len) | 339 | if (read(input, filename, len) != len) |
261 | goto out; | 340 | goto out; |
@@ -292,9 +371,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
292 | int perf_session__process_events(struct perf_session *self, | 371 | int perf_session__process_events(struct perf_session *self, |
293 | struct perf_event_ops *ops) | 372 | struct perf_event_ops *ops) |
294 | { | 373 | { |
295 | int err; | 374 | int err, mmap_prot, mmap_flags; |
296 | unsigned long head, shift; | 375 | u64 head, shift; |
297 | unsigned long offset = 0; | 376 | u64 offset = 0; |
298 | size_t page_size; | 377 | size_t page_size; |
299 | event_t *event; | 378 | event_t *event; |
300 | uint32_t size; | 379 | uint32_t size; |
@@ -330,9 +409,16 @@ out_getcwd_err: | |||
330 | offset += shift; | 409 | offset += shift; |
331 | head -= shift; | 410 | head -= shift; |
332 | 411 | ||
412 | mmap_prot = PROT_READ; | ||
413 | mmap_flags = MAP_SHARED; | ||
414 | |||
415 | if (self->header.needs_swap) { | ||
416 | mmap_prot |= PROT_WRITE; | ||
417 | mmap_flags = MAP_PRIVATE; | ||
418 | } | ||
333 | remap: | 419 | remap: |
334 | buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, | 420 | buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, |
335 | MAP_SHARED, self->fd, offset); | 421 | mmap_flags, self->fd, offset); |
336 | if (buf == MAP_FAILED) { | 422 | if (buf == MAP_FAILED) { |
337 | pr_err("failed to mmap file\n"); | 423 | pr_err("failed to mmap file\n"); |
338 | err = -errno; | 424 | err = -errno; |
@@ -342,6 +428,8 @@ remap: | |||
342 | more: | 428 | more: |
343 | event = (event_t *)(buf + head); | 429 | event = (event_t *)(buf + head); |
344 | 430 | ||
431 | if (self->header.needs_swap) | ||
432 | perf_event_header__bswap(&event->header); | ||
345 | size = event->header.size; | 433 | size = event->header.size; |
346 | if (size == 0) | 434 | if (size == 0) |
347 | size = 8; | 435 | size = 8; |
@@ -361,12 +449,12 @@ more: | |||
361 | 449 | ||
362 | size = event->header.size; | 450 | size = event->header.size; |
363 | 451 | ||
364 | dump_printf("\n%#lx [%#x]: event: %d\n", | 452 | dump_printf("\n%#Lx [%#x]: event: %d\n", |
365 | offset + head, event->header.size, event->header.type); | 453 | offset + head, event->header.size, event->header.type); |
366 | 454 | ||
367 | if (size == 0 || | 455 | if (size == 0 || |
368 | perf_session__process_event(self, event, ops, offset, head) < 0) { | 456 | perf_session__process_event(self, event, ops, offset, head) < 0) { |
369 | dump_printf("%#lx [%#x]: skipping unknown header type: %d\n", | 457 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", |
370 | offset + head, event->header.size, | 458 | offset + head, event->header.size, |
371 | event->header.type); | 459 | event->header.type); |
372 | /* | 460 | /* |