diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 185 |
1 files changed, 177 insertions, 8 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6702ac28754b..6ac62ae6b8fa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -228,6 +228,15 @@ static int process_finished_round(struct perf_tool *tool, | |||
228 | union perf_event *event, | 228 | union perf_event *event, |
229 | struct perf_session *session); | 229 | struct perf_session *session); |
230 | 230 | ||
231 | static int process_id_index_stub(struct perf_tool *tool __maybe_unused, | ||
232 | union perf_event *event __maybe_unused, | ||
233 | struct perf_session *perf_session | ||
234 | __maybe_unused) | ||
235 | { | ||
236 | dump_printf(": unhandled!\n"); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
231 | void perf_tool__fill_defaults(struct perf_tool *tool) | 240 | void perf_tool__fill_defaults(struct perf_tool *tool) |
232 | { | 241 | { |
233 | if (tool->sample == NULL) | 242 | if (tool->sample == NULL) |
@@ -262,6 +271,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
262 | else | 271 | else |
263 | tool->finished_round = process_finished_round_stub; | 272 | tool->finished_round = process_finished_round_stub; |
264 | } | 273 | } |
274 | if (tool->id_index == NULL) | ||
275 | tool->id_index = process_id_index_stub; | ||
265 | } | 276 | } |
266 | 277 | ||
267 | static void swap_sample_id_all(union perf_event *event, void *data) | 278 | static void swap_sample_id_all(union perf_event *event, void *data) |
@@ -460,6 +471,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { | |||
460 | [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, | 471 | [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, |
461 | [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, | 472 | [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, |
462 | [PERF_RECORD_HEADER_BUILD_ID] = NULL, | 473 | [PERF_RECORD_HEADER_BUILD_ID] = NULL, |
474 | [PERF_RECORD_ID_INDEX] = perf_event__all64_swap, | ||
463 | [PERF_RECORD_HEADER_MAX] = NULL, | 475 | [PERF_RECORD_HEADER_MAX] = NULL, |
464 | }; | 476 | }; |
465 | 477 | ||
@@ -580,15 +592,46 @@ static void regs_dump__printf(u64 mask, u64 *regs) | |||
580 | } | 592 | } |
581 | } | 593 | } |
582 | 594 | ||
595 | static const char *regs_abi[] = { | ||
596 | [PERF_SAMPLE_REGS_ABI_NONE] = "none", | ||
597 | [PERF_SAMPLE_REGS_ABI_32] = "32-bit", | ||
598 | [PERF_SAMPLE_REGS_ABI_64] = "64-bit", | ||
599 | }; | ||
600 | |||
601 | static inline const char *regs_dump_abi(struct regs_dump *d) | ||
602 | { | ||
603 | if (d->abi > PERF_SAMPLE_REGS_ABI_64) | ||
604 | return "unknown"; | ||
605 | |||
606 | return regs_abi[d->abi]; | ||
607 | } | ||
608 | |||
609 | static void regs__printf(const char *type, struct regs_dump *regs) | ||
610 | { | ||
611 | u64 mask = regs->mask; | ||
612 | |||
613 | printf("... %s regs: mask 0x%" PRIx64 " ABI %s\n", | ||
614 | type, | ||
615 | mask, | ||
616 | regs_dump_abi(regs)); | ||
617 | |||
618 | regs_dump__printf(mask, regs->regs); | ||
619 | } | ||
620 | |||
583 | static void regs_user__printf(struct perf_sample *sample) | 621 | static void regs_user__printf(struct perf_sample *sample) |
584 | { | 622 | { |
585 | struct regs_dump *user_regs = &sample->user_regs; | 623 | struct regs_dump *user_regs = &sample->user_regs; |
586 | 624 | ||
587 | if (user_regs->regs) { | 625 | if (user_regs->regs) |
588 | u64 mask = user_regs->mask; | 626 | regs__printf("user", user_regs); |
589 | printf("... user regs: mask 0x%" PRIx64 "\n", mask); | 627 | } |
590 | regs_dump__printf(mask, user_regs->regs); | 628 | |
591 | } | 629 | static void regs_intr__printf(struct perf_sample *sample) |
630 | { | ||
631 | struct regs_dump *intr_regs = &sample->intr_regs; | ||
632 | |||
633 | if (intr_regs->regs) | ||
634 | regs__printf("intr", intr_regs); | ||
592 | } | 635 | } |
593 | 636 | ||
594 | static void stack_user__printf(struct stack_dump *dump) | 637 | static void stack_user__printf(struct stack_dump *dump) |
@@ -687,6 +730,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
687 | if (sample_type & PERF_SAMPLE_REGS_USER) | 730 | if (sample_type & PERF_SAMPLE_REGS_USER) |
688 | regs_user__printf(sample); | 731 | regs_user__printf(sample); |
689 | 732 | ||
733 | if (sample_type & PERF_SAMPLE_REGS_INTR) | ||
734 | regs_intr__printf(sample); | ||
735 | |||
690 | if (sample_type & PERF_SAMPLE_STACK_USER) | 736 | if (sample_type & PERF_SAMPLE_STACK_USER) |
691 | stack_user__printf(&sample->user_stack); | 737 | stack_user__printf(&sample->user_stack); |
692 | 738 | ||
@@ -888,11 +934,26 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
888 | return tool->build_id(tool, event, session); | 934 | return tool->build_id(tool, event, session); |
889 | case PERF_RECORD_FINISHED_ROUND: | 935 | case PERF_RECORD_FINISHED_ROUND: |
890 | return tool->finished_round(tool, event, session); | 936 | return tool->finished_round(tool, event, session); |
937 | case PERF_RECORD_ID_INDEX: | ||
938 | return tool->id_index(tool, event, session); | ||
891 | default: | 939 | default: |
892 | return -EINVAL; | 940 | return -EINVAL; |
893 | } | 941 | } |
894 | } | 942 | } |
895 | 943 | ||
944 | int perf_session__deliver_synth_event(struct perf_session *session, | ||
945 | union perf_event *event, | ||
946 | struct perf_sample *sample, | ||
947 | struct perf_tool *tool) | ||
948 | { | ||
949 | events_stats__inc(&session->stats, event->header.type); | ||
950 | |||
951 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | ||
952 | return perf_session__process_user_event(session, event, tool, 0); | ||
953 | |||
954 | return perf_session__deliver_event(session, event, sample, tool, 0); | ||
955 | } | ||
956 | |||
896 | static void event_swap(union perf_event *event, bool sample_id_all) | 957 | static void event_swap(union perf_event *event, bool sample_id_all) |
897 | { | 958 | { |
898 | perf_event__swap_op swap; | 959 | perf_event__swap_op swap; |
@@ -1417,9 +1478,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | |||
1417 | if (symbol_conf.use_callchain && sample->callchain) { | 1478 | if (symbol_conf.use_callchain && sample->callchain) { |
1418 | struct addr_location node_al; | 1479 | struct addr_location node_al; |
1419 | 1480 | ||
1420 | if (machine__resolve_callchain(al->machine, evsel, al->thread, | 1481 | if (thread__resolve_callchain(al->thread, evsel, |
1421 | sample, NULL, NULL, | 1482 | sample, NULL, NULL, |
1422 | PERF_MAX_STACK_DEPTH) != 0) { | 1483 | PERF_MAX_STACK_DEPTH) != 0) { |
1423 | if (verbose) | 1484 | if (verbose) |
1424 | error("Failed to resolve callchain. Skipping\n"); | 1485 | error("Failed to resolve callchain. Skipping\n"); |
1425 | return; | 1486 | return; |
@@ -1594,3 +1655,111 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, | |||
1594 | out: | 1655 | out: |
1595 | return err; | 1656 | return err; |
1596 | } | 1657 | } |
1658 | |||
1659 | int perf_event__process_id_index(struct perf_tool *tool __maybe_unused, | ||
1660 | union perf_event *event, | ||
1661 | struct perf_session *session) | ||
1662 | { | ||
1663 | struct perf_evlist *evlist = session->evlist; | ||
1664 | struct id_index_event *ie = &event->id_index; | ||
1665 | size_t i, nr, max_nr; | ||
1666 | |||
1667 | max_nr = (ie->header.size - sizeof(struct id_index_event)) / | ||
1668 | sizeof(struct id_index_entry); | ||
1669 | nr = ie->nr; | ||
1670 | if (nr > max_nr) | ||
1671 | return -EINVAL; | ||
1672 | |||
1673 | if (dump_trace) | ||
1674 | fprintf(stdout, " nr: %zu\n", nr); | ||
1675 | |||
1676 | for (i = 0; i < nr; i++) { | ||
1677 | struct id_index_entry *e = &ie->entries[i]; | ||
1678 | struct perf_sample_id *sid; | ||
1679 | |||
1680 | if (dump_trace) { | ||
1681 | fprintf(stdout, " ... id: %"PRIu64, e->id); | ||
1682 | fprintf(stdout, " idx: %"PRIu64, e->idx); | ||
1683 | fprintf(stdout, " cpu: %"PRId64, e->cpu); | ||
1684 | fprintf(stdout, " tid: %"PRId64"\n", e->tid); | ||
1685 | } | ||
1686 | |||
1687 | sid = perf_evlist__id2sid(evlist, e->id); | ||
1688 | if (!sid) | ||
1689 | return -ENOENT; | ||
1690 | sid->idx = e->idx; | ||
1691 | sid->cpu = e->cpu; | ||
1692 | sid->tid = e->tid; | ||
1693 | } | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | int perf_event__synthesize_id_index(struct perf_tool *tool, | ||
1698 | perf_event__handler_t process, | ||
1699 | struct perf_evlist *evlist, | ||
1700 | struct machine *machine) | ||
1701 | { | ||
1702 | union perf_event *ev; | ||
1703 | struct perf_evsel *evsel; | ||
1704 | size_t nr = 0, i = 0, sz, max_nr, n; | ||
1705 | int err; | ||
1706 | |||
1707 | pr_debug2("Synthesizing id index\n"); | ||
1708 | |||
1709 | max_nr = (UINT16_MAX - sizeof(struct id_index_event)) / | ||
1710 | sizeof(struct id_index_entry); | ||
1711 | |||
1712 | evlist__for_each(evlist, evsel) | ||
1713 | nr += evsel->ids; | ||
1714 | |||
1715 | n = nr > max_nr ? max_nr : nr; | ||
1716 | sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry); | ||
1717 | ev = zalloc(sz); | ||
1718 | if (!ev) | ||
1719 | return -ENOMEM; | ||
1720 | |||
1721 | ev->id_index.header.type = PERF_RECORD_ID_INDEX; | ||
1722 | ev->id_index.header.size = sz; | ||
1723 | ev->id_index.nr = n; | ||
1724 | |||
1725 | evlist__for_each(evlist, evsel) { | ||
1726 | u32 j; | ||
1727 | |||
1728 | for (j = 0; j < evsel->ids; j++) { | ||
1729 | struct id_index_entry *e; | ||
1730 | struct perf_sample_id *sid; | ||
1731 | |||
1732 | if (i >= n) { | ||
1733 | err = process(tool, ev, NULL, machine); | ||
1734 | if (err) | ||
1735 | goto out_err; | ||
1736 | nr -= n; | ||
1737 | i = 0; | ||
1738 | } | ||
1739 | |||
1740 | e = &ev->id_index.entries[i++]; | ||
1741 | |||
1742 | e->id = evsel->id[j]; | ||
1743 | |||
1744 | sid = perf_evlist__id2sid(evlist, e->id); | ||
1745 | if (!sid) { | ||
1746 | free(ev); | ||
1747 | return -ENOENT; | ||
1748 | } | ||
1749 | |||
1750 | e->idx = sid->idx; | ||
1751 | e->cpu = sid->cpu; | ||
1752 | e->tid = sid->tid; | ||
1753 | } | ||
1754 | } | ||
1755 | |||
1756 | sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry); | ||
1757 | ev->id_index.header.size = sz; | ||
1758 | ev->id_index.nr = nr; | ||
1759 | |||
1760 | err = process(tool, ev, NULL, machine); | ||
1761 | out_err: | ||
1762 | free(ev); | ||
1763 | |||
1764 | return err; | ||
1765 | } | ||