diff options
| author | David Ahern <dsahern@gmail.com> | 2011-05-30 15:08:23 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-06-02 12:31:01 -0400 |
| commit | 7cec0922389e080d11ec43dd23aa778e136bd1e1 (patch) | |
| tree | 0d772b32f38b4ef16e4256711e947b38baa2c2f9 /tools | |
| parent | 610723f24eeb842025178a6722fa9108c4e157b6 (diff) | |
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.com
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/Documentation/perf-script.txt | 4 | ||||
| -rw-r--r-- | tools/perf/builtin-script.c | 84 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 4 |
4 files changed, 82 insertions, 11 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 1e744c2391dc..c6068cb43f57 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
| @@ -115,8 +115,8 @@ OPTIONS | |||
| 115 | -f:: | 115 | -f:: |
| 116 | --fields:: | 116 | --fields:: |
| 117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
| 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso. Field | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr. |
| 119 | list can be prepended with the type, trace, sw or hw, | 119 | Field list can be prepended with the type, trace, sw or hw, |
| 120 | to indicate to which event type the field list applies. | 120 | to indicate to which event type the field list applies. |
| 121 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace | 121 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace |
| 122 | 122 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a8bd00f2e557..3056b45b3dd6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -33,6 +33,7 @@ enum perf_output_field { | |||
| 33 | PERF_OUTPUT_IP = 1U << 7, | 33 | PERF_OUTPUT_IP = 1U << 7, |
| 34 | PERF_OUTPUT_SYM = 1U << 8, | 34 | PERF_OUTPUT_SYM = 1U << 8, |
| 35 | PERF_OUTPUT_DSO = 1U << 9, | 35 | PERF_OUTPUT_DSO = 1U << 9, |
| 36 | PERF_OUTPUT_ADDR = 1U << 10, | ||
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | struct output_option { | 39 | struct output_option { |
| @@ -49,6 +50,7 @@ struct output_option { | |||
| 49 | {.str = "ip", .field = PERF_OUTPUT_IP}, | 50 | {.str = "ip", .field = PERF_OUTPUT_IP}, |
| 50 | {.str = "sym", .field = PERF_OUTPUT_SYM}, | 51 | {.str = "sym", .field = PERF_OUTPUT_SYM}, |
| 51 | {.str = "dso", .field = PERF_OUTPUT_DSO}, | 52 | {.str = "dso", .field = PERF_OUTPUT_DSO}, |
| 53 | {.str = "addr", .field = PERF_OUTPUT_ADDR}, | ||
| 52 | }; | 54 | }; |
| 53 | 55 | ||
| 54 | /* default set to maintain compatibility with current format */ | 56 | /* default set to maintain compatibility with current format */ |
| @@ -173,14 +175,22 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 173 | !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) | 175 | !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) |
| 174 | symbol_conf.use_callchain = false; | 176 | symbol_conf.use_callchain = false; |
| 175 | } | 177 | } |
| 176 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP)) { | 178 | |
| 177 | pr_err("Display of symbols requested but IP is not selected.\n" | 179 | if (PRINT_FIELD(ADDR) && |
| 178 | "No addresses to convert to symbols.\n"); | 180 | perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", |
| 181 | PERF_OUTPUT_ADDR)) | ||
| 182 | return -EINVAL; | ||
| 183 | |||
| 184 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | ||
| 185 | pr_err("Display of symbols requested but neither sample IP nor " | ||
| 186 | "sample address\nis selected. Hence, no addresses to convert " | ||
| 187 | "to symbols.\n"); | ||
| 179 | return -EINVAL; | 188 | return -EINVAL; |
| 180 | } | 189 | } |
| 181 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP)) { | 190 | if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
| 182 | pr_err("Display of DSO requested but IP is not selected.\n" | 191 | pr_err("Display of DSO requested but neither sample IP nor " |
| 183 | "No addresses to convert to dso.\n"); | 192 | "sample address\nis selected. Hence, no addresses to convert " |
| 193 | "to DSO.\n"); | ||
| 184 | return -EINVAL; | 194 | return -EINVAL; |
| 185 | } | 195 | } |
| 186 | 196 | ||
| @@ -288,6 +298,63 @@ static void print_sample_start(struct perf_sample *sample, | |||
| 288 | } | 298 | } |
| 289 | } | 299 | } |
| 290 | 300 | ||
| 301 | static bool sample_addr_correlates_sym(struct perf_event_attr *attr) | ||
| 302 | { | ||
| 303 | if ((attr->type == PERF_TYPE_SOFTWARE) && | ||
| 304 | ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) || | ||
| 305 | (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) || | ||
| 306 | (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))) | ||
| 307 | return true; | ||
| 308 | |||
| 309 | return false; | ||
| 310 | } | ||
| 311 | |||
| 312 | static void print_sample_addr(union perf_event *event, | ||
| 313 | struct perf_sample *sample, | ||
| 314 | struct perf_session *session, | ||
| 315 | struct thread *thread, | ||
| 316 | struct perf_event_attr *attr) | ||
| 317 | { | ||
| 318 | struct addr_location al; | ||
| 319 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
| 320 | const char *symname, *dsoname; | ||
| 321 | |||
| 322 | printf("%16" PRIx64, sample->addr); | ||
| 323 | |||
| 324 | if (!sample_addr_correlates_sym(attr)) | ||
| 325 | return; | ||
| 326 | |||
| 327 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, | ||
| 328 | event->ip.pid, sample->addr, &al); | ||
| 329 | if (!al.map) | ||
| 330 | thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, | ||
| 331 | event->ip.pid, sample->addr, &al); | ||
| 332 | |||
| 333 | al.cpu = sample->cpu; | ||
| 334 | al.sym = NULL; | ||
| 335 | |||
| 336 | if (al.map) | ||
| 337 | al.sym = map__find_symbol(al.map, al.addr, NULL); | ||
| 338 | |||
| 339 | if (PRINT_FIELD(SYM)) { | ||
| 340 | if (al.sym && al.sym->name) | ||
| 341 | symname = al.sym->name; | ||
| 342 | else | ||
| 343 | symname = ""; | ||
| 344 | |||
| 345 | printf(" %16s", symname); | ||
| 346 | } | ||
| 347 | |||
| 348 | if (PRINT_FIELD(DSO)) { | ||
| 349 | if (al.map && al.map->dso && al.map->dso->name) | ||
| 350 | dsoname = al.map->dso->name; | ||
| 351 | else | ||
| 352 | dsoname = ""; | ||
| 353 | |||
| 354 | printf(" (%s)", dsoname); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 291 | static void process_event(union perf_event *event __unused, | 358 | static void process_event(union perf_event *event __unused, |
| 292 | struct perf_sample *sample, | 359 | struct perf_sample *sample, |
| 293 | struct perf_evsel *evsel, | 360 | struct perf_evsel *evsel, |
| @@ -305,6 +372,9 @@ static void process_event(union perf_event *event __unused, | |||
| 305 | print_trace_event(sample->cpu, sample->raw_data, | 372 | print_trace_event(sample->cpu, sample->raw_data, |
| 306 | sample->raw_size); | 373 | sample->raw_size); |
| 307 | 374 | ||
| 375 | if (PRINT_FIELD(ADDR)) | ||
| 376 | print_sample_addr(event, sample, session, thread, attr); | ||
| 377 | |||
| 308 | if (PRINT_FIELD(IP)) { | 378 | if (PRINT_FIELD(IP)) { |
| 309 | if (!symbol_conf.use_callchain) | 379 | if (!symbol_conf.use_callchain) |
| 310 | printf(" "); | 380 | printf(" "); |
| @@ -1003,7 +1073,7 @@ static const struct option options[] = { | |||
| 1003 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1073 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
| 1004 | "Look for files with symbols relative to this directory"), | 1074 | "Look for files with symbols relative to this directory"), |
| 1005 | OPT_CALLBACK('f', "fields", NULL, "str", | 1075 | OPT_CALLBACK('f', "fields", NULL, "str", |
| 1006 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso", | 1076 | "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", |
| 1007 | parse_output_fields), | 1077 | parse_output_fields), |
| 1008 | 1078 | ||
| 1009 | OPT_END() | 1079 | OPT_END() |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0239eb87b232..a03a36b7908a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -377,6 +377,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
| 377 | array++; | 377 | array++; |
| 378 | } | 378 | } |
| 379 | 379 | ||
| 380 | data->addr = 0; | ||
| 380 | if (type & PERF_SAMPLE_ADDR) { | 381 | if (type & PERF_SAMPLE_ADDR) { |
| 381 | data->addr = *array; | 382 | data->addr = *array; |
| 382 | array++; | 383 | array++; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0dd418299261..b723f211881c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -708,9 +708,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event, | |||
| 708 | if (!dump_trace) | 708 | if (!dump_trace) |
| 709 | return; | 709 | return; |
| 710 | 710 | ||
| 711 | printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n", | 711 | printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n", |
| 712 | event->header.misc, sample->pid, sample->tid, sample->ip, | 712 | event->header.misc, sample->pid, sample->tid, sample->ip, |
| 713 | sample->period); | 713 | sample->period, sample->addr); |
| 714 | 714 | ||
| 715 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) | 715 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) |
| 716 | callchain__printf(sample); | 716 | callchain__printf(sample); |
