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 | } | ||
