perf hists: Accumulate hist entry stat based on the callchain
authorNamhyung Kim <namhyung@kernel.org>
Tue, 11 Sep 2012 05:13:04 +0000 (14:13 +0900)
committerJiri Olsa <jolsa@kernel.org>
Sun, 1 Jun 2014 12:34:57 +0000 (14:34 +0200)
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>
tools/perf/builtin-report.c
tools/perf/util/callchain.c
tools/perf/util/hist.c
tools/perf/util/hist.h

index 3201bdfa8c3f2b721390652d9afc75042e1d5d2e..e8fa9fea341f273bea00688182cb92569aac54b7 100644 (file)
@@ -115,6 +115,8 @@ static int process_sample_event(struct perf_tool *tool,
                iter.ops = &hist_iter_branch;
        else if (rep->mem_mode)
                iter.ops = &hist_iter_mem;
+       else if (symbol_conf.cumulate_callchain)
+               iter.ops = &hist_iter_cumulative;
        else
                iter.ops = &hist_iter_normal;
 
index 9a42382b3921a76a531d97481a32df2e8f29542f..2af69c47b7255733cc266f692ec65f2fb59bb7ea 100644 (file)
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
        if (sample->callchain == NULL)
                return 0;
 
-       if (symbol_conf.use_callchain || sort__has_parent) {
+       if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
+           sort__has_parent) {
                return machine__resolve_callchain(al->machine, evsel, al->thread,
                                                  sample, parent, al, max_stack);
        }
index b9facf33b2244815456b53d508749c6140447e11..6079b5acfb6db74d66975ede08e305d4e4f9beae 100644 (file)
@@ -696,6 +696,94 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
        return hist_entry__append_callchain(he, sample);
 }
 
+static int
+iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
+                             struct addr_location *al __maybe_unused)
+{
+       callchain_cursor_commit(&callchain_cursor);
+       return 0;
+}
+
+static int
+iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
+                                struct addr_location *al)
+{
+       struct perf_evsel *evsel = iter->evsel;
+       struct perf_sample *sample = iter->sample;
+       struct hist_entry *he;
+       int err = 0;
+
+       he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
+                               sample->period, sample->weight,
+                               sample->transaction, true);
+       if (he == NULL)
+               return -ENOMEM;
+
+       iter->he = he;
+
+       /*
+        * The iter->he will be over-written after ->add_next_entry()
+        * called so inc stats for the original entry now.
+        */
+       if (ui__has_annotation())
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+
+       hists__inc_nr_samples(&evsel->hists, he->filtered);
+
+       return err;
+}
+
+static int
+iter_next_cumulative_entry(struct hist_entry_iter *iter,
+                          struct addr_location *al)
+{
+       struct callchain_cursor_node *node;
+
+       node = callchain_cursor_current(&callchain_cursor);
+       if (node == NULL)
+               return 0;
+
+       al->map = node->map;
+       al->sym = node->sym;
+       if (node->map)
+               al->addr = node->map->map_ip(node->map, node->ip);
+       else
+               al->addr = node->ip;
+
+       if (iter->hide_unresolved && al->sym == NULL)
+               return 0;
+
+       callchain_cursor_advance(&callchain_cursor);
+       return 1;
+}
+
+static int
+iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
+                              struct addr_location *al)
+{
+       struct perf_evsel *evsel = iter->evsel;
+       struct perf_sample *sample = iter->sample;
+       struct hist_entry *he;
+
+       he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
+                               sample->period, sample->weight,
+                               sample->transaction, false);
+       if (he == NULL)
+               return -ENOMEM;
+
+       iter->he = he;
+
+       return 0;
+}
+
+static int
+iter_finish_cumulative_entry(struct hist_entry_iter *iter,
+                            struct addr_location *al __maybe_unused)
+{
+       iter->he = NULL;
+       return 0;
+}
+
 const struct hist_iter_ops hist_iter_mem = {
        .prepare_entry          = iter_prepare_mem_entry,
        .add_single_entry       = iter_add_single_mem_entry,
@@ -720,6 +808,14 @@ const struct hist_iter_ops hist_iter_normal = {
        .finish_entry           = iter_finish_normal_entry,
 };
 
+const struct hist_iter_ops hist_iter_cumulative = {
+       .prepare_entry          = iter_prepare_cumulative_entry,
+       .add_single_entry       = iter_add_single_cumulative_entry,
+       .next_entry             = iter_next_cumulative_entry,
+       .add_next_entry         = iter_add_next_cumulative_entry,
+       .finish_entry           = iter_finish_cumulative_entry,
+};
+
 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
                         struct perf_evsel *evsel, struct perf_sample *sample,
                         int max_stack_depth)
index bedb24d3643c5d0ca4a8787c70e2a261d7b1b542..78409f95d012403c7bc2dfaf2b2b2867ebb864ee 100644 (file)
@@ -124,6 +124,7 @@ struct hist_entry_iter {
 extern const struct hist_iter_ops hist_iter_normal;
 extern const struct hist_iter_ops hist_iter_branch;
 extern const struct hist_iter_ops hist_iter_mem;
+extern const struct hist_iter_ops hist_iter_cumulative;
 
 struct hist_entry *__hists__add_entry(struct hists *hists,
                                      struct addr_location *al,