Commit 7cec0922 authored by David Ahern's avatar David Ahern Committed by Arnaldo Carvalho de Melo

perf script: Add printing of sample address

Resolve to a function or variable if possible and if the sym option is
enabled.

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>
Link: http://lkml.kernel.org/r/1306782503-22002-1-git-send-email-dsahern@gmail.comSigned-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 610723f2
...@@ -115,8 +115,8 @@ OPTIONS ...@@ -115,8 +115,8 @@ 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. Field comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
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
......
...@@ -33,6 +33,7 @@ enum perf_output_field { ...@@ -33,6 +33,7 @@ enum perf_output_field {
PERF_OUTPUT_IP = 1U << 7, PERF_OUTPUT_IP = 1U << 7,
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,
}; };
struct output_option { struct output_option {
...@@ -49,6 +50,7 @@ struct output_option { ...@@ -49,6 +50,7 @@ struct output_option {
{.str = "ip", .field = PERF_OUTPUT_IP}, {.str = "ip", .field = PERF_OUTPUT_IP},
{.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},
}; };
/* default set to maintain compatibility with current format */ /* default set to maintain compatibility with current format */
...@@ -173,14 +175,22 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, ...@@ -173,14 +175,22 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
!(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
symbol_conf.use_callchain = false; symbol_conf.use_callchain = false;
} }
if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP)) {
pr_err("Display of symbols requested but IP is not selected.\n" if (PRINT_FIELD(ADDR) &&
"No addresses to convert to symbols.\n"); perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
PERF_OUTPUT_ADDR))
return -EINVAL;
if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
pr_err("Display of symbols requested but neither sample IP nor "
"sample address\nis selected. Hence, no addresses to convert "
"to symbols.\n");
return -EINVAL; return -EINVAL;
} }
if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP)) { if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
pr_err("Display of DSO requested but IP is not selected.\n" pr_err("Display of DSO requested but neither sample IP nor "
"No addresses to convert to dso.\n"); "sample address\nis selected. Hence, no addresses to convert "
"to DSO.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -288,6 +298,63 @@ static void print_sample_start(struct perf_sample *sample, ...@@ -288,6 +298,63 @@ static void print_sample_start(struct perf_sample *sample,
} }
} }
static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
{
if ((attr->type == PERF_TYPE_SOFTWARE) &&
((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
return true;
return false;
}
static void print_sample_addr(union perf_event *event,
struct perf_sample *sample,
struct perf_session *session,
struct thread *thread,
struct perf_event_attr *attr)
{
struct addr_location al;
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
const char *symname, *dsoname;
printf("%16" PRIx64, sample->addr);
if (!sample_addr_correlates_sym(attr))
return;
thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
event->ip.pid, sample->addr, &al);
if (!al.map)
thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
event->ip.pid, sample->addr, &al);
al.cpu = sample->cpu;
al.sym = NULL;
if (al.map)
al.sym = map__find_symbol(al.map, al.addr, NULL);
if (PRINT_FIELD(SYM)) {
if (al.sym && al.sym->name)
symname = al.sym->name;
else
symname = "";
printf(" %16s", symname);
}
if (PRINT_FIELD(DSO)) {
if (al.map && al.map->dso && al.map->dso->name)
dsoname = al.map->dso->name;
else
dsoname = "";
printf(" (%s)", dsoname);
}
}
static void process_event(union perf_event *event __unused, static void process_event(union perf_event *event __unused,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
...@@ -305,6 +372,9 @@ static void process_event(union perf_event *event __unused, ...@@ -305,6 +372,9 @@ 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(ADDR))
print_sample_addr(event, sample, session, thread, attr);
if (PRINT_FIELD(IP)) { if (PRINT_FIELD(IP)) {
if (!symbol_conf.use_callchain) if (!symbol_conf.use_callchain)
printf(" "); printf(" ");
...@@ -1003,7 +1073,7 @@ static const struct option options[] = { ...@@ -1003,7 +1073,7 @@ 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", "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",
parse_output_fields), parse_output_fields),
OPT_END() OPT_END()
......
...@@ -377,6 +377,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, ...@@ -377,6 +377,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
array++; array++;
} }
data->addr = 0;
if (type & PERF_SAMPLE_ADDR) { if (type & PERF_SAMPLE_ADDR) {
data->addr = *array; data->addr = *array;
array++; array++;
......
...@@ -708,9 +708,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event, ...@@ -708,9 +708,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
if (!dump_trace) if (!dump_trace)
return; return;
printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n", printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
event->header.misc, sample->pid, sample->tid, sample->ip, event->header.misc, sample->pid, sample->tid, sample->ip,
sample->period); sample->period, sample->addr);
if (session->sample_type & PERF_SAMPLE_CALLCHAIN) if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
callchain__printf(sample); callchain__printf(sample);
......
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