diff options
author | Namhyung Kim <namhyung@kernel.org> | 2014-01-07 03:02:25 -0500 |
---|---|---|
committer | Jiri Olsa <jolsa@kernel.org> | 2014-06-01 08:35:05 -0400 |
commit | 9d3c02d7188866299eebe3c4a652c08140a71f40 (patch) | |
tree | 1a45d4db4976bb33a0f315d24f6fa7f70aef1c66 /tools | |
parent | 2bf1a12340bda1bf621f27b9892094a51b1297fd (diff) |
perf tools: Add callback function to hist_entry_iter
The new ->add_entry_cb() will be called after an entry was added to
the histogram. It's used for code sharing between perf report and
perf top. Note that ops->add_*_entry() should set iter->he properly
in order to call the ->add_entry_cb.
Also pass @arg to the callback function. It'll be used by perf top
later.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arun Sharma <asharma@fb.com>
Tested-by: Rodrigo Campos <rodrigo@sdfg.com.ar>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Link: http://lkml.kernel.org/r/87k393g999.fsf@sejong.aot.lge.com
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-report.c | 61 | ||||
-rw-r--r-- | tools/perf/tests/hists_filter.c | 2 | ||||
-rw-r--r-- | tools/perf/tests/hists_output.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 67 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 5 |
5 files changed, 84 insertions, 53 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6cac509212ee..21d830bafff3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -80,14 +80,59 @@ static int report__config(const char *var, const char *value, void *cb) | |||
80 | return perf_default_config(var, value, cb); | 80 | return perf_default_config(var, value, cb); |
81 | } | 81 | } |
82 | 82 | ||
83 | static void report__inc_stats(struct report *rep, | 83 | static void report__inc_stats(struct report *rep, struct hist_entry *he) |
84 | struct hist_entry *he __maybe_unused) | ||
85 | { | 84 | { |
86 | /* | 85 | /* |
87 | * We cannot access @he at this time. Just assume it's a new entry. | 86 | * The @he is either of a newly created one or an existing one |
88 | * It'll be fixed once we have a callback mechanism in hist_iter. | 87 | * merging current sample. We only want to count a new one so |
88 | * checking ->nr_events being 1. | ||
89 | */ | 89 | */ |
90 | rep->nr_entries++; | 90 | if (he->stat.nr_events == 1) |
91 | rep->nr_entries++; | ||
92 | } | ||
93 | |||
94 | static int hist_iter__report_callback(struct hist_entry_iter *iter, | ||
95 | struct addr_location *al, bool single, | ||
96 | void *arg) | ||
97 | { | ||
98 | int err = 0; | ||
99 | struct report *rep = arg; | ||
100 | struct hist_entry *he = iter->he; | ||
101 | struct perf_evsel *evsel = iter->evsel; | ||
102 | struct mem_info *mi; | ||
103 | struct branch_info *bi; | ||
104 | |||
105 | report__inc_stats(rep, he); | ||
106 | |||
107 | if (!ui__has_annotation()) | ||
108 | return 0; | ||
109 | |||
110 | if (sort__mode == SORT_MODE__BRANCH) { | ||
111 | bi = he->branch_info; | ||
112 | err = addr_map_symbol__inc_samples(&bi->from, evsel->idx); | ||
113 | if (err) | ||
114 | goto out; | ||
115 | |||
116 | err = addr_map_symbol__inc_samples(&bi->to, evsel->idx); | ||
117 | |||
118 | } else if (rep->mem_mode) { | ||
119 | mi = he->mem_info; | ||
120 | err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx); | ||
121 | if (err) | ||
122 | goto out; | ||
123 | |||
124 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
125 | |||
126 | } else if (symbol_conf.cumulate_callchain) { | ||
127 | if (single) | ||
128 | err = hist_entry__inc_addr_samples(he, evsel->idx, | ||
129 | al->addr); | ||
130 | } else { | ||
131 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
132 | } | ||
133 | |||
134 | out: | ||
135 | return err; | ||
91 | } | 136 | } |
92 | 137 | ||
93 | static int process_sample_event(struct perf_tool *tool, | 138 | static int process_sample_event(struct perf_tool *tool, |
@@ -100,6 +145,7 @@ static int process_sample_event(struct perf_tool *tool, | |||
100 | struct addr_location al; | 145 | struct addr_location al; |
101 | struct hist_entry_iter iter = { | 146 | struct hist_entry_iter iter = { |
102 | .hide_unresolved = rep->hide_unresolved, | 147 | .hide_unresolved = rep->hide_unresolved, |
148 | .add_entry_cb = hist_iter__report_callback, | ||
103 | }; | 149 | }; |
104 | int ret; | 150 | int ret; |
105 | 151 | ||
@@ -127,9 +173,8 @@ static int process_sample_event(struct perf_tool *tool, | |||
127 | if (al.map != NULL) | 173 | if (al.map != NULL) |
128 | al.map->dso->hit = 1; | 174 | al.map->dso->hit = 1; |
129 | 175 | ||
130 | report__inc_stats(rep, NULL); | 176 | ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack, |
131 | 177 | rep); | |
132 | ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack); | ||
133 | if (ret < 0) | 178 | if (ret < 0) |
134 | pr_debug("problem adding hist entry, skipping event\n"); | 179 | pr_debug("problem adding hist entry, skipping event\n"); |
135 | 180 | ||
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 76b02e1de701..3539403bbad4 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -82,7 +82,7 @@ static int add_hist_entries(struct perf_evlist *evlist, | |||
82 | goto out; | 82 | goto out; |
83 | 83 | ||
84 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, | 84 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, |
85 | PERF_MAX_STACK_DEPTH) < 0) | 85 | PERF_MAX_STACK_DEPTH, NULL) < 0) |
86 | goto out; | 86 | goto out; |
87 | 87 | ||
88 | fake_samples[i].thread = al.thread; | 88 | fake_samples[i].thread = al.thread; |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 1308f88a9169..d40461ecd210 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -71,7 +71,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
71 | goto out; | 71 | goto out; |
72 | 72 | ||
73 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, | 73 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, |
74 | PERF_MAX_STACK_DEPTH) < 0) | 74 | PERF_MAX_STACK_DEPTH, NULL) < 0) |
75 | goto out; | 75 | goto out; |
76 | 76 | ||
77 | fake_samples[i].thread = al.thread; | 77 | fake_samples[i].thread = al.thread; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index c6f5f5251aad..5a0a4b2cadc4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -517,27 +517,16 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al | |||
517 | } | 517 | } |
518 | 518 | ||
519 | static int | 519 | static int |
520 | iter_finish_mem_entry(struct hist_entry_iter *iter, struct addr_location *al) | 520 | iter_finish_mem_entry(struct hist_entry_iter *iter, |
521 | struct addr_location *al __maybe_unused) | ||
521 | { | 522 | { |
522 | struct perf_evsel *evsel = iter->evsel; | 523 | struct perf_evsel *evsel = iter->evsel; |
523 | struct hist_entry *he = iter->he; | 524 | struct hist_entry *he = iter->he; |
524 | struct mem_info *mx; | ||
525 | int err = -EINVAL; | 525 | int err = -EINVAL; |
526 | 526 | ||
527 | if (he == NULL) | 527 | if (he == NULL) |
528 | goto out; | 528 | goto out; |
529 | 529 | ||
530 | if (ui__has_annotation()) { | ||
531 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
532 | if (err) | ||
533 | goto out; | ||
534 | |||
535 | mx = he->mem_info; | ||
536 | err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); | ||
537 | if (err) | ||
538 | goto out; | ||
539 | } | ||
540 | |||
541 | hists__inc_nr_samples(&evsel->hists, he->filtered); | 530 | hists__inc_nr_samples(&evsel->hists, he->filtered); |
542 | 531 | ||
543 | err = hist_entry__append_callchain(he, iter->sample); | 532 | err = hist_entry__append_callchain(he, iter->sample); |
@@ -575,6 +564,9 @@ static int | |||
575 | iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused, | 564 | iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused, |
576 | struct addr_location *al __maybe_unused) | 565 | struct addr_location *al __maybe_unused) |
577 | { | 566 | { |
567 | /* to avoid calling callback function */ | ||
568 | iter->he = NULL; | ||
569 | |||
578 | return 0; | 570 | return 0; |
579 | } | 571 | } |
580 | 572 | ||
@@ -599,7 +591,7 @@ iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) | |||
599 | static int | 591 | static int |
600 | iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) | 592 | iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) |
601 | { | 593 | { |
602 | struct branch_info *bi, *bx; | 594 | struct branch_info *bi; |
603 | struct perf_evsel *evsel = iter->evsel; | 595 | struct perf_evsel *evsel = iter->evsel; |
604 | struct hist_entry *he = NULL; | 596 | struct hist_entry *he = NULL; |
605 | int i = iter->curr; | 597 | int i = iter->curr; |
@@ -619,17 +611,6 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a | |||
619 | if (he == NULL) | 611 | if (he == NULL) |
620 | return -ENOMEM; | 612 | return -ENOMEM; |
621 | 613 | ||
622 | if (ui__has_annotation()) { | ||
623 | bx = he->branch_info; | ||
624 | err = addr_map_symbol__inc_samples(&bx->from, evsel->idx); | ||
625 | if (err) | ||
626 | goto out; | ||
627 | |||
628 | err = addr_map_symbol__inc_samples(&bx->to, evsel->idx); | ||
629 | if (err) | ||
630 | goto out; | ||
631 | } | ||
632 | |||
633 | hists__inc_nr_samples(&evsel->hists, he->filtered); | 614 | hists__inc_nr_samples(&evsel->hists, he->filtered); |
634 | 615 | ||
635 | out: | 616 | out: |
@@ -673,9 +654,9 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location | |||
673 | } | 654 | } |
674 | 655 | ||
675 | static int | 656 | static int |
676 | iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) | 657 | iter_finish_normal_entry(struct hist_entry_iter *iter, |
658 | struct addr_location *al __maybe_unused) | ||
677 | { | 659 | { |
678 | int err; | ||
679 | struct hist_entry *he = iter->he; | 660 | struct hist_entry *he = iter->he; |
680 | struct perf_evsel *evsel = iter->evsel; | 661 | struct perf_evsel *evsel = iter->evsel; |
681 | struct perf_sample *sample = iter->sample; | 662 | struct perf_sample *sample = iter->sample; |
@@ -685,12 +666,6 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) | |||
685 | 666 | ||
686 | iter->he = NULL; | 667 | iter->he = NULL; |
687 | 668 | ||
688 | if (ui__has_annotation()) { | ||
689 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
690 | if (err) | ||
691 | return err; | ||
692 | } | ||
693 | |||
694 | hists__inc_nr_samples(&evsel->hists, he->filtered); | 669 | hists__inc_nr_samples(&evsel->hists, he->filtered); |
695 | 670 | ||
696 | return hist_entry__append_callchain(he, sample); | 671 | return hist_entry__append_callchain(he, sample); |
@@ -746,13 +721,6 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, | |||
746 | */ | 721 | */ |
747 | callchain_cursor_commit(&callchain_cursor); | 722 | callchain_cursor_commit(&callchain_cursor); |
748 | 723 | ||
749 | /* | ||
750 | * The iter->he will be over-written after ->add_next_entry() | ||
751 | * called so inc stats for the original entry now. | ||
752 | */ | ||
753 | if (ui__has_annotation()) | ||
754 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
755 | |||
756 | hists__inc_nr_samples(&evsel->hists, he->filtered); | 724 | hists__inc_nr_samples(&evsel->hists, he->filtered); |
757 | 725 | ||
758 | return err; | 726 | return err; |
@@ -802,8 +770,11 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
802 | * It's possible that it has cycles or recursive calls. | 770 | * It's possible that it has cycles or recursive calls. |
803 | */ | 771 | */ |
804 | for (i = 0; i < iter->curr; i++) { | 772 | for (i = 0; i < iter->curr; i++) { |
805 | if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) | 773 | if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) { |
774 | /* to avoid calling callback function */ | ||
775 | iter->he = NULL; | ||
806 | return 0; | 776 | return 0; |
777 | } | ||
807 | } | 778 | } |
808 | 779 | ||
809 | he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, | 780 | he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, |
@@ -863,7 +834,7 @@ const struct hist_iter_ops hist_iter_cumulative = { | |||
863 | 834 | ||
864 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 835 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
865 | struct perf_evsel *evsel, struct perf_sample *sample, | 836 | struct perf_evsel *evsel, struct perf_sample *sample, |
866 | int max_stack_depth) | 837 | int max_stack_depth, void *arg) |
867 | { | 838 | { |
868 | int err, err2; | 839 | int err, err2; |
869 | 840 | ||
@@ -883,10 +854,22 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | |||
883 | if (err) | 854 | if (err) |
884 | goto out; | 855 | goto out; |
885 | 856 | ||
857 | if (iter->he && iter->add_entry_cb) { | ||
858 | err = iter->add_entry_cb(iter, al, true, arg); | ||
859 | if (err) | ||
860 | goto out; | ||
861 | } | ||
862 | |||
886 | while (iter->ops->next_entry(iter, al)) { | 863 | while (iter->ops->next_entry(iter, al)) { |
887 | err = iter->ops->add_next_entry(iter, al); | 864 | err = iter->ops->add_next_entry(iter, al); |
888 | if (err) | 865 | if (err) |
889 | break; | 866 | break; |
867 | |||
868 | if (iter->he && iter->add_entry_cb) { | ||
869 | err = iter->add_entry_cb(iter, al, false, arg); | ||
870 | if (err) | ||
871 | goto out; | ||
872 | } | ||
890 | } | 873 | } |
891 | 874 | ||
892 | out: | 875 | out: |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 99ad3cb433fb..82b28ff98062 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -119,6 +119,9 @@ struct hist_entry_iter { | |||
119 | void *priv; | 119 | void *priv; |
120 | 120 | ||
121 | const struct hist_iter_ops *ops; | 121 | const struct hist_iter_ops *ops; |
122 | /* user-defined callback function (optional) */ | ||
123 | int (*add_entry_cb)(struct hist_entry_iter *iter, | ||
124 | struct addr_location *al, bool single, void *arg); | ||
122 | }; | 125 | }; |
123 | 126 | ||
124 | extern const struct hist_iter_ops hist_iter_normal; | 127 | extern const struct hist_iter_ops hist_iter_normal; |
@@ -135,7 +138,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
135 | bool sample_self); | 138 | bool sample_self); |
136 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 139 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
137 | struct perf_evsel *evsel, struct perf_sample *sample, | 140 | struct perf_evsel *evsel, struct perf_sample *sample, |
138 | int max_stack_depth); | 141 | int max_stack_depth, void *arg); |
139 | 142 | ||
140 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); | 143 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); |
141 | int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); | 144 | int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); |