diff options
| -rw-r--r-- | tools/perf/perf.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 46 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 44 |
5 files changed, 87 insertions, 6 deletions
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 511c2831aa81..1dabb8553499 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -52,6 +52,7 @@ struct record_opts { | |||
| 52 | bool sample_weight; | 52 | bool sample_weight; |
| 53 | bool sample_time; | 53 | bool sample_time; |
| 54 | bool period; | 54 | bool period; |
| 55 | bool sample_intr_regs; | ||
| 55 | unsigned int freq; | 56 | unsigned int freq; |
| 56 | unsigned int mmap_pages; | 57 | unsigned int mmap_pages; |
| 57 | unsigned int user_freq; | 58 | unsigned int user_freq; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7be389735402..09b9e8d3fcf7 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -188,6 +188,7 @@ struct perf_sample { | |||
| 188 | struct ip_callchain *callchain; | 188 | struct ip_callchain *callchain; |
| 189 | struct branch_stack *branch_stack; | 189 | struct branch_stack *branch_stack; |
| 190 | struct regs_dump user_regs; | 190 | struct regs_dump user_regs; |
| 191 | struct regs_dump intr_regs; | ||
| 191 | struct stack_dump user_stack; | 192 | struct stack_dump user_stack; |
| 192 | struct sample_read read; | 193 | struct sample_read read; |
| 193 | }; | 194 | }; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 12b4396c7175..34344ffa79ca 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -661,6 +661,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
| 661 | if (callchain_param.enabled && !evsel->no_aux_samples) | 661 | if (callchain_param.enabled && !evsel->no_aux_samples) |
| 662 | perf_evsel__config_callgraph(evsel); | 662 | perf_evsel__config_callgraph(evsel); |
| 663 | 663 | ||
| 664 | if (opts->sample_intr_regs) { | ||
| 665 | attr->sample_regs_intr = PERF_REGS_MASK; | ||
| 666 | perf_evsel__set_sample_bit(evsel, REGS_INTR); | ||
| 667 | } | ||
| 668 | |||
| 664 | if (target__has_cpu(&opts->target)) | 669 | if (target__has_cpu(&opts->target)) |
| 665 | perf_evsel__set_sample_bit(evsel, CPU); | 670 | perf_evsel__set_sample_bit(evsel, CPU); |
| 666 | 671 | ||
| @@ -1037,6 +1042,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
| 1037 | ret += PRINT_ATTR_X64(branch_sample_type); | 1042 | ret += PRINT_ATTR_X64(branch_sample_type); |
| 1038 | ret += PRINT_ATTR_X64(sample_regs_user); | 1043 | ret += PRINT_ATTR_X64(sample_regs_user); |
| 1039 | ret += PRINT_ATTR_U32(sample_stack_user); | 1044 | ret += PRINT_ATTR_U32(sample_stack_user); |
| 1045 | ret += PRINT_ATTR_X64(sample_regs_intr); | ||
| 1040 | 1046 | ||
| 1041 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); | 1047 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); |
| 1042 | 1048 | ||
| @@ -1536,6 +1542,23 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 1536 | array++; | 1542 | array++; |
| 1537 | } | 1543 | } |
| 1538 | 1544 | ||
| 1545 | data->intr_regs.abi = PERF_SAMPLE_REGS_ABI_NONE; | ||
| 1546 | if (type & PERF_SAMPLE_REGS_INTR) { | ||
| 1547 | OVERFLOW_CHECK_u64(array); | ||
| 1548 | data->intr_regs.abi = *array; | ||
| 1549 | array++; | ||
| 1550 | |||
| 1551 | if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) { | ||
| 1552 | u64 mask = evsel->attr.sample_regs_intr; | ||
| 1553 | |||
| 1554 | sz = hweight_long(mask) * sizeof(u64); | ||
| 1555 | OVERFLOW_CHECK(array, sz, max_size); | ||
| 1556 | data->intr_regs.mask = mask; | ||
| 1557 | data->intr_regs.regs = (u64 *)array; | ||
| 1558 | array = (void *)array + sz; | ||
| 1559 | } | ||
| 1560 | } | ||
| 1561 | |||
| 1539 | return 0; | 1562 | return 0; |
| 1540 | } | 1563 | } |
| 1541 | 1564 | ||
| @@ -1631,6 +1654,16 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | |||
| 1631 | if (type & PERF_SAMPLE_TRANSACTION) | 1654 | if (type & PERF_SAMPLE_TRANSACTION) |
| 1632 | result += sizeof(u64); | 1655 | result += sizeof(u64); |
| 1633 | 1656 | ||
| 1657 | if (type & PERF_SAMPLE_REGS_INTR) { | ||
| 1658 | if (sample->intr_regs.abi) { | ||
| 1659 | result += sizeof(u64); | ||
| 1660 | sz = hweight_long(sample->intr_regs.mask) * sizeof(u64); | ||
| 1661 | result += sz; | ||
| 1662 | } else { | ||
| 1663 | result += sizeof(u64); | ||
| 1664 | } | ||
| 1665 | } | ||
| 1666 | |||
| 1634 | return result; | 1667 | return result; |
| 1635 | } | 1668 | } |
| 1636 | 1669 | ||
| @@ -1809,6 +1842,17 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
| 1809 | array++; | 1842 | array++; |
| 1810 | } | 1843 | } |
| 1811 | 1844 | ||
| 1845 | if (type & PERF_SAMPLE_REGS_INTR) { | ||
| 1846 | if (sample->intr_regs.abi) { | ||
| 1847 | *array++ = sample->intr_regs.abi; | ||
| 1848 | sz = hweight_long(sample->intr_regs.mask) * sizeof(u64); | ||
| 1849 | memcpy(array, sample->intr_regs.regs, sz); | ||
| 1850 | array = (void *)array + sz; | ||
| 1851 | } else { | ||
| 1852 | *array++ = 0; | ||
| 1853 | } | ||
| 1854 | } | ||
| 1855 | |||
| 1812 | return 0; | 1856 | return 0; |
| 1813 | } | 1857 | } |
| 1814 | 1858 | ||
| @@ -1938,7 +1982,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value) | |||
| 1938 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), | 1982 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), |
| 1939 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | 1983 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
| 1940 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | 1984 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
| 1941 | bit_name(IDENTIFIER), | 1985 | bit_name(IDENTIFIER), bit_name(REGS_INTR), |
| 1942 | { .name = NULL, } | 1986 | { .name = NULL, } |
| 1943 | }; | 1987 | }; |
| 1944 | #undef bit_name | 1988 | #undef bit_name |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 76442caca37e..05fab7a188dc 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -2143,6 +2143,7 @@ static const int attr_file_abi_sizes[] = { | |||
| 2143 | [1] = PERF_ATTR_SIZE_VER1, | 2143 | [1] = PERF_ATTR_SIZE_VER1, |
| 2144 | [2] = PERF_ATTR_SIZE_VER2, | 2144 | [2] = PERF_ATTR_SIZE_VER2, |
| 2145 | [3] = PERF_ATTR_SIZE_VER3, | 2145 | [3] = PERF_ATTR_SIZE_VER3, |
| 2146 | [4] = PERF_ATTR_SIZE_VER4, | ||
| 2146 | 0, | 2147 | 0, |
| 2147 | }; | 2148 | }; |
| 2148 | 2149 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f4478ce72fdb..6ac62ae6b8fa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -592,15 +592,46 @@ static void regs_dump__printf(u64 mask, u64 *regs) | |||
| 592 | } | 592 | } |
| 593 | } | 593 | } |
| 594 | 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 | |||
| 595 | static void regs_user__printf(struct perf_sample *sample) | 621 | static void regs_user__printf(struct perf_sample *sample) |
| 596 | { | 622 | { |
| 597 | struct regs_dump *user_regs = &sample->user_regs; | 623 | struct regs_dump *user_regs = &sample->user_regs; |
| 598 | 624 | ||
| 599 | if (user_regs->regs) { | 625 | if (user_regs->regs) |
| 600 | u64 mask = user_regs->mask; | 626 | regs__printf("user", user_regs); |
| 601 | printf("... user regs: mask 0x%" PRIx64 "\n", mask); | 627 | } |
| 602 | regs_dump__printf(mask, user_regs->regs); | 628 | |
| 603 | } | 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); | ||
| 604 | } | 635 | } |
| 605 | 636 | ||
| 606 | static void stack_user__printf(struct stack_dump *dump) | 637 | static void stack_user__printf(struct stack_dump *dump) |
| @@ -699,6 +730,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 699 | if (sample_type & PERF_SAMPLE_REGS_USER) | 730 | if (sample_type & PERF_SAMPLE_REGS_USER) |
| 700 | regs_user__printf(sample); | 731 | regs_user__printf(sample); |
| 701 | 732 | ||
| 733 | if (sample_type & PERF_SAMPLE_REGS_INTR) | ||
| 734 | regs_intr__printf(sample); | ||
| 735 | |||
| 702 | if (sample_type & PERF_SAMPLE_STACK_USER) | 736 | if (sample_type & PERF_SAMPLE_STACK_USER) |
| 703 | stack_user__printf(&sample->user_stack); | 737 | stack_user__printf(&sample->user_stack); |
| 704 | 738 | ||
