diff options
author | Namhyung Kim <namhyung@kernel.org> | 2012-09-11 01:13:04 -0400 |
---|---|---|
committer | Jiri Olsa <jolsa@kernel.org> | 2014-06-01 08:34:57 -0400 |
commit | 7a13aa28aa268359cee006059731f49bcd1f839e (patch) | |
tree | d3748f0fa3e62fabf3f018cd2789076dc593f392 /tools | |
parent | a0b51af367a6831330564c96dc4cc1ac63413701 (diff) |
perf hists: Accumulate hist entry stat based on the callchain
Call __hists__add_entry() for each callchain node to get an
accumulated stat for an entry. Introduce new cumulative_iter ops to
process them properly.
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/1401335910-16832-6-git-send-email-namhyung@kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 3 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 96 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 1 |
4 files changed, 101 insertions, 1 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3201bdfa8c3f..e8fa9fea341f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -115,6 +115,8 @@ static int process_sample_event(struct perf_tool *tool, | |||
115 | iter.ops = &hist_iter_branch; | 115 | iter.ops = &hist_iter_branch; |
116 | else if (rep->mem_mode) | 116 | else if (rep->mem_mode) |
117 | iter.ops = &hist_iter_mem; | 117 | iter.ops = &hist_iter_mem; |
118 | else if (symbol_conf.cumulate_callchain) | ||
119 | iter.ops = &hist_iter_cumulative; | ||
118 | else | 120 | else |
119 | iter.ops = &hist_iter_normal; | 121 | iter.ops = &hist_iter_normal; |
120 | 122 | ||
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9a42382b3921..2af69c47b725 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent | |||
616 | if (sample->callchain == NULL) | 616 | if (sample->callchain == NULL) |
617 | return 0; | 617 | return 0; |
618 | 618 | ||
619 | if (symbol_conf.use_callchain || sort__has_parent) { | 619 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || |
620 | sort__has_parent) { | ||
620 | return machine__resolve_callchain(al->machine, evsel, al->thread, | 621 | return machine__resolve_callchain(al->machine, evsel, al->thread, |
621 | sample, parent, al, max_stack); | 622 | sample, parent, al, max_stack); |
622 | } | 623 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b9facf33b224..6079b5acfb6d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -696,6 +696,94 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) | |||
696 | return hist_entry__append_callchain(he, sample); | 696 | return hist_entry__append_callchain(he, sample); |
697 | } | 697 | } |
698 | 698 | ||
699 | static int | ||
700 | iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, | ||
701 | struct addr_location *al __maybe_unused) | ||
702 | { | ||
703 | callchain_cursor_commit(&callchain_cursor); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static int | ||
708 | iter_add_single_cumulative_entry(struct hist_entry_iter *iter, | ||
709 | struct addr_location *al) | ||
710 | { | ||
711 | struct perf_evsel *evsel = iter->evsel; | ||
712 | struct perf_sample *sample = iter->sample; | ||
713 | struct hist_entry *he; | ||
714 | int err = 0; | ||
715 | |||
716 | he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, | ||
717 | sample->period, sample->weight, | ||
718 | sample->transaction, true); | ||
719 | if (he == NULL) | ||
720 | return -ENOMEM; | ||
721 | |||
722 | iter->he = he; | ||
723 | |||
724 | /* | ||
725 | * The iter->he will be over-written after ->add_next_entry() | ||
726 | * called so inc stats for the original entry now. | ||
727 | */ | ||
728 | if (ui__has_annotation()) | ||
729 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
730 | |||
731 | hists__inc_nr_samples(&evsel->hists, he->filtered); | ||
732 | |||
733 | return err; | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | iter_next_cumulative_entry(struct hist_entry_iter *iter, | ||
738 | struct addr_location *al) | ||
739 | { | ||
740 | struct callchain_cursor_node *node; | ||
741 | |||
742 | node = callchain_cursor_current(&callchain_cursor); | ||
743 | if (node == NULL) | ||
744 | return 0; | ||
745 | |||
746 | al->map = node->map; | ||
747 | al->sym = node->sym; | ||
748 | if (node->map) | ||
749 | al->addr = node->map->map_ip(node->map, node->ip); | ||
750 | else | ||
751 | al->addr = node->ip; | ||
752 | |||
753 | if (iter->hide_unresolved && al->sym == NULL) | ||
754 | return 0; | ||
755 | |||
756 | callchain_cursor_advance(&callchain_cursor); | ||
757 | return 1; | ||
758 | } | ||
759 | |||
760 | static int | ||
761 | iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | ||
762 | struct addr_location *al) | ||
763 | { | ||
764 | struct perf_evsel *evsel = iter->evsel; | ||
765 | struct perf_sample *sample = iter->sample; | ||
766 | struct hist_entry *he; | ||
767 | |||
768 | he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, | ||
769 | sample->period, sample->weight, | ||
770 | sample->transaction, false); | ||
771 | if (he == NULL) | ||
772 | return -ENOMEM; | ||
773 | |||
774 | iter->he = he; | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int | ||
780 | iter_finish_cumulative_entry(struct hist_entry_iter *iter, | ||
781 | struct addr_location *al __maybe_unused) | ||
782 | { | ||
783 | iter->he = NULL; | ||
784 | return 0; | ||
785 | } | ||
786 | |||
699 | const struct hist_iter_ops hist_iter_mem = { | 787 | const struct hist_iter_ops hist_iter_mem = { |
700 | .prepare_entry = iter_prepare_mem_entry, | 788 | .prepare_entry = iter_prepare_mem_entry, |
701 | .add_single_entry = iter_add_single_mem_entry, | 789 | .add_single_entry = iter_add_single_mem_entry, |
@@ -720,6 +808,14 @@ const struct hist_iter_ops hist_iter_normal = { | |||
720 | .finish_entry = iter_finish_normal_entry, | 808 | .finish_entry = iter_finish_normal_entry, |
721 | }; | 809 | }; |
722 | 810 | ||
811 | const struct hist_iter_ops hist_iter_cumulative = { | ||
812 | .prepare_entry = iter_prepare_cumulative_entry, | ||
813 | .add_single_entry = iter_add_single_cumulative_entry, | ||
814 | .next_entry = iter_next_cumulative_entry, | ||
815 | .add_next_entry = iter_add_next_cumulative_entry, | ||
816 | .finish_entry = iter_finish_cumulative_entry, | ||
817 | }; | ||
818 | |||
723 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 819 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
724 | struct perf_evsel *evsel, struct perf_sample *sample, | 820 | struct perf_evsel *evsel, struct perf_sample *sample, |
725 | int max_stack_depth) | 821 | int max_stack_depth) |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index bedb24d3643c..78409f95d012 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -124,6 +124,7 @@ struct hist_entry_iter { | |||
124 | extern const struct hist_iter_ops hist_iter_normal; | 124 | extern const struct hist_iter_ops hist_iter_normal; |
125 | extern const struct hist_iter_ops hist_iter_branch; | 125 | extern const struct hist_iter_ops hist_iter_branch; |
126 | extern const struct hist_iter_ops hist_iter_mem; | 126 | extern const struct hist_iter_ops hist_iter_mem; |
127 | extern const struct hist_iter_ops hist_iter_cumulative; | ||
127 | 128 | ||
128 | struct hist_entry *__hists__add_entry(struct hists *hists, | 129 | struct hist_entry *__hists__add_entry(struct hists *hists, |
129 | struct addr_location *al, | 130 | struct addr_location *al, |