perf script: Add support for dumping symbols
Add option to dump symbols found in events. e.g., perf script -f comm,pid,tid,time,trace,sym swapper 0/0 537.037184: prev_comm=swapper prev_pid=0 prev_prio=120... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff8100134a cpu_idle ([kernel.kallsyms]) ffffffff81370b39 rest_init ([kernel.kallsyms]) ffffffff81696c23 start_kernel ([kernel.kallsyms].init.text) ffffffff816962af x86_64_start_reservations ([kernel.kallsyms].init.text) ffffffff816963b9 x86_64_start_kernel ([kernel.kallsyms].init.text) sshd 1675/1675 537.037309: prev_comm=sshd prev_pid=1675 prev_prio=120... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff813837aa schedule_hrtimeout_range_clock ([kernel.kallsyms]) ffffffff81383886 schedule_hrtimeout_range ([kernel.kallsyms]) ffffffff8110c4f9 poll_schedule_timeout ([kernel.kallsyms]) ffffffff8110cd20 do_select ([kernel.kallsyms]) ffffffff8110ced8 core_sys_select ([kernel.kallsyms]) ffffffff8110d00d sys_select ([kernel.kallsyms]) ffffffff81002bc2 system_call ([kernel.kallsyms]) 7f1647e56e93 __GI_select (/lib64/libc-2.12.90.so) netstat 1692/1692 537.038664: prev_comm=netstat prev_pid=1692 prev_prio=... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff81002c3a sysret_careful ([kernel.kallsyms]) 7f7a6cd1b210 __GI___libc_read (/lib64/libc-2.12.90.so) Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> LKML-Reference: <1299734608-5223-6-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern <daahern@cisco.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
745f43e343
commit
c0230b2bfb
|
@ -115,7 +115,21 @@ 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
|
comm, tid, pid, time, cpu, event, trace, sym
|
||||||
|
|
||||||
|
-k::
|
||||||
|
--vmlinux=<file>::
|
||||||
|
vmlinux pathname
|
||||||
|
|
||||||
|
--kallsyms=<file>::
|
||||||
|
kallsyms pathname
|
||||||
|
|
||||||
|
--symfs=<directory>::
|
||||||
|
Look for files with symbols relative to this directory.
|
||||||
|
|
||||||
|
-G::
|
||||||
|
--hide-call-graph::
|
||||||
|
When printing symbols do not display call chain.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -19,6 +19,7 @@ static bool debug_mode;
|
||||||
static u64 last_timestamp;
|
static u64 last_timestamp;
|
||||||
static u64 nr_unordered;
|
static u64 nr_unordered;
|
||||||
extern const struct option record_options[];
|
extern const struct option record_options[];
|
||||||
|
static bool no_callchain;
|
||||||
|
|
||||||
enum perf_output_field {
|
enum perf_output_field {
|
||||||
PERF_OUTPUT_COMM = 1U << 0,
|
PERF_OUTPUT_COMM = 1U << 0,
|
||||||
|
@ -28,6 +29,7 @@ enum perf_output_field {
|
||||||
PERF_OUTPUT_CPU = 1U << 4,
|
PERF_OUTPUT_CPU = 1U << 4,
|
||||||
PERF_OUTPUT_EVNAME = 1U << 5,
|
PERF_OUTPUT_EVNAME = 1U << 5,
|
||||||
PERF_OUTPUT_TRACE = 1U << 6,
|
PERF_OUTPUT_TRACE = 1U << 6,
|
||||||
|
PERF_OUTPUT_SYM = 1U << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_option {
|
struct output_option {
|
||||||
|
@ -41,6 +43,7 @@ struct output_option {
|
||||||
{.str = "cpu", .field = PERF_OUTPUT_CPU},
|
{.str = "cpu", .field = PERF_OUTPUT_CPU},
|
||||||
{.str = "event", .field = PERF_OUTPUT_EVNAME},
|
{.str = "event", .field = PERF_OUTPUT_EVNAME},
|
||||||
{.str = "trace", .field = PERF_OUTPUT_TRACE},
|
{.str = "trace", .field = PERF_OUTPUT_TRACE},
|
||||||
|
{.str = "sym", .field = PERF_OUTPUT_SYM},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* default set to maintain compatibility with current format */
|
/* default set to maintain compatibility with current format */
|
||||||
|
@ -65,6 +68,8 @@ static void print_sample_start(struct perf_sample *sample,
|
||||||
if (PRINT_FIELD(COMM)) {
|
if (PRINT_FIELD(COMM)) {
|
||||||
if (latency_format)
|
if (latency_format)
|
||||||
printf("%8.8s ", thread->comm);
|
printf("%8.8s ", thread->comm);
|
||||||
|
else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
|
||||||
|
printf("%s ", thread->comm);
|
||||||
else
|
else
|
||||||
printf("%16s ", thread->comm);
|
printf("%16s ", thread->comm);
|
||||||
}
|
}
|
||||||
|
@ -112,6 +117,14 @@ static void process_event(union perf_event *event __unused,
|
||||||
print_trace_event(sample->cpu, sample->raw_data,
|
print_trace_event(sample->cpu, sample->raw_data,
|
||||||
sample->raw_size);
|
sample->raw_size);
|
||||||
|
|
||||||
|
if (PRINT_FIELD(SYM)) {
|
||||||
|
if (!symbol_conf.use_callchain)
|
||||||
|
printf(" ");
|
||||||
|
else
|
||||||
|
printf("\n");
|
||||||
|
perf_session__print_symbols(event, sample, session);
|
||||||
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +203,10 @@ static int process_sample_event(union perf_event *event,
|
||||||
|
|
||||||
static struct perf_event_ops event_ops = {
|
static struct perf_event_ops event_ops = {
|
||||||
.sample = process_sample_event,
|
.sample = process_sample_event,
|
||||||
|
.mmap = perf_event__process_mmap,
|
||||||
.comm = perf_event__process_comm,
|
.comm = perf_event__process_comm,
|
||||||
|
.exit = perf_event__process_task,
|
||||||
|
.fork = perf_event__process_task,
|
||||||
.attr = perf_event__process_attr,
|
.attr = perf_event__process_attr,
|
||||||
.event_type = perf_event__process_event_type,
|
.event_type = perf_event__process_event_type,
|
||||||
.tracing_data = perf_event__process_tracing_data,
|
.tracing_data = perf_event__process_tracing_data,
|
||||||
|
@ -722,8 +738,16 @@ static const struct option options[] = {
|
||||||
"input file name"),
|
"input file name"),
|
||||||
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
|
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
|
||||||
"do various checks like samples ordering and lost events"),
|
"do various checks like samples ordering and lost events"),
|
||||||
|
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||||
|
"file", "vmlinux pathname"),
|
||||||
|
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
|
||||||
|
"file", "kallsyms pathname"),
|
||||||
|
OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
|
||||||
|
"When printing symbols do not display call chain"),
|
||||||
|
OPT_STRING(0, "symfs", &symbol_conf.symfs, "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. Options: comm,tid,pid,time,cpu,event,trace",
|
"comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym",
|
||||||
parse_output_fields),
|
parse_output_fields),
|
||||||
|
|
||||||
OPT_END()
|
OPT_END()
|
||||||
|
@ -905,6 +929,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN))
|
||||||
|
symbol_conf.use_callchain = true;
|
||||||
|
else
|
||||||
|
symbol_conf.use_callchain = false;
|
||||||
|
|
||||||
if (strcmp(input_name, "-") &&
|
if (strcmp(input_name, "-") &&
|
||||||
!perf_session__has_traces(session, "record -R"))
|
!perf_session__has_traces(session, "record -R"))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void perf_session__print_symbols(union perf_event *event,
|
||||||
|
struct perf_sample *sample,
|
||||||
|
struct perf_session *session)
|
||||||
|
{
|
||||||
|
struct addr_location al;
|
||||||
|
const char *symname, *dsoname;
|
||||||
|
struct callchain_cursor *cursor = &session->callchain_cursor;
|
||||||
|
struct callchain_cursor_node *node;
|
||||||
|
|
||||||
|
if (perf_event__preprocess_sample(event, session, &al, sample,
|
||||||
|
NULL) < 0) {
|
||||||
|
error("problem processing %d event, skipping it.\n",
|
||||||
|
event->header.type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol_conf.use_callchain && sample->callchain) {
|
||||||
|
|
||||||
|
if (perf_session__resolve_callchain(session, al.thread,
|
||||||
|
sample->callchain, NULL) != 0) {
|
||||||
|
if (verbose)
|
||||||
|
error("Failed to resolve callchain. Skipping\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callchain_cursor_commit(cursor);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
node = callchain_cursor_current(cursor);
|
||||||
|
if (!node)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (node->sym && node->sym->name)
|
||||||
|
symname = node->sym->name;
|
||||||
|
else
|
||||||
|
symname = "";
|
||||||
|
|
||||||
|
if (node->map && node->map->dso && node->map->dso->name)
|
||||||
|
dsoname = node->map->dso->name;
|
||||||
|
else
|
||||||
|
dsoname = "";
|
||||||
|
|
||||||
|
printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
|
||||||
|
|
||||||
|
callchain_cursor_advance(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (al.sym && al.sym->name)
|
||||||
|
symname = al.sym->name;
|
||||||
|
else
|
||||||
|
symname = "";
|
||||||
|
|
||||||
|
if (al.map && al.map->dso && al.map->dso->name)
|
||||||
|
dsoname = al.map->dso->name;
|
||||||
|
else
|
||||||
|
dsoname = "";
|
||||||
|
|
||||||
|
printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
|
||||||
session->sample_id_all, sample);
|
session->sample_id_all, sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void perf_session__print_symbols(union perf_event *event,
|
||||||
|
struct perf_sample *sample,
|
||||||
|
struct perf_session *session);
|
||||||
|
|
||||||
#endif /* __PERF_SESSION_H */
|
#endif /* __PERF_SESSION_H */
|
||||||
|
|
Loading…
Reference in a new issue