diff options
author | Andi Kleen <ak@linux.intel.com> | 2018-12-03 19:18:48 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-12-17 12:57:07 -0500 |
commit | dd2e18e9ac20e3ffc27cabf318e83b43ed5ddb92 (patch) | |
tree | dc66716b24bad19fbb27f572e31541a9169c4000 /tools/perf/builtin-script.c | |
parent | 42da438c1bc4ad9b904401aff03678ddbf1329b0 (diff) |
perf tools: Support 'srccode' output
When looking at PT or brstackinsn traces with 'perf script' it can be
very useful to see the source code. This adds a simple facility to print
them with 'perf script', if the information is available through dwarf
% perf record ...
% perf script -F insn,ip,sym,srccode
...
4004c6 main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004c6 main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004cd main
5 for (i = 0; i < 10000000; i++)
4004b3 main
6 v++;
% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn
...
main+22:
0000000000400543 insn: e8 ca ff ff ff # PRED
|18 f1();
f1:
0000000000400512 insn: 55
|10 {
0000000000400513 insn: 48 89 e5
0000000000400516 insn: b8 00 00 00 00
|11 f2();
000000000040051b insn: e8 d6 ff ff ff # PRED
f2:
00000000004004f6 insn: 55
|5 {
00000000004004f7 insn: 48 89 e5
00000000004004fa insn: 8b 05 2c 0b 20 00
|6 c = a / b;
0000000000400500 insn: 8b 0d 2a 0b 20 00
0000000000400506 insn: 99
0000000000400507 insn: f7 f9
0000000000400509 insn: 89 05 29 0b 20 00
000000000040050f insn: 90
|7 }
0000000000400510 insn: 5d
0000000000400511 insn: c3 # PRED
f1+14:
0000000000400520 insn: b8 00 00 00 00
|12 f2();
0000000000400525 insn: e8 cc ff ff ff # PRED
f2:
00000000004004f6 insn: 55
|5 {
00000000004004f7 insn: 48 89 e5
00000000004004fa insn: 8b 05 2c 0b 20 00
|6 c = a / b;
Not supported for callchains currently, would need some layout changes
there.
Committer notes:
Fixed the build on Alpine Linux (3.4 .. 3.8) by addressing this
warning:
In file included from util/srccode.c:19:0:
/usr/include/sys/fcntl.h:1:2: error: #warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h> [-Werror=cpp]
#warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h>
^~~~~~~
cc1: all warnings being treated as errors
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20181204001848.24769-1-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3ea98fe72f7f..3728b50e52e2 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -96,6 +96,7 @@ enum perf_output_field { | |||
96 | PERF_OUTPUT_UREGS = 1U << 27, | 96 | PERF_OUTPUT_UREGS = 1U << 27, |
97 | PERF_OUTPUT_METRIC = 1U << 28, | 97 | PERF_OUTPUT_METRIC = 1U << 28, |
98 | PERF_OUTPUT_MISC = 1U << 29, | 98 | PERF_OUTPUT_MISC = 1U << 29, |
99 | PERF_OUTPUT_SRCCODE = 1U << 30, | ||
99 | }; | 100 | }; |
100 | 101 | ||
101 | struct output_option { | 102 | struct output_option { |
@@ -132,6 +133,7 @@ struct output_option { | |||
132 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, | 133 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, |
133 | {.str = "metric", .field = PERF_OUTPUT_METRIC}, | 134 | {.str = "metric", .field = PERF_OUTPUT_METRIC}, |
134 | {.str = "misc", .field = PERF_OUTPUT_MISC}, | 135 | {.str = "misc", .field = PERF_OUTPUT_MISC}, |
136 | {.str = "srccode", .field = PERF_OUTPUT_SRCCODE}, | ||
135 | }; | 137 | }; |
136 | 138 | ||
137 | enum { | 139 | enum { |
@@ -424,7 +426,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
424 | pr_err("Display of DSO requested but no address to convert.\n"); | 426 | pr_err("Display of DSO requested but no address to convert.\n"); |
425 | return -EINVAL; | 427 | return -EINVAL; |
426 | } | 428 | } |
427 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { | 429 | if ((PRINT_FIELD(SRCLINE) || PRINT_FIELD(SRCCODE)) && !PRINT_FIELD(IP)) { |
428 | pr_err("Display of source line number requested but sample IP is not\n" | 430 | pr_err("Display of source line number requested but sample IP is not\n" |
429 | "selected. Hence, no address to lookup the source line number.\n"); | 431 | "selected. Hence, no address to lookup the source line number.\n"); |
430 | return -EINVAL; | 432 | return -EINVAL; |
@@ -907,6 +909,22 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
907 | return len; | 909 | return len; |
908 | } | 910 | } |
909 | 911 | ||
912 | static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr) | ||
913 | { | ||
914 | struct addr_location al; | ||
915 | int ret = 0; | ||
916 | |||
917 | memset(&al, 0, sizeof(al)); | ||
918 | thread__find_map(thread, cpumode, addr, &al); | ||
919 | if (!al.map) | ||
920 | return 0; | ||
921 | ret = map__fprintf_srccode(al.map, al.addr, stdout, | ||
922 | &thread->srccode_state); | ||
923 | if (ret) | ||
924 | ret += printf("\n"); | ||
925 | return ret; | ||
926 | } | ||
927 | |||
910 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, | 928 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, |
911 | struct perf_insn *x, u8 *inbuf, int len, | 929 | struct perf_insn *x, u8 *inbuf, int len, |
912 | int insn, FILE *fp, int *total_cycles) | 930 | int insn, FILE *fp, int *total_cycles) |
@@ -998,6 +1016,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
998 | x.cpumode, x.cpu, &lastsym, attr, fp); | 1016 | x.cpumode, x.cpu, &lastsym, attr, fp); |
999 | printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], | 1017 | printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], |
1000 | &x, buffer, len, 0, fp, &total_cycles); | 1018 | &x, buffer, len, 0, fp, &total_cycles); |
1019 | if (PRINT_FIELD(SRCCODE)) | ||
1020 | printed += print_srccode(thread, x.cpumode, br->entries[nr - 1].from); | ||
1001 | } | 1021 | } |
1002 | 1022 | ||
1003 | /* Print all blocks */ | 1023 | /* Print all blocks */ |
@@ -1027,12 +1047,16 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
1027 | if (ip == end) { | 1047 | if (ip == end) { |
1028 | printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, | 1048 | printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, |
1029 | &total_cycles); | 1049 | &total_cycles); |
1050 | if (PRINT_FIELD(SRCCODE)) | ||
1051 | printed += print_srccode(thread, x.cpumode, ip); | ||
1030 | break; | 1052 | break; |
1031 | } else { | 1053 | } else { |
1032 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, | 1054 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, |
1033 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); | 1055 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); |
1034 | if (ilen == 0) | 1056 | if (ilen == 0) |
1035 | break; | 1057 | break; |
1058 | if (PRINT_FIELD(SRCCODE)) | ||
1059 | print_srccode(thread, x.cpumode, ip); | ||
1036 | insn++; | 1060 | insn++; |
1037 | } | 1061 | } |
1038 | } | 1062 | } |
@@ -1063,6 +1087,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
1063 | 1087 | ||
1064 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip, | 1088 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip, |
1065 | dump_insn(&x, sample->ip, buffer, len, NULL)); | 1089 | dump_insn(&x, sample->ip, buffer, len, NULL)); |
1090 | if (PRINT_FIELD(SRCCODE)) | ||
1091 | print_srccode(thread, x.cpumode, sample->ip); | ||
1066 | goto out; | 1092 | goto out; |
1067 | } | 1093 | } |
1068 | for (off = 0; off <= end - start; off += ilen) { | 1094 | for (off = 0; off <= end - start; off += ilen) { |
@@ -1070,6 +1096,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
1070 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); | 1096 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); |
1071 | if (ilen == 0) | 1097 | if (ilen == 0) |
1072 | break; | 1098 | break; |
1099 | if (PRINT_FIELD(SRCCODE)) | ||
1100 | print_srccode(thread, x.cpumode, start + off); | ||
1073 | } | 1101 | } |
1074 | out: | 1102 | out: |
1075 | return printed; | 1103 | return printed; |
@@ -1252,7 +1280,16 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, | |||
1252 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | 1280 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); |
1253 | 1281 | ||
1254 | printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); | 1282 | printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
1255 | return printed + fprintf(fp, "\n"); | 1283 | printed += fprintf(fp, "\n"); |
1284 | if (PRINT_FIELD(SRCCODE)) { | ||
1285 | int ret = map__fprintf_srccode(al->map, al->addr, stdout, | ||
1286 | &thread->srccode_state); | ||
1287 | if (ret) { | ||
1288 | printed += ret; | ||
1289 | printed += printf("\n"); | ||
1290 | } | ||
1291 | } | ||
1292 | return printed; | ||
1256 | } | 1293 | } |
1257 | 1294 | ||
1258 | static struct { | 1295 | static struct { |
@@ -1792,6 +1829,12 @@ static void process_event(struct perf_script *script, | |||
1792 | fprintf(fp, "%16" PRIx64, sample->phys_addr); | 1829 | fprintf(fp, "%16" PRIx64, sample->phys_addr); |
1793 | fprintf(fp, "\n"); | 1830 | fprintf(fp, "\n"); |
1794 | 1831 | ||
1832 | if (PRINT_FIELD(SRCCODE)) { | ||
1833 | if (map__fprintf_srccode(al->map, al->addr, stdout, | ||
1834 | &thread->srccode_state)) | ||
1835 | printf("\n"); | ||
1836 | } | ||
1837 | |||
1795 | if (PRINT_FIELD(METRIC)) | 1838 | if (PRINT_FIELD(METRIC)) |
1796 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); | 1839 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); |
1797 | 1840 | ||