diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-16 10:49:27 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-16 10:53:37 -0500 |
commit | c351c2816177eb7d2979ec874b9b895abe9d6e5c (patch) | |
tree | b6dd7fb4a5e048168319111e18082025c2e93f1b /tools/perf/util | |
parent | 125c4fad1e60751ceaab1ee2a73bddf31213e5ca (diff) |
perf diff: Use perf_session__fprintf_hists just like 'perf record'
That means that almost everything you can do with 'perf report'
can be done with 'perf diff', for instance:
$ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2699
samples) ] $ perf record -f find / > /dev/null
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.062 MB perf.data (~2687
samples) ] perf diff | head -8
9.02% +1.00% find libc-2.10.1.so [.] _IO_vfprintf_internal
2.91% -1.00% find [kernel] [k] __kmalloc
2.85% -1.00% find [kernel] [k] ext4_htree_store_dirent
1.99% -1.00% find [kernel] [k] _atomic_dec_and_lock
2.44% find [kernel] [k] half_md4_transform
$
So if you want to zoom into libc:
$ perf diff --dsos libc-2.10.1.so | head -8
37.34% find [.] _IO_vfprintf_internal
10.34% find [.] __GI_memmove
8.25% +2.00% find [.] _int_malloc
5.07% -1.00% find [.] __GI_mempcpy
7.62% +2.00% find [.] _int_free
$
And if there were multiple commands using libc, it is also
possible to aggregate them all by using --sort symbol:
$ perf diff --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% [.] __GI_mempcpy
7.62% +2.00% [.] _int_free
$
The displacement column now is off by default, to use it:
perf diff -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34% [.] _IO_vfprintf_internal
10.34% [.] __GI_memmove
8.25% +2.00% [.] _int_malloc
5.07% -1.00% +2 [.] __GI_mempcpy
7.62% +2.00% -1 [.] _int_free
$
Using -t/--field-separator can be used for scripting:
$ perf diff -t, -m --dsos libc-2.10.1.so --sort symbol | head -8
37.34, , ,[.] _IO_vfprintf_internal
10.34, , ,[.] __GI_memmove
8.25,+2.00%, ,[.] _int_malloc
5.07,-1.00%, +2,[.] __GI_mempcpy
7.62,+2.00%, -1,[.] _int_free
6.99,+1.00%, -1,[.] _IO_new_file_xsputn
1.89,-2.00%, +4,[.] __readdir64
$
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: <1260978567-550-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/hist.c | 126 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 11 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 2 |
4 files changed, 119 insertions, 25 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6e416a62e0d6..ecf853cdc0bf 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -454,34 +454,80 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
454 | return ret; | 454 | return ret; |
455 | } | 455 | } |
456 | 456 | ||
457 | static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | 457 | static size_t hist_entry__fprintf(struct hist_entry *self, |
458 | struct perf_session *session) | 458 | struct perf_session *session, |
459 | struct perf_session *pair_session, | ||
460 | bool show_displacement, | ||
461 | long displacement, FILE *fp) | ||
459 | { | 462 | { |
460 | struct sort_entry *se; | 463 | struct sort_entry *se; |
464 | u64 count, total; | ||
465 | const char *sep = symbol_conf.field_sep; | ||
461 | size_t ret; | 466 | size_t ret; |
462 | 467 | ||
463 | if (symbol_conf.exclude_other && !self->parent) | 468 | if (symbol_conf.exclude_other && !self->parent) |
464 | return 0; | 469 | return 0; |
465 | 470 | ||
466 | if (session->events_stats.total) | 471 | if (pair_session) { |
467 | ret = percent_color_fprintf(fp, | 472 | count = self->pair ? self->pair->count : 0; |
468 | symbol_conf.field_sep ? "%.2f" : " %6.2f%%", | 473 | total = pair_session->events_stats.total; |
469 | (self->count * 100.0) / session->events_stats.total); | 474 | } else { |
475 | count = self->count; | ||
476 | total = session->events_stats.total; | ||
477 | } | ||
478 | |||
479 | if (total) | ||
480 | ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", | ||
481 | (count * 100.0) / total); | ||
470 | else | 482 | else |
471 | ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count); | 483 | ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); |
472 | 484 | ||
473 | if (symbol_conf.show_nr_samples) { | 485 | if (symbol_conf.show_nr_samples) { |
474 | if (symbol_conf.field_sep) | 486 | if (sep) |
475 | fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count); | 487 | fprintf(fp, "%c%lld", *sep, count); |
476 | else | 488 | else |
477 | fprintf(fp, "%11lld", self->count); | 489 | fprintf(fp, "%11lld", count); |
490 | } | ||
491 | |||
492 | if (pair_session) { | ||
493 | char bf[32]; | ||
494 | double old_percent = 0, new_percent = 0, diff; | ||
495 | |||
496 | if (total > 0) | ||
497 | old_percent = (count * 100) / total; | ||
498 | if (session->events_stats.total > 0) | ||
499 | new_percent = (self->count * 100) / session->events_stats.total; | ||
500 | |||
501 | diff = old_percent - new_percent; | ||
502 | |||
503 | if ((u64)diff != 0) | ||
504 | snprintf(bf, sizeof(bf), "%+4.2F%%", diff); | ||
505 | else | ||
506 | snprintf(bf, sizeof(bf), " "); | ||
507 | |||
508 | if (sep) | ||
509 | ret += fprintf(fp, "%c%s", *sep, bf); | ||
510 | else | ||
511 | ret += fprintf(fp, "%11.11s", bf); | ||
512 | |||
513 | if (show_displacement) { | ||
514 | if (displacement) | ||
515 | snprintf(bf, sizeof(bf), "%+4ld", displacement); | ||
516 | else | ||
517 | snprintf(bf, sizeof(bf), " "); | ||
518 | |||
519 | if (sep) | ||
520 | fprintf(fp, "%c%s", *sep, bf); | ||
521 | else | ||
522 | fprintf(fp, "%6.6s", bf); | ||
523 | } | ||
478 | } | 524 | } |
479 | 525 | ||
480 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 526 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
481 | if (se->elide) | 527 | if (se->elide) |
482 | continue; | 528 | continue; |
483 | 529 | ||
484 | fprintf(fp, "%s", symbol_conf.field_sep ?: " "); | 530 | fprintf(fp, "%s", sep ?: " "); |
485 | ret += se->print(fp, self, se->width ? *se->width : 0); | 531 | ret += se->print(fp, self, se->width ? *se->width : 0); |
486 | } | 532 | } |
487 | 533 | ||
@@ -504,29 +550,49 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, | |||
504 | return ret; | 550 | return ret; |
505 | } | 551 | } |
506 | 552 | ||
507 | size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | 553 | size_t perf_session__fprintf_hists(struct perf_session *self, |
554 | struct perf_session *pair, | ||
555 | bool show_displacement, FILE *fp) | ||
508 | { | 556 | { |
509 | struct hist_entry *pos; | ||
510 | struct sort_entry *se; | 557 | struct sort_entry *se; |
511 | struct rb_node *nd; | 558 | struct rb_node *nd; |
512 | size_t ret = 0; | 559 | size_t ret = 0; |
560 | unsigned long position = 1; | ||
561 | long displacement = 0; | ||
513 | unsigned int width; | 562 | unsigned int width; |
563 | const char *sep = symbol_conf.field_sep; | ||
514 | char *col_width = symbol_conf.col_width_list_str; | 564 | char *col_width = symbol_conf.col_width_list_str; |
515 | 565 | ||
516 | init_rem_hits(); | 566 | init_rem_hits(); |
517 | 567 | ||
518 | fprintf(fp, "# Overhead"); | 568 | fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); |
569 | |||
519 | if (symbol_conf.show_nr_samples) { | 570 | if (symbol_conf.show_nr_samples) { |
520 | if (symbol_conf.field_sep) | 571 | if (sep) |
521 | fprintf(fp, "%cSamples", *symbol_conf.field_sep); | 572 | fprintf(fp, "%cSamples", *sep); |
522 | else | 573 | else |
523 | fputs(" Samples ", fp); | 574 | fputs(" Samples ", fp); |
524 | } | 575 | } |
576 | |||
577 | if (pair) { | ||
578 | if (sep) | ||
579 | ret += fprintf(fp, "%cDelta", *sep); | ||
580 | else | ||
581 | ret += fprintf(fp, " Delta "); | ||
582 | |||
583 | if (show_displacement) { | ||
584 | if (sep) | ||
585 | ret += fprintf(fp, "%cDisplacement", *sep); | ||
586 | else | ||
587 | ret += fprintf(fp, " Displ"); | ||
588 | } | ||
589 | } | ||
590 | |||
525 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 591 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
526 | if (se->elide) | 592 | if (se->elide) |
527 | continue; | 593 | continue; |
528 | if (symbol_conf.field_sep) { | 594 | if (sep) { |
529 | fprintf(fp, "%c%s", *symbol_conf.field_sep, se->header); | 595 | fprintf(fp, "%c%s", *sep, se->header); |
530 | continue; | 596 | continue; |
531 | } | 597 | } |
532 | width = strlen(se->header); | 598 | width = strlen(se->header); |
@@ -545,12 +611,17 @@ size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | |||
545 | } | 611 | } |
546 | fprintf(fp, "\n"); | 612 | fprintf(fp, "\n"); |
547 | 613 | ||
548 | if (symbol_conf.field_sep) | 614 | if (sep) |
549 | goto print_entries; | 615 | goto print_entries; |
550 | 616 | ||
551 | fprintf(fp, "# ........"); | 617 | fprintf(fp, "# ........"); |
552 | if (symbol_conf.show_nr_samples) | 618 | if (symbol_conf.show_nr_samples) |
553 | fprintf(fp, " .........."); | 619 | fprintf(fp, " .........."); |
620 | if (pair) { | ||
621 | fprintf(fp, " .........."); | ||
622 | if (show_displacement) | ||
623 | fprintf(fp, " ....."); | ||
624 | } | ||
554 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 625 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
555 | unsigned int i; | 626 | unsigned int i; |
556 | 627 | ||
@@ -565,14 +636,23 @@ size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp) | |||
565 | for (i = 0; i < width; i++) | 636 | for (i = 0; i < width; i++) |
566 | fprintf(fp, "."); | 637 | fprintf(fp, "."); |
567 | } | 638 | } |
568 | fprintf(fp, "\n"); | ||
569 | 639 | ||
570 | fprintf(fp, "#\n"); | 640 | fprintf(fp, "\n#\n"); |
571 | 641 | ||
572 | print_entries: | 642 | print_entries: |
573 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | 643 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { |
574 | pos = rb_entry(nd, struct hist_entry, rb_node); | 644 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
575 | ret += hist_entry__fprintf(fp, pos, self); | 645 | |
646 | if (show_displacement) { | ||
647 | if (h->pair != NULL) | ||
648 | displacement = ((long)h->pair->position - | ||
649 | (long)position); | ||
650 | else | ||
651 | displacement = 0; | ||
652 | ++position; | ||
653 | } | ||
654 | ret += hist_entry__fprintf(h, self, pair, show_displacement, | ||
655 | displacement, fp); | ||
576 | } | 656 | } |
577 | 657 | ||
578 | free(rem_sq_bracket); | 658 | free(rem_sq_bracket); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index c7ac78d93b0c..e5f99b24048b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -21,6 +21,7 @@ void hist_entry__free(struct hist_entry *); | |||
21 | 21 | ||
22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); | 22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); |
23 | void perf_session__collapse_resort(struct perf_session *self); | 23 | void perf_session__collapse_resort(struct perf_session *self); |
24 | size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp); | 24 | size_t perf_session__fprintf_hists(struct perf_session *self, |
25 | 25 | struct perf_session *pair, | |
26 | bool show_displacement, FILE *fp); | ||
26 | #endif /* __PERF_HIST_H */ | 27 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cff1c316fa91..cb0f327de9e8 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -303,3 +303,14 @@ void setup_sorting(const char * const usagestr[], const struct option *opts) | |||
303 | 303 | ||
304 | free(str); | 304 | free(str); |
305 | } | 305 | } |
306 | |||
307 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | ||
308 | const char *list_name, FILE *fp) | ||
309 | { | ||
310 | if (list && strlist__nr_entries(list) == 1) { | ||
311 | if (fp != NULL) | ||
312 | fprintf(fp, "# %s: %s\n", list_name, | ||
313 | strlist__entry(list, 0)->s); | ||
314 | self->elide = true; | ||
315 | } | ||
316 | } | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 925f083e1eee..753f9ea99fb0 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -101,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); | |||
101 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); | 101 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); |
102 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); | 102 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); |
103 | extern int sort_dimension__add(const char *); | 103 | extern int sort_dimension__add(const char *); |
104 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | ||
105 | const char *list_name, FILE *fp); | ||
104 | 106 | ||
105 | #endif /* __PERF_SORT_H */ | 107 | #endif /* __PERF_SORT_H */ |