Skip to content

Commit dd2e18e

Browse files
Andi Kleenacmel
authored andcommitted
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 <[email protected]> Tested-by: Jiri Olsa <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 42da438 commit dd2e18e

File tree

12 files changed

+339
-3
lines changed

12 files changed

+339
-3
lines changed

tools/perf/Documentation/perf-script.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ OPTIONS
117117
Comma separated list of fields to print. Options are:
118118
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
119119
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
120-
brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc.
120+
brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode.
121121
Field list can be prepended with the type, trace, sw or hw,
122122
to indicate to which event type the field list applies.
123123
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace

tools/perf/builtin-script.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ enum perf_output_field {
9696
PERF_OUTPUT_UREGS = 1U << 27,
9797
PERF_OUTPUT_METRIC = 1U << 28,
9898
PERF_OUTPUT_MISC = 1U << 29,
99+
PERF_OUTPUT_SRCCODE = 1U << 30,
99100
};
100101

101102
struct output_option {
@@ -132,6 +133,7 @@ struct output_option {
132133
{.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR},
133134
{.str = "metric", .field = PERF_OUTPUT_METRIC},
134135
{.str = "misc", .field = PERF_OUTPUT_MISC},
136+
{.str = "srccode", .field = PERF_OUTPUT_SRCCODE},
135137
};
136138

137139
enum {
@@ -424,7 +426,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
424426
pr_err("Display of DSO requested but no address to convert.\n");
425427
return -EINVAL;
426428
}
427-
if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
429+
if ((PRINT_FIELD(SRCLINE) || PRINT_FIELD(SRCCODE)) && !PRINT_FIELD(IP)) {
428430
pr_err("Display of source line number requested but sample IP is not\n"
429431
"selected. Hence, no address to lookup the source line number.\n");
430432
return -EINVAL;
@@ -907,6 +909,22 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
907909
return len;
908910
}
909911

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+
910928
static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
911929
struct perf_insn *x, u8 *inbuf, int len,
912930
int insn, FILE *fp, int *total_cycles)
@@ -998,6 +1016,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
9981016
x.cpumode, x.cpu, &lastsym, attr, fp);
9991017
printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
10001018
&x, buffer, len, 0, fp, &total_cycles);
1019+
if (PRINT_FIELD(SRCCODE))
1020+
printed += print_srccode(thread, x.cpumode, br->entries[nr - 1].from);
10011021
}
10021022

10031023
/* Print all blocks */
@@ -1027,12 +1047,16 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
10271047
if (ip == end) {
10281048
printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp,
10291049
&total_cycles);
1050+
if (PRINT_FIELD(SRCCODE))
1051+
printed += print_srccode(thread, x.cpumode, ip);
10301052
break;
10311053
} else {
10321054
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip,
10331055
dump_insn(&x, ip, buffer + off, len - off, &ilen));
10341056
if (ilen == 0)
10351057
break;
1058+
if (PRINT_FIELD(SRCCODE))
1059+
print_srccode(thread, x.cpumode, ip);
10361060
insn++;
10371061
}
10381062
}
@@ -1063,13 +1087,17 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
10631087

10641088
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
10651089
dump_insn(&x, sample->ip, buffer, len, NULL));
1090+
if (PRINT_FIELD(SRCCODE))
1091+
print_srccode(thread, x.cpumode, sample->ip);
10661092
goto out;
10671093
}
10681094
for (off = 0; off <= end - start; off += ilen) {
10691095
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off,
10701096
dump_insn(&x, start + off, buffer + off, len - off, &ilen));
10711097
if (ilen == 0)
10721098
break;
1099+
if (PRINT_FIELD(SRCCODE))
1100+
print_srccode(thread, x.cpumode, start + off);
10731101
}
10741102
out:
10751103
return printed;
@@ -1252,7 +1280,16 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample,
12521280
printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
12531281

12541282
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;
12561293
}
12571294

12581295
static struct {
@@ -1792,6 +1829,12 @@ static void process_event(struct perf_script *script,
17921829
fprintf(fp, "%16" PRIx64, sample->phys_addr);
17931830
fprintf(fp, "\n");
17941831

1832+
if (PRINT_FIELD(SRCCODE)) {
1833+
if (map__fprintf_srccode(al->map, al->addr, stdout,
1834+
&thread->srccode_state))
1835+
printf("\n");
1836+
}
1837+
17951838
if (PRINT_FIELD(METRIC))
17961839
perf_sample__fprint_metric(script, thread, evsel, sample, fp);
17971840

tools/perf/util/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ libperf-y += stat-shadow.o
7777
libperf-y += stat-display.o
7878
libperf-y += record.o
7979
libperf-y += srcline.o
80+
libperf-y += srccode.o
8081
libperf-y += data.o
8182
libperf-y += tsc.o
8283
libperf-y += cloexec.o

tools/perf/util/evsel_fprintf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
173173
if (!print_oneline)
174174
printed += fprintf(fp, "\n");
175175

176+
/* Add srccode here too? */
176177
if (symbol_conf.bt_stop_list &&
177178
node->sym &&
178179
strlist__has_entry(symbol_conf.bt_stop_list,

tools/perf/util/map.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "srcline.h"
2020
#include "namespaces.h"
2121
#include "unwind.h"
22+
#include "srccode.h"
2223

2324
static void __maps__insert(struct maps *maps, struct map *map);
2425
static void __maps__insert_name(struct maps *maps, struct map *map);
@@ -421,6 +422,54 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
421422
return ret;
422423
}
423424

425+
int map__fprintf_srccode(struct map *map, u64 addr,
426+
FILE *fp,
427+
struct srccode_state *state)
428+
{
429+
char *srcfile;
430+
int ret = 0;
431+
unsigned line;
432+
int len;
433+
char *srccode;
434+
435+
if (!map || !map->dso)
436+
return 0;
437+
srcfile = get_srcline_split(map->dso,
438+
map__rip_2objdump(map, addr),
439+
&line);
440+
if (!srcfile)
441+
return 0;
442+
443+
/* Avoid redundant printing */
444+
if (state &&
445+
state->srcfile &&
446+
!strcmp(state->srcfile, srcfile) &&
447+
state->line == line) {
448+
free(srcfile);
449+
return 0;
450+
}
451+
452+
srccode = find_sourceline(srcfile, line, &len);
453+
if (!srccode)
454+
goto out_free_line;
455+
456+
ret = fprintf(fp, "|%-8d %.*s", line, len, srccode);
457+
state->srcfile = srcfile;
458+
state->line = line;
459+
return ret;
460+
461+
out_free_line:
462+
free(srcfile);
463+
return ret;
464+
}
465+
466+
467+
void srccode_state_free(struct srccode_state *state)
468+
{
469+
zfree(&state->srcfile);
470+
state->line = 0;
471+
}
472+
424473
/**
425474
* map__rip_2objdump - convert symbol start address to objdump address.
426475
* @map: memory map

tools/perf/util/map.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,22 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
174174
int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
175175
FILE *fp);
176176

177+
struct srccode_state {
178+
char *srcfile;
179+
unsigned line;
180+
};
181+
182+
static inline void srccode_state_init(struct srccode_state *state)
183+
{
184+
state->srcfile = NULL;
185+
state->line = 0;
186+
}
187+
188+
void srccode_state_free(struct srccode_state *state);
189+
190+
int map__fprintf_srccode(struct map *map, u64 addr,
191+
FILE *fp, struct srccode_state *state);
192+
177193
int map__load(struct map *map);
178194
struct symbol *map__find_symbol(struct map *map, u64 addr);
179195
struct symbol *map__find_symbol_by_name(struct map *map, const char *name);

0 commit comments

Comments
 (0)