perf script: Add the offset field specifier

Add the offset field specifier 'symoff' to show the offset from
the symbols in the output of perf-script. We can get the more
detailed address information.

Output sample:
ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0
ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0
      301ec016b3 _start+0x3     => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b96 _dl_start+0x26
ffffffff81467612 irq_return+0x0 => 301ec04b9d _dl_start+0x2d
      301ec04beb _dl_start+0x7b => 301ec04c0d _dl_start+0x9d
      301ec04c11 _dl_start+0xa1 => 301ec04bf0 _dl_start+0x80
[snip]

Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20120130044314.2384.67094.stgit@linux3
Signed-off-by: Akihiro Nagai <akihiro.nagai.hw@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Akihiro Nagai 2012-01-30 13:43:15 +09:00 committed by Arnaldo Carvalho de Melo
parent 9558259697
commit a978f2ab41
6 changed files with 47 additions and 16 deletions

View file

@ -115,7 +115,7 @@ OPTIONS
-f:: -f::
--fields:: --fields::
Comma separated list of fields to print. Options are: Comma separated list of fields to print. Options are:
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr. comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff.
Field list can be prepended with the type, trace, sw or hw, Field list can be prepended with the type, trace, sw or hw,
to indicate to which event type the field list applies. to indicate to which event type the field list applies.
e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace

View file

@ -40,6 +40,7 @@ enum perf_output_field {
PERF_OUTPUT_SYM = 1U << 8, PERF_OUTPUT_SYM = 1U << 8,
PERF_OUTPUT_DSO = 1U << 9, PERF_OUTPUT_DSO = 1U << 9,
PERF_OUTPUT_ADDR = 1U << 10, PERF_OUTPUT_ADDR = 1U << 10,
PERF_OUTPUT_SYMOFFSET = 1U << 11,
}; };
struct output_option { struct output_option {
@ -57,6 +58,7 @@ struct output_option {
{.str = "sym", .field = PERF_OUTPUT_SYM}, {.str = "sym", .field = PERF_OUTPUT_SYM},
{.str = "dso", .field = PERF_OUTPUT_DSO}, {.str = "dso", .field = PERF_OUTPUT_DSO},
{.str = "addr", .field = PERF_OUTPUT_ADDR}, {.str = "addr", .field = PERF_OUTPUT_ADDR},
{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
}; };
/* default set to maintain compatibility with current format */ /* default set to maintain compatibility with current format */
@ -193,6 +195,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
"to symbols.\n"); "to symbols.\n");
return -EINVAL; return -EINVAL;
} }
if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {
pr_err("Display of offsets requested but symbol is not"
"selected.\n");
return -EINVAL;
}
if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
pr_err("Display of DSO requested but neither sample IP nor " pr_err("Display of DSO requested but neither sample IP nor "
"sample address\nis selected. Hence, no addresses to convert " "sample address\nis selected. Hence, no addresses to convert "
@ -353,7 +360,10 @@ static void print_sample_addr(union perf_event *event,
if (PRINT_FIELD(SYM)) { if (PRINT_FIELD(SYM)) {
printf(" "); printf(" ");
symbol__fprintf_symname(al.sym, stdout); if (PRINT_FIELD(SYMOFFSET))
symbol__fprintf_symname_offs(al.sym, &al, stdout);
else
symbol__fprintf_symname(al.sym, stdout);
} }
if (PRINT_FIELD(DSO)) { if (PRINT_FIELD(DSO)) {
@ -378,7 +388,8 @@ static void print_sample_bts(union perf_event *event,
else else
printf("\n"); printf("\n");
perf_event__print_ip(event, sample, machine, evsel, perf_event__print_ip(event, sample, machine, evsel,
PRINT_FIELD(SYM), PRINT_FIELD(DSO)); PRINT_FIELD(SYM), PRINT_FIELD(DSO),
PRINT_FIELD(SYMOFFSET));
} }
printf(" => "); printf(" => ");
@ -421,7 +432,8 @@ static void process_event(union perf_event *event __unused,
else else
printf("\n"); printf("\n");
perf_event__print_ip(event, sample, machine, evsel, perf_event__print_ip(event, sample, machine, evsel,
PRINT_FIELD(SYM), PRINT_FIELD(DSO)); PRINT_FIELD(SYM), PRINT_FIELD(DSO),
PRINT_FIELD(SYMOFFSET));
} }
printf("\n"); printf("\n");
@ -1131,7 +1143,10 @@ static const struct option options[] = {
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory"),
OPT_CALLBACK('f', "fields", NULL, "str", OPT_CALLBACK('f', "fields", NULL, "str",
"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", "comma separated output fields prepend with 'type:'. "
"Valid types: hw,sw,trace,raw. "
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
"addr,symoff",
parse_output_fields), parse_output_fields),
OPT_BOOLEAN('a', "all-cpus", &system_wide, OPT_BOOLEAN('a', "all-cpus", &system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),

View file

@ -1293,7 +1293,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
struct machine *machine, struct perf_evsel *evsel, struct machine *machine, struct perf_evsel *evsel,
int print_sym, int print_dso) int print_sym, int print_dso, int print_symoffset)
{ {
struct addr_location al; struct addr_location al;
struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
@ -1340,7 +1340,11 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
printf("%16" PRIx64, sample->ip); printf("%16" PRIx64, sample->ip);
if (print_sym) { if (print_sym) {
printf(" "); printf(" ");
symbol__fprintf_symname(al.sym, stdout); if (print_symoffset)
symbol__fprintf_symname_offs(al.sym, &al,
stdout);
else
symbol__fprintf_symname(al.sym, stdout);
} }
if (print_dso) { if (print_dso) {

View file

@ -147,7 +147,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
struct machine *machine, struct perf_evsel *evsel, struct machine *machine, struct perf_evsel *evsel,
int print_sym, int print_dso); int print_sym, int print_dso, int print_symoffset);
int perf_session__cpu_bitmap(struct perf_session *session, int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap); const char *cpu_list, unsigned long *cpu_bitmap);

View file

@ -263,16 +263,26 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
sym->name); sym->name);
} }
size_t symbol__fprintf_symname_offs(const struct symbol *sym,
const struct addr_location *al, FILE *fp)
{
unsigned long offset;
size_t length;
if (sym && sym->name) {
length = fprintf(fp, "%s", sym->name);
if (al) {
offset = al->addr - sym->start;
length += fprintf(fp, "+0x%lx", offset);
}
return length;
} else
return fprintf(fp, "[unknown]");
}
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
{ {
const char *symname; return symbol__fprintf_symname_offs(sym, NULL, fp);
if (sym && sym->name)
symname = sym->name;
else
symname = "[unknown]";
return fprintf(fp, "%s", symname);
} }
void dso__set_long_name(struct dso *dso, char *name) void dso__set_long_name(struct dso *dso, char *name)

View file

@ -241,6 +241,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
int symbol__init(void); int symbol__init(void);
void symbol__exit(void); void symbol__exit(void);
size_t symbol__fprintf_symname_offs(const struct symbol *sym,
const struct addr_location *al, FILE *fp);
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
bool symbol_type__is_a(char symbol_type, enum map_type map_type); bool symbol_type__is_a(char symbol_type, enum map_type map_type);