diff options
author | Stephane Eranian <eranian@google.com> | 2014-09-24 07:48:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-11-16 05:41:59 -0500 |
commit | 6a21c0b5c2abd2fdfa6fff79f11df3d6082c1873 (patch) | |
tree | ff097bc4f3a2a3d6b400b82853852cb49dc2036a /tools | |
parent | aea48559ac454a065244d3eff0c94cc8af9c553e (diff) |
perf tools: Add core support for sampling intr machine state regs
Add the infrastructure to setup, collect and report the interrupt
machine state regs which can be captured by the kernel.
Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: cebbert.lkml@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Jean Pihet <jean.pihet@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Waiman Long <Waiman.Long@hp.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1411559322-16548-4-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-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 | ||