aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung@kernel.org>2014-01-07 03:02:25 -0500
committerJiri Olsa <jolsa@kernel.org>2014-06-01 08:35:05 -0400
commit9d3c02d7188866299eebe3c4a652c08140a71f40 (patch)
tree1a45d4db4976bb33a0f315d24f6fa7f70aef1c66 /tools
parent2bf1a12340bda1bf621f27b9892094a51b1297fd (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.c61
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/util/hist.c67
-rw-r--r--tools/perf/util/hist.h5
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
83static void report__inc_stats(struct report *rep, 83static 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
94static 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
134out:
135 return err;
91} 136}
92 137
93static int process_sample_event(struct perf_tool *tool, 138static 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
519static int 519static int
520iter_finish_mem_entry(struct hist_entry_iter *iter, struct addr_location *al) 520iter_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
575iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused, 564iter_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)
599static int 591static int
600iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) 592iter_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
635out: 616out:
@@ -673,9 +654,9 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
673} 654}
674 655
675static int 656static int
676iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) 657iter_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
864int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 835int 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
892out: 875out:
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
124extern const struct hist_iter_ops hist_iter_normal; 127extern 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);
136int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 139int 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
140int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 143int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
141int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);