perf report: Add --percentage option
authorNamhyung Kim <namhyung@kernel.org>
Tue, 14 Jan 2014 02:52:48 +0000 (11:52 +0900)
committerJiri Olsa <jolsa@redhat.com>
Wed, 16 Apr 2014 15:16:03 +0000 (17:16 +0200)
The --percentage option is for controlling overhead percentage
displayed.  It can only receive either of "relative" or "absolute".

"relative" means it's relative to filtered entries only so that the
sum of shown entries will be always 100%.  "absolute" means it retains
the original value before and after the filter is applied.

  $ perf report -s comm
  # Overhead       Command
  # ........  ............
  #
      74.19%           cc1
       7.61%           gcc
       6.11%            as
       4.35%            sh
       4.14%          make
       1.13%        fixdep
  ...

  $ perf report -s comm -c cc1,gcc --percentage absolute
  # Overhead       Command
  # ........  ............
  #
      74.19%           cc1
       7.61%           gcc

  $ perf report -s comm -c cc1,gcc --percentage relative
  # Overhead       Command
  # ........  ............
  #
      90.69%           cc1
       9.31%           gcc

Note that it has zero effect if no filter was applied.

Suggested-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1397145720-8063-3-git-send-email-namhyung@kernel.org
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
tools/perf/Documentation/perf-report.txt
tools/perf/builtin-report.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h

index 8eab8a4bdeb8bea5f712b4fe918d65acbce5e19c..09af66298564113643ef5db11540ef7e6c8652fd 100644 (file)
@@ -25,10 +25,6 @@ OPTIONS
 --verbose::
         Be more verbose. (show symbol address, etc)
 
--d::
---dsos=::
-       Only consider symbols in these dsos. CSV that understands
-       file://filename entries.
 -n::
 --show-nr-samples::
        Show the number of samples for each symbol
@@ -42,11 +38,18 @@ OPTIONS
 -c::
 --comms=::
        Only consider symbols in these comms. CSV that understands
-       file://filename entries.
+       file://filename entries.  This option will affect the percentage of
+       the overhead column.  See --percentage for more info.
+-d::
+--dsos=::
+       Only consider symbols in these dsos. CSV that understands
+       file://filename entries.  This option will affect the percentage of
+       the overhead column.  See --percentage for more info.
 -S::
 --symbols=::
        Only consider these symbols. CSV that understands
-       file://filename entries.
+       file://filename entries.  This option will affect the percentage of
+       the overhead column.  See --percentage for more info.
 
 --symbol-filter=::
        Only show symbols that match (partially) with this filter.
@@ -237,6 +240,15 @@ OPTIONS
        Do not show entries which have an overhead under that percent.
        (Default: 0).
 
+--percentage::
+       Determine how to display the overhead percentage of filtered entries.
+       Filters can be applied by --comms, --dsos and/or --symbols options and
+       Zoom operations on the TUI (thread, dso, etc).
+
+       "relative" means it's relative to filtered entries only so that the
+       sum of shown entries will be always 100%.  "absolute" means it retains
+       the original value before and after the filter is applied.
+
 --header::
        Show header information in the perf.data file.  This includes
        various information like hostname, OS and perf version, cpu/mem
index 2fca56c9d68a08639a94c25ab8cb0017f1e5363e..7ec351bda8331e0e03f3992d137b0205b7f81dcc 100644 (file)
@@ -343,6 +343,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
        char buf[512];
        size_t size = sizeof(buf);
 
+       if (symbol_conf.filter_relative) {
+               nr_samples = hists->stats.nr_non_filtered_samples;
+               nr_events = hists->stats.total_non_filtered_period;
+       }
+
        if (perf_evsel__is_group_event(evsel)) {
                struct perf_evsel *pos;
 
@@ -350,8 +355,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
                evname = buf;
 
                for_each_group_member(pos, evsel) {
-                       nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-                       nr_events += pos->hists.stats.total_period;
+                       if (symbol_conf.filter_relative) {
+                               nr_samples += pos->hists.stats.nr_non_filtered_samples;
+                               nr_events += pos->hists.stats.total_non_filtered_period;
+                       } else {
+                               nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+                               nr_events += pos->hists.stats.total_period;
+                       }
                }
        }
 
@@ -707,6 +717,20 @@ parse_percent_limit(const struct option *opt, const char *str,
        return 0;
 }
 
+static int
+parse_percentage(const struct option *opt __maybe_unused, const char *str,
+                int unset __maybe_unused)
+{
+       if (!strcmp(str, "relative"))
+               symbol_conf.filter_relative = true;
+       else if (!strcmp(str, "absolute"))
+               symbol_conf.filter_relative = false;
+       else
+               return -1;
+
+       return 0;
+}
+
 int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        struct perf_session *session;
@@ -829,6 +853,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
        OPT_CALLBACK(0, "percent-limit", &report, "percent",
                     "Don't show entries under that percent", parse_percent_limit),
+       OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
+                    "how to display percentage of filtered entries", parse_percentage),
        OPT_END()
        };
        struct perf_data_file file = {
index 7ec871af3f6f8c5cc4796f40c14c801aa3ba3943..7ad11477a0f5b3b78d815350219c84a36853078d 100644 (file)
@@ -769,12 +769,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
 
        for (nd = browser->top; nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               float percent = h->stat.period * 100.0 /
-                                       hb->hists->stats.total_period;
+               u64 total = hists__total_period(h->hists);
+               float percent = 0.0;
 
                if (h->filtered)
                        continue;
 
+               if (total)
+                       percent = h->stat.period * 100.0 / total;
+
                if (percent < hb->min_pcnt)
                        continue;
 
@@ -792,8 +795,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
 {
        while (nd != NULL) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               float percent = h->stat.period * 100.0 /
-                                       hists->stats.total_period;
+               u64 total = hists__total_period(hists);
+               float percent = 0.0;
+
+               if (total)
+                       percent = h->stat.period * 100.0 / total;
 
                if (percent < min_pcnt)
                        return NULL;
@@ -813,8 +819,11 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
 {
        while (nd != NULL) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               float percent = h->stat.period * 100.0 /
-                                       hists->stats.total_period;
+               u64 total = hists__total_period(hists);
+               float percent = 0.0;
+
+               if (total)
+                       percent = h->stat.period * 100.0 / total;
 
                if (!h->filtered && percent >= min_pcnt)
                        return nd;
@@ -1189,6 +1198,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
        char buf[512];
        size_t buflen = sizeof(buf);
 
+       if (symbol_conf.filter_relative) {
+               nr_samples = hists->stats.nr_non_filtered_samples;
+               nr_events = hists->stats.total_non_filtered_period;
+       }
+
        if (perf_evsel__is_group_event(evsel)) {
                struct perf_evsel *pos;
 
@@ -1196,8 +1210,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
                ev_name = buf;
 
                for_each_group_member(pos, evsel) {
-                       nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-                       nr_events += pos->hists.stats.total_period;
+                       if (symbol_conf.filter_relative) {
+                               nr_samples += pos->hists.stats.nr_non_filtered_samples;
+                               nr_events += pos->hists.stats.total_non_filtered_period;
+                       } else {
+                               nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+                               nr_events += pos->hists.stats.total_period;
+                       }
                }
        }
 
index e395ef9b0ae00494187c089fde8c6b6a7a5259c4..91f10f3f6dd16cd003e42a84e797541fa8d11d84 100644 (file)
@@ -228,12 +228,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
                GtkTreeIter iter;
-               float percent = h->stat.period * 100.0 /
-                                       hists->stats.total_period;
+               u64 total = hists__total_period(h->hists);
+               float percent = 0.0;
 
                if (h->filtered)
                        continue;
 
+               if (total)
+                       percent = h->stat.period * 100.0 / total;
+
                if (percent < min_pcnt)
                        continue;
 
@@ -261,12 +264,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                }
 
                if (symbol_conf.use_callchain && sort__has_sym) {
-                       u64 total;
-
                        if (callchain_param.mode == CHAIN_GRAPH_REL)
                                total = h->stat.period;
-                       else
-                               total = hists->stats.total_period;
 
                        perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
                                                sym_col, total);
index 0f403b83e9d1c1da19b7be850c7c49ffba0b074d..0912805c08f4d1ec4913a57d66eec7e4379891fb 100644 (file)
@@ -32,10 +32,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
 
        if (fmt_percent) {
                double percent = 0.0;
+               u64 total = hists__total_period(hists);
 
-               if (hists->stats.total_period)
-                       percent = 100.0 * get_field(he) /
-                                 hists->stats.total_period;
+               if (total)
+                       percent = 100.0 * get_field(he) / total;
 
                ret += hpp__call_print_fn(hpp, print_fn, fmt, percent);
        } else
@@ -50,7 +50,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
 
                list_for_each_entry(pair, &he->pairs.head, pairs.node) {
                        u64 period = get_field(pair);
-                       u64 total = pair->hists->stats.total_period;
+                       u64 total = hists__total_period(pair->hists);
 
                        if (!total)
                                continue;
index 1ed3e2b86f0bd6bd2d646f1e9132b2e0f847ba1e..3ebd89a282576a42104fbab071200b51b4bbb8fd 100644 (file)
@@ -321,9 +321,11 @@ void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
 {
        if (!h->filtered) {
                hists__calc_col_len(hists, h);
-               ++hists->nr_entries;
-               hists->stats.total_period += h->stat.period;
+               hists->nr_non_filtered_entries++;
+               hists->stats.total_non_filtered_period += h->stat.period;
        }
+       hists->nr_entries++;
+       hists->stats.total_period += h->stat.period;
 }
 
 static u8 symbol__parent_filter(const struct symbol *parent)
@@ -674,8 +676,9 @@ void hists__output_resort(struct hists *hists)
        next = rb_first(root);
        hists->entries = RB_ROOT;
 
-       hists->nr_entries = hists->nr_non_filtered_entries = 0;
-       hists->stats.total_period = hists->stats.total_non_filtered_period = 0;
+       hists->nr_non_filtered_entries = 0;
+       hists->stats.total_period = 0;
+       hists->stats.total_non_filtered_period = 0;
        hists__reset_col_len(hists);
 
        while (next) {
@@ -694,16 +697,11 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
        if (h->filtered)
                return;
 
-       ++hists->nr_entries;
        ++hists->nr_non_filtered_entries;
-       if (h->ms.unfolded) {
-               hists->nr_entries += h->nr_rows;
+       if (h->ms.unfolded)
                hists->nr_non_filtered_entries += h->nr_rows;
-       }
        h->row_offset = 0;
-       hists->stats.total_period += h->stat.period;
        hists->stats.total_non_filtered_period += h->stat.period;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
        hists->stats.nr_non_filtered_samples += h->stat.nr_events;
 
        hists__calc_col_len(hists, h);
@@ -726,9 +724,8 @@ void hists__filter_by_dso(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->nr_non_filtered_entries = hists->stats.total_non_filtered_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->nr_non_filtered_entries = 0;
+       hists->stats.total_non_filtered_period = 0;
        hists->stats.nr_non_filtered_samples = 0;
        hists__reset_col_len(hists);
 
@@ -761,9 +758,8 @@ void hists__filter_by_thread(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->nr_non_filtered_entries = hists->stats.total_non_filtered_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->nr_non_filtered_entries = 0;
+       hists->stats.total_non_filtered_period = 0;
        hists->stats.nr_non_filtered_samples = 0;
        hists__reset_col_len(hists);
 
@@ -794,9 +790,8 @@ void hists__filter_by_symbol(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->nr_non_filtered_entries = hists->stats.total_non_filtered_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->nr_non_filtered_entries = 0;
+       hists->stats.total_non_filtered_period = 0;
        hists->stats.nr_non_filtered_samples = 0;
        hists__reset_col_len(hists);
 
@@ -942,3 +937,9 @@ int hists__link(struct hists *leader, struct hists *other)
 
        return 0;
 }
+
+u64 hists__total_period(struct hists *hists)
+{
+       return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
+               hists->stats.total_period;
+}
index 213551469f366ef78649916c8b24410f10d4c0f6..3191496bd3b75aaa71ec1cd9555dcf6ebc140b0f 100644 (file)
@@ -115,6 +115,7 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
+u64 hists__total_period(struct hists *hists);
 void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
 void hists__inc_nr_events(struct hists *hists, u32 type);
 void events_stats__inc(struct events_stats *stats, u32 type);
index 95e249779931216f5cbeb5b09c26ea0655a0fcf7..b2eca6c17a70b27c6dd19b5f6a3c358096a3853d 100644 (file)
@@ -33,6 +33,7 @@ struct symbol_conf symbol_conf = {
        .try_vmlinux_path = true,
        .annotate_src     = true,
        .demangle         = true,
+       .filter_relative  = true,
        .symfs            = "",
 };
 
index 501e4e722e8e853258e3e06b8448cc5792005971..ae94e006a52dd09ee1a3a871bbcd49afa2147558 100644 (file)
@@ -115,7 +115,8 @@ struct symbol_conf {
                        annotate_asm_raw,
                        annotate_src,
                        event_group,
-                       demangle;
+                       demangle,
+                       filter_relative;
        const char      *vmlinux_name,
                        *kallsyms_name,
                        *source_prefix,