Commit a978f2ab authored by Akihiro Nagai's avatar Akihiro Nagai Committed by Arnaldo Carvalho de Melo

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@linux3Signed-off-by: default avatarAkihiro Nagai <akihiro.nagai.hw@hitachi.com>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 95582596
...@@ -115,7 +115,7 @@ OPTIONS ...@@ -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
......
...@@ -40,6 +40,7 @@ enum perf_output_field { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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[] = { ...@@ -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"),
......
...@@ -1293,7 +1293,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, ...@@ -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, ...@@ -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) {
......
...@@ -147,7 +147,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, ...@@ -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);
......
...@@ -263,16 +263,26 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp) ...@@ -263,16 +263,26 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
sym->name); sym->name);
} }
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) size_t symbol__fprintf_symname_offs(const struct symbol *sym,
const struct addr_location *al, FILE *fp)
{ {
const char *symname; unsigned long offset;
size_t length;
if (sym && sym->name) if (sym && sym->name) {
symname = sym->name; length = fprintf(fp, "%s", sym->name);
else if (al) {
symname = "[unknown]"; offset = al->addr - sym->start;
length += fprintf(fp, "+0x%lx", offset);
}
return length;
} else
return fprintf(fp, "[unknown]");
}
return fprintf(fp, "%s", symname); size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
{
return symbol__fprintf_symname_offs(sym, NULL, fp);
} }
void dso__set_long_name(struct dso *dso, char *name) void dso__set_long_name(struct dso *dso, char *name)
......
...@@ -241,6 +241,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines); ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment