diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-15 17:04:41 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-16 02:53:49 -0500 |
commit | c410a33887c17cac95ed8b0d860cdfb5c087a7d8 (patch) | |
tree | 54fe6ed5ac64ff77763ff686af58bd36b04e73d6 | |
parent | 655000e7c75a559681ee7f15f6fa870c80ae3194 (diff) |
perf symbols: Move symbol filtering to event__preprocess_sample()
So that --dsos, --comm, --symbols can bem used in more tools,
like in perf diff:
$ perf record -f find / > /dev/null
$ perf record -f find / > /dev/null
$ perf diff --dsos /lib64/libc-2.10.1.so | head -5
1 +22392124 /lib64/libc-2.10.1.so _IO_vfprintf_internal
2 +6410655 /lib64/libc-2.10.1.so __GI_memmove
3 +1 +9192692 /lib64/libc-2.10.1.so _int_malloc
4 -1 -15158605 /lib64/libc-2.10.1.so _int_free
5 +45669 /lib64/libc-2.10.1.so _IO_new_file_xsputn
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260914682-29652-3-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 19 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 86 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/util/event.c | 42 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 5 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 4 |
7 files changed, 84 insertions, 76 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 645d58058431..593ff25006de 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -141,7 +141,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
141 | return -1; | 141 | return -1; |
142 | } | 142 | } |
143 | 143 | ||
144 | if (perf_session__add_hist_entry(session, &al, 1)) { | 144 | if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { |
145 | fprintf(stderr, "problem incrementing symbol count, " | 145 | fprintf(stderr, "problem incrementing symbol count, " |
146 | "skipping event\n"); | 146 | "skipping event\n"); |
147 | return -1; | 147 | return -1; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 4fde60655341..ff91e9c291bb 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -50,6 +50,9 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi | |||
50 | return -1; | 50 | return -1; |
51 | } | 51 | } |
52 | 52 | ||
53 | if (al.filtered) | ||
54 | return 0; | ||
55 | |||
53 | event__parse_sample(event, session->sample_type, &data); | 56 | event__parse_sample(event, session->sample_type, &data); |
54 | 57 | ||
55 | if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) { | 58 | if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) { |
@@ -182,10 +185,14 @@ blank: memset(displacement, ' ', sizeof(displacement)); | |||
182 | printed = fprintf(fp, "%4lu %5.5s ", pos, displacement); | 185 | printed = fprintf(fp, "%4lu %5.5s ", pos, displacement); |
183 | 186 | ||
184 | if (show_percent) { | 187 | if (show_percent) { |
185 | double old_percent = (old_count * 100) / pair_session->events_stats.total, | 188 | double old_percent = 0, new_percent = 0, diff; |
186 | new_percent = (self->count * 100) / session->events_stats.total; | 189 | |
187 | double diff = old_percent - new_percent; | 190 | if (pair_session->events_stats.total > 0) |
191 | old_percent = (old_count * 100) / pair_session->events_stats.total; | ||
192 | if (session->events_stats.total > 0) | ||
193 | new_percent = (self->count * 100) / session->events_stats.total; | ||
188 | 194 | ||
195 | diff = old_percent - new_percent; | ||
189 | if (verbose) | 196 | if (verbose) |
190 | printed += fprintf(fp, " %3.2f%% %3.2f%%", old_percent, new_percent); | 197 | printed += fprintf(fp, " %3.2f%% %3.2f%%", old_percent, new_percent); |
191 | 198 | ||
@@ -260,6 +267,12 @@ static const struct option options[] = { | |||
260 | "Don't shorten the pathnames taking into account the cwd"), | 267 | "Don't shorten the pathnames taking into account the cwd"), |
261 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, | 268 | OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, |
262 | "Don't shorten the pathnames taking into account the cwd"), | 269 | "Don't shorten the pathnames taking into account the cwd"), |
270 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | ||
271 | "only consider symbols in these dsos"), | ||
272 | OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | ||
273 | "only consider symbols in these comms"), | ||
274 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | ||
275 | "only consider these symbols"), | ||
263 | OPT_END() | 276 | OPT_END() |
264 | }; | 277 | }; |
265 | 278 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 03afac3b56ef..9c595340326a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -316,14 +316,14 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | |||
316 | 316 | ||
317 | if (total_samples) | 317 | if (total_samples) |
318 | ret = percent_color_fprintf(fp, | 318 | ret = percent_color_fprintf(fp, |
319 | field_sep ? "%.2f" : " %6.2f%%", | 319 | symbol_conf.field_sep ? "%.2f" : " %6.2f%%", |
320 | (self->count * 100.0) / total_samples); | 320 | (self->count * 100.0) / total_samples); |
321 | else | 321 | else |
322 | ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count); | 322 | ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count); |
323 | 323 | ||
324 | if (show_nr_samples) { | 324 | if (show_nr_samples) { |
325 | if (field_sep) | 325 | if (symbol_conf.field_sep) |
326 | fprintf(fp, "%c%lld", *field_sep, self->count); | 326 | fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count); |
327 | else | 327 | else |
328 | fprintf(fp, "%11lld", self->count); | 328 | fprintf(fp, "%11lld", self->count); |
329 | } | 329 | } |
@@ -332,7 +332,7 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | |||
332 | if (se->elide) | 332 | if (se->elide) |
333 | continue; | 333 | continue; |
334 | 334 | ||
335 | fprintf(fp, "%s", field_sep ?: " "); | 335 | fprintf(fp, "%s", symbol_conf.field_sep ?: " "); |
336 | ret += se->print(fp, self, se->width ? *se->width : 0); | 336 | ret += se->print(fp, self, se->width ? *se->width : 0); |
337 | } | 337 | } |
338 | 338 | ||
@@ -355,28 +355,11 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | |||
355 | return ret; | 355 | return ret; |
356 | } | 356 | } |
357 | 357 | ||
358 | /* | ||
359 | * | ||
360 | */ | ||
361 | |||
362 | static void dso__calc_col_width(struct dso *self) | ||
363 | { | ||
364 | if (!symbol_conf.col_width_list_str && !field_sep && | ||
365 | (!symbol_conf.dso_list || | ||
366 | strlist__has_entry(symbol_conf.dso_list, self->name))) { | ||
367 | unsigned int slen = strlen(self->name); | ||
368 | if (slen > dsos__col_width) | ||
369 | dsos__col_width = slen; | ||
370 | } | ||
371 | |||
372 | self->slen_calculated = 1; | ||
373 | } | ||
374 | |||
375 | static void thread__comm_adjust(struct thread *self) | 358 | static void thread__comm_adjust(struct thread *self) |
376 | { | 359 | { |
377 | char *comm = self->comm; | 360 | char *comm = self->comm; |
378 | 361 | ||
379 | if (!symbol_conf.col_width_list_str && !field_sep && | 362 | if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && |
380 | (!symbol_conf.comm_list || | 363 | (!symbol_conf.comm_list || |
381 | strlist__has_entry(symbol_conf.comm_list, comm))) { | 364 | strlist__has_entry(symbol_conf.comm_list, comm))) { |
382 | unsigned int slen = strlen(comm); | 365 | unsigned int slen = strlen(comm); |
@@ -452,16 +435,16 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, | |||
452 | 435 | ||
453 | fprintf(fp, "# Overhead"); | 436 | fprintf(fp, "# Overhead"); |
454 | if (show_nr_samples) { | 437 | if (show_nr_samples) { |
455 | if (field_sep) | 438 | if (symbol_conf.field_sep) |
456 | fprintf(fp, "%cSamples", *field_sep); | 439 | fprintf(fp, "%cSamples", *symbol_conf.field_sep); |
457 | else | 440 | else |
458 | fputs(" Samples ", fp); | 441 | fputs(" Samples ", fp); |
459 | } | 442 | } |
460 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 443 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
461 | if (se->elide) | 444 | if (se->elide) |
462 | continue; | 445 | continue; |
463 | if (field_sep) { | 446 | if (symbol_conf.field_sep) { |
464 | fprintf(fp, "%c%s", *field_sep, se->header); | 447 | fprintf(fp, "%c%s", *symbol_conf.field_sep, se->header); |
465 | continue; | 448 | continue; |
466 | } | 449 | } |
467 | width = strlen(se->header); | 450 | width = strlen(se->header); |
@@ -480,7 +463,7 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, | |||
480 | } | 463 | } |
481 | fprintf(fp, "\n"); | 464 | fprintf(fp, "\n"); |
482 | 465 | ||
483 | if (field_sep) | 466 | if (symbol_conf.field_sep) |
484 | goto print_entries; | 467 | goto print_entries; |
485 | 468 | ||
486 | fprintf(fp, "# ........"); | 469 | fprintf(fp, "# ........"); |
@@ -542,13 +525,8 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
542 | 525 | ||
543 | static int process_sample_event(event_t *event, struct perf_session *session) | 526 | static int process_sample_event(event_t *event, struct perf_session *session) |
544 | { | 527 | { |
545 | struct sample_data data; | 528 | struct sample_data data = { .period = 1, }; |
546 | int cpumode; | ||
547 | struct addr_location al; | 529 | struct addr_location al; |
548 | struct thread *thread; | ||
549 | |||
550 | memset(&data, 0, sizeof(data)); | ||
551 | data.period = 1; | ||
552 | 530 | ||
553 | event__parse_sample(event, session->sample_type, &data); | 531 | event__parse_sample(event, session->sample_type, &data); |
554 | 532 | ||
@@ -576,39 +554,13 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
576 | } | 554 | } |
577 | } | 555 | } |
578 | 556 | ||
579 | thread = perf_session__findnew(session, data.pid); | 557 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { |
580 | if (thread == NULL) { | 558 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
581 | pr_debug("problem processing %d event, skipping it.\n", | ||
582 | event->header.type); | 559 | event->header.type); |
583 | return -1; | 560 | return -1; |
584 | } | 561 | } |
585 | 562 | ||
586 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 563 | if (al.filtered) |
587 | |||
588 | if (symbol_conf.comm_list && | ||
589 | !strlist__has_entry(symbol_conf.comm_list, thread->comm)) | ||
590 | return 0; | ||
591 | |||
592 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
593 | |||
594 | thread__find_addr_location(thread, session, cpumode, | ||
595 | MAP__FUNCTION, data.ip, &al, NULL); | ||
596 | /* | ||
597 | * We have to do this here as we may have a dso with no symbol hit that | ||
598 | * has a name longer than the ones with symbols sampled. | ||
599 | */ | ||
600 | if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated) | ||
601 | dso__calc_col_width(al.map->dso); | ||
602 | |||
603 | if (symbol_conf.dso_list && | ||
604 | (!al.map || !al.map->dso || | ||
605 | !(strlist__has_entry(symbol_conf.dso_list, al.map->dso->short_name) || | ||
606 | (al.map->dso->short_name != al.map->dso->long_name && | ||
607 | strlist__has_entry(symbol_conf.dso_list, al.map->dso->long_name))))) | ||
608 | return 0; | ||
609 | |||
610 | if (symbol_conf.sym_list && al.sym && | ||
611 | !strlist__has_entry(symbol_conf.sym_list, al.sym->name)) | ||
612 | return 0; | 564 | return 0; |
613 | 565 | ||
614 | if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { | 566 | if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { |
@@ -834,7 +786,7 @@ static const struct option options[] = { | |||
834 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, | 786 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, |
835 | "width[,width...]", | 787 | "width[,width...]", |
836 | "don't try to adjust column width, use these fixed values"), | 788 | "don't try to adjust column width, use these fixed values"), |
837 | OPT_STRING('t', "field-separator", &field_sep, "separator", | 789 | OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", |
838 | "separator for columns, no spaces will be added between " | 790 | "separator for columns, no spaces will be added between " |
839 | "columns '.' is reserved."), | 791 | "columns '.' is reserved."), |
840 | OPT_END() | 792 | OPT_END() |
@@ -877,11 +829,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
877 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | 829 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); |
878 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | 830 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); |
879 | 831 | ||
880 | if (field_sep && *field_sep == '.') { | ||
881 | fputs("'.' is the only non valid --field-separator argument\n", | ||
882 | stderr); | ||
883 | exit(129); | ||
884 | } | ||
885 | |||
886 | return __cmd_report(); | 832 | return __cmd_report(); |
887 | } | 833 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index cd89b6d036b7..ddc584b64871 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -948,7 +948,7 @@ static void event__process_sample(const event_t *self, | |||
948 | } | 948 | } |
949 | 949 | ||
950 | if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || | 950 | if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || |
951 | al.sym == NULL) | 951 | al.sym == NULL || al.filtered) |
952 | return; | 952 | return; |
953 | 953 | ||
954 | syme = symbol__priv(al.sym); | 954 | syme = symbol__priv(al.sym); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 375fb6dca1cf..bf491fda1f47 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -2,7 +2,9 @@ | |||
2 | #include "event.h" | 2 | #include "event.h" |
3 | #include "debug.h" | 3 | #include "debug.h" |
4 | #include "session.h" | 4 | #include "session.h" |
5 | #include "sort.h" | ||
5 | #include "string.h" | 6 | #include "string.h" |
7 | #include "strlist.h" | ||
6 | #include "thread.h" | 8 | #include "thread.h" |
7 | 9 | ||
8 | static pid_t event__synthesize_comm(pid_t pid, int full, | 10 | static pid_t event__synthesize_comm(pid_t pid, int full, |
@@ -299,6 +301,19 @@ try_again: | |||
299 | } | 301 | } |
300 | } | 302 | } |
301 | 303 | ||
304 | static void dso__calc_col_width(struct dso *self) | ||
305 | { | ||
306 | if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && | ||
307 | (!symbol_conf.dso_list || | ||
308 | strlist__has_entry(symbol_conf.dso_list, self->name))) { | ||
309 | unsigned int slen = strlen(self->name); | ||
310 | if (slen > dsos__col_width) | ||
311 | dsos__col_width = slen; | ||
312 | } | ||
313 | |||
314 | self->slen_calculated = 1; | ||
315 | } | ||
316 | |||
302 | int event__preprocess_sample(const event_t *self, struct perf_session *session, | 317 | int event__preprocess_sample(const event_t *self, struct perf_session *session, |
303 | struct addr_location *al, symbol_filter_t filter) | 318 | struct addr_location *al, symbol_filter_t filter) |
304 | { | 319 | { |
@@ -308,6 +323,10 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
308 | if (thread == NULL) | 323 | if (thread == NULL) |
309 | return -1; | 324 | return -1; |
310 | 325 | ||
326 | if (symbol_conf.comm_list && | ||
327 | !strlist__has_entry(symbol_conf.comm_list, thread->comm)) | ||
328 | goto out_filtered; | ||
329 | |||
311 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 330 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
312 | 331 | ||
313 | thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, | 332 | thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, |
@@ -315,6 +334,29 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
315 | dump_printf(" ...... dso: %s\n", | 334 | dump_printf(" ...... dso: %s\n", |
316 | al->map ? al->map->dso->long_name : | 335 | al->map ? al->map->dso->long_name : |
317 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | 336 | al->level == 'H' ? "[hypervisor]" : "<not found>"); |
337 | /* | ||
338 | * We have to do this here as we may have a dso with no symbol hit that | ||
339 | * has a name longer than the ones with symbols sampled. | ||
340 | */ | ||
341 | if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) | ||
342 | dso__calc_col_width(al->map->dso); | ||
343 | |||
344 | if (symbol_conf.dso_list && | ||
345 | (!al->map || !al->map->dso || | ||
346 | !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || | ||
347 | (al->map->dso->short_name != al->map->dso->long_name && | ||
348 | strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) | ||
349 | goto out_filtered; | ||
350 | |||
351 | if (symbol_conf.sym_list && al->sym && | ||
352 | !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) | ||
353 | goto out_filtered; | ||
354 | |||
355 | al->filtered = false; | ||
356 | return 0; | ||
357 | |||
358 | out_filtered: | ||
359 | al->filtered = true; | ||
318 | return 0; | 360 | return 0; |
319 | } | 361 | } |
320 | 362 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 164286ace7df..7707897b59f1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1764,6 +1764,11 @@ int symbol__init(void) | |||
1764 | if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) | 1764 | if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) |
1765 | return -1; | 1765 | return -1; |
1766 | 1766 | ||
1767 | if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { | ||
1768 | pr_err("'.' is the only non valid --field-separator argument\n"); | ||
1769 | return -1; | ||
1770 | } | ||
1771 | |||
1767 | if (setup_list(&symbol_conf.dso_list, | 1772 | if (setup_list(&symbol_conf.dso_list, |
1768 | symbol_conf.dso_list_str, "dso") < 0) | 1773 | symbol_conf.dso_list_str, "dso") < 0) |
1769 | return -1; | 1774 | return -1; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index d61f35074997..60151521f41d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -56,7 +56,8 @@ struct symbol_conf { | |||
56 | bool try_vmlinux_path, | 56 | bool try_vmlinux_path, |
57 | use_modules, | 57 | use_modules, |
58 | sort_by_name; | 58 | sort_by_name; |
59 | const char *vmlinux_name; | 59 | const char *vmlinux_name, |
60 | *field_sep; | ||
60 | char *dso_list_str, | 61 | char *dso_list_str, |
61 | *comm_list_str, | 62 | *comm_list_str, |
62 | *sym_list_str, | 63 | *sym_list_str, |
@@ -79,6 +80,7 @@ struct addr_location { | |||
79 | struct symbol *sym; | 80 | struct symbol *sym; |
80 | u64 addr; | 81 | u64 addr; |
81 | char level; | 82 | char level; |
83 | bool filtered; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | struct dso { | 86 | struct dso { |