perf tools: Skip elided sort entries
[deliverable/linux.git] / tools / perf / util / hist.c
index f38590d7561b99733c5c32154eb1dee8c9777572..b262b44b7a656d8dca4fcab7488e43e3c49ebb8c 100644 (file)
@@ -225,14 +225,18 @@ static void he_stat__decay(struct he_stat *he_stat)
 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 {
        u64 prev_period = he->stat.period;
+       u64 diff;
 
        if (prev_period == 0)
                return true;
 
        he_stat__decay(&he->stat);
 
+       diff = prev_period - he->stat.period;
+
+       hists->stats.total_period -= diff;
        if (!he->filtered)
-               hists->stats.total_period -= prev_period - he->stat.period;
+               hists->stats.total_non_filtered_period -= diff;
 
        return he->stat.period == 0;
 }
@@ -259,8 +263,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
                        if (sort__need_collapse)
                                rb_erase(&n->rb_node_in, &hists->entries_collapsed);
 
-                       hist_entry__free(n);
                        --hists->nr_entries;
+                       if (!n->filtered)
+                               --hists->nr_non_filtered_entries;
+
+                       hist_entry__free(n);
                }
        }
 }
@@ -317,15 +324,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
        return he;
 }
 
-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;
-       }
-}
-
 static u8 symbol__parent_filter(const struct symbol *parent)
 {
        if (symbol_conf.exclude_other && parent == NULL)
@@ -391,7 +389,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
        if (!he)
                return NULL;
 
-       hists->nr_entries++;
        rb_link_node(&he->rb_node_in, parent, p);
        rb_insert_color(&he->rb_node_in, hists->entries_in);
 out:
@@ -435,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
 int64_t
 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
 {
-       struct sort_entry *se;
+       struct perf_hpp_fmt *fmt;
        int64_t cmp = 0;
 
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               cmp = se->se_cmp(left, right);
+       perf_hpp__for_each_sort_list(fmt) {
+               if (perf_hpp__should_skip(fmt))
+                       continue;
+
+               cmp = fmt->cmp(left, right);
                if (cmp)
                        break;
        }
@@ -450,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
 int64_t
 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
 {
-       struct sort_entry *se;
+       struct perf_hpp_fmt *fmt;
        int64_t cmp = 0;
 
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
-               f = se->se_collapse ?: se->se_cmp;
+       perf_hpp__for_each_sort_list(fmt) {
+               if (perf_hpp__should_skip(fmt))
+                       continue;
 
-               cmp = f(left, right);
+               cmp = fmt->collapse(left, right);
                if (cmp)
                        break;
        }
@@ -571,64 +570,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
        }
 }
 
-/*
- * reverse the map, sort on period.
- */
-
-static int period_cmp(u64 period_a, u64 period_b)
+static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
 {
-       if (period_a > period_b)
-               return 1;
-       if (period_a < period_b)
-               return -1;
-       return 0;
-}
-
-static int hist_entry__sort_on_period(struct hist_entry *a,
-                                     struct hist_entry *b)
-{
-       int ret;
-       int i, nr_members;
-       struct perf_evsel *evsel;
-       struct hist_entry *pair;
-       u64 *periods_a, *periods_b;
+       struct perf_hpp_fmt *fmt;
+       int64_t cmp = 0;
 
-       ret = period_cmp(a->stat.period, b->stat.period);
-       if (ret || !symbol_conf.event_group)
-               return ret;
+       perf_hpp__for_each_sort_list(fmt) {
+               if (perf_hpp__should_skip(fmt))
+                       continue;
 
-       evsel = hists_to_evsel(a->hists);
-       nr_members = evsel->nr_members;
-       if (nr_members <= 1)
-               return ret;
+               cmp = fmt->sort(a, b);
+               if (cmp)
+                       break;
+       }
 
-       periods_a = zalloc(sizeof(periods_a) * nr_members);
-       periods_b = zalloc(sizeof(periods_b) * nr_members);
+       return cmp;
+}
 
-       if (!periods_a || !periods_b)
-               goto out;
+static void hists__reset_filter_stats(struct hists *hists)
+{
+       hists->nr_non_filtered_entries = 0;
+       hists->stats.total_non_filtered_period = 0;
+}
 
-       list_for_each_entry(pair, &a->pairs.head, pairs.node) {
-               evsel = hists_to_evsel(pair->hists);
-               periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
-       }
+void hists__reset_stats(struct hists *hists)
+{
+       hists->nr_entries = 0;
+       hists->stats.total_period = 0;
 
-       list_for_each_entry(pair, &b->pairs.head, pairs.node) {
-               evsel = hists_to_evsel(pair->hists);
-               periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
-       }
+       hists__reset_filter_stats(hists);
+}
 
-       for (i = 1; i < nr_members; i++) {
-               ret = period_cmp(periods_a[i], periods_b[i]);
-               if (ret)
-                       break;
-       }
+static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
+{
+       hists->nr_non_filtered_entries++;
+       hists->stats.total_non_filtered_period += h->stat.period;
+}
 
-out:
-       free(periods_a);
-       free(periods_b);
+void hists__inc_stats(struct hists *hists, struct hist_entry *h)
+{
+       if (!h->filtered)
+               hists__inc_filter_stats(hists, h);
 
-       return ret;
+       hists->nr_entries++;
+       hists->stats.total_period += h->stat.period;
 }
 
 static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node);
 
-               if (hist_entry__sort_on_period(he, iter) > 0)
+               if (hist_entry__sort(he, iter) > 0)
                        p = &(*p)->rb_left;
                else
                        p = &(*p)->rb_right;
@@ -674,8 +659,7 @@ void hists__output_resort(struct hists *hists)
        next = rb_first(root);
        hists->entries = RB_ROOT;
 
-       hists->nr_entries = 0;
-       hists->stats.total_period = 0;
+       hists__reset_stats(hists);
        hists__reset_col_len(hists);
 
        while (next) {
@@ -683,7 +667,10 @@ void hists__output_resort(struct hists *hists)
                next = rb_next(&n->rb_node_in);
 
                __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
-               hists__inc_nr_entries(hists, n);
+               hists__inc_stats(hists, n);
+
+               if (!n->filtered)
+                       hists__calc_col_len(hists, n);
        }
 }
 
@@ -694,13 +681,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
        if (h->filtered)
                return;
 
-       ++hists->nr_entries;
-       if (h->ms.unfolded)
-               hists->nr_entries += h->nr_rows;
+       /* force fold unfiltered entry for simplicity */
+       h->ms.unfolded = false;
        h->row_offset = 0;
-       hists->stats.total_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__inc_filter_stats(hists, h);
        hists__calc_col_len(hists, h);
 }
 
@@ -721,8 +708,9 @@ void hists__filter_by_dso(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->stats.nr_non_filtered_samples = 0;
+
+       hists__reset_filter_stats(hists);
        hists__reset_col_len(hists);
 
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +742,9 @@ void hists__filter_by_thread(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->stats.nr_non_filtered_samples = 0;
+
+       hists__reset_filter_stats(hists);
        hists__reset_col_len(hists);
 
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +774,9 @@ void hists__filter_by_symbol(struct hists *hists)
 {
        struct rb_node *nd;
 
-       hists->nr_entries = hists->stats.total_period = 0;
-       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists->stats.nr_non_filtered_samples = 0;
+
+       hists__reset_filter_stats(hists);
        hists__reset_col_len(hists);
 
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -847,7 +837,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
                he->hists = hists;
                rb_link_node(&he->rb_node_in, parent, p);
                rb_insert_color(&he->rb_node_in, root);
-               hists__inc_nr_entries(hists, he);
+               hists__inc_stats(hists, he);
                he->dummy = true;
        }
 out:
@@ -931,3 +921,30 @@ 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;
+}
+
+int parse_filter_percentage(const struct option *opt __maybe_unused,
+                           const char *arg, int unset __maybe_unused)
+{
+       if (!strcmp(arg, "relative"))
+               symbol_conf.filter_relative = true;
+       else if (!strcmp(arg, "absolute"))
+               symbol_conf.filter_relative = false;
+       else
+               return -1;
+
+       return 0;
+}
+
+int perf_hist_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "hist.percentage"))
+               return parse_filter_percentage(NULL, value, 0);
+
+       return 0;
+}
This page took 0.028637 seconds and 5 git commands to generate.