perf hists: Use own hpp_list for hierarchy mode
[deliverable/linux.git] / tools / perf / util / hist.c
index a44bf5ae6acbe1aa31e08001a9df07c5bbe947ea..29da9e0d8db90591e8c3c82798a5f06713dcd5d8 100644 (file)
@@ -248,6 +248,8 @@ static void he_stat__decay(struct he_stat *he_stat)
        /* XXX need decay for weight too? */
 }
 
+static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
+
 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 {
        u64 prev_period = he->stat.period;
@@ -263,21 +265,45 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 
        diff = prev_period - he->stat.period;
 
-       hists->stats.total_period -= diff;
-       if (!he->filtered)
-               hists->stats.total_non_filtered_period -= diff;
+       if (!he->depth) {
+               hists->stats.total_period -= diff;
+               if (!he->filtered)
+                       hists->stats.total_non_filtered_period -= diff;
+       }
+
+       if (!he->leaf) {
+               struct hist_entry *child;
+               struct rb_node *node = rb_first(&he->hroot_out);
+               while (node) {
+                       child = rb_entry(node, struct hist_entry, rb_node);
+                       node = rb_next(node);
+
+                       if (hists__decay_entry(hists, child))
+                               hists__delete_entry(hists, child);
+               }
+       }
 
        return he->stat.period == 0;
 }
 
 static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
 {
-       rb_erase(&he->rb_node, &hists->entries);
+       struct rb_root *root_in;
+       struct rb_root *root_out;
 
-       if (sort__need_collapse)
-               rb_erase(&he->rb_node_in, &hists->entries_collapsed);
-       else
-               rb_erase(&he->rb_node_in, hists->entries_in);
+       if (he->parent_he) {
+               root_in  = &he->parent_he->hroot_in;
+               root_out = &he->parent_he->hroot_out;
+       } else {
+               if (sort__need_collapse)
+                       root_in = &hists->entries_collapsed;
+               else
+                       root_in = hists->entries_in;
+               root_out = &hists->entries;
+       }
+
+       rb_erase(&he->rb_node_in, root_in);
+       rb_erase(&he->rb_node, root_out);
 
        --hists->nr_entries;
        if (!he->filtered)
@@ -976,6 +1002,10 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
        int64_t cmp = 0;
 
        hists__for_each_sort_list(hists, fmt) {
+               if (perf_hpp__is_dynamic_entry(fmt) &&
+                   !perf_hpp__defined_dynamic_entry(fmt, hists))
+                       continue;
+
                cmp = fmt->cmp(fmt, left, right);
                if (cmp)
                        break;
@@ -992,6 +1022,10 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
        int64_t cmp = 0;
 
        hists__for_each_sort_list(hists, fmt) {
+               if (perf_hpp__is_dynamic_entry(fmt) &&
+                   !perf_hpp__defined_dynamic_entry(fmt, hists))
+                       continue;
+
                cmp = fmt->collapse(fmt, left, right);
                if (cmp)
                        break;
@@ -1057,18 +1091,25 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
 static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
                                                 struct rb_root *root,
                                                 struct hist_entry *he,
-                                                struct perf_hpp_fmt *fmt)
+                                                struct perf_hpp_list *hpp_list)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter, *new;
+       struct perf_hpp_fmt *fmt;
        int64_t cmp;
 
        while (*p != NULL) {
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node_in);
 
-               cmp = fmt->collapse(fmt, iter, he);
+               cmp = 0;
+               perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
+                       cmp = fmt->collapse(fmt, iter, he);
+                       if (cmp)
+                               break;
+               }
+
                if (!cmp) {
                        he_stat__add_stat(&iter->stat, &he->stat);
                        return iter;
@@ -1087,24 +1128,26 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
        hists__apply_filters(hists, new);
        hists->nr_entries++;
 
-       /* save related format for output */
-       new->fmt = fmt;
+       /* save related format list for output */
+       new->hpp_list = hpp_list;
 
        /* some fields are now passed to 'new' */
-       if (perf_hpp__is_trace_entry(fmt))
-               he->trace_output = NULL;
-       else
-               new->trace_output = NULL;
+       perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
+               if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
+                       he->trace_output = NULL;
+               else
+                       new->trace_output = NULL;
 
-       if (perf_hpp__is_srcline_entry(fmt))
-               he->srcline = NULL;
-       else
-               new->srcline = NULL;
+               if (perf_hpp__is_srcline_entry(fmt))
+                       he->srcline = NULL;
+               else
+                       new->srcline = NULL;
 
-       if (perf_hpp__is_srcfile_entry(fmt))
-               he->srcfile = NULL;
-       else
-               new->srcfile = NULL;
+               if (perf_hpp__is_srcfile_entry(fmt))
+                       he->srcfile = NULL;
+               else
+                       new->srcfile = NULL;
+       }
 
        rb_link_node(&new->rb_node_in, parent, p);
        rb_insert_color(&new->rb_node_in, root);
@@ -1115,21 +1158,19 @@ static int hists__hierarchy_insert_entry(struct hists *hists,
                                         struct rb_root *root,
                                         struct hist_entry *he)
 {
-       struct perf_hpp_fmt *fmt;
+       struct perf_hpp_list_node *node;
        struct hist_entry *new_he = NULL;
        struct hist_entry *parent = NULL;
        int depth = 0;
        int ret = 0;
 
-       hists__for_each_sort_list(hists, fmt) {
-               if (!perf_hpp__is_sort_entry(fmt) &&
-                   !perf_hpp__is_dynamic_entry(fmt))
-                       continue;
-               if (perf_hpp__should_skip(fmt, hists))
+       list_for_each_entry(node, &hists->hpp_formats, list) {
+               /* skip period (overhead) and elided columns */
+               if (node->level == 0 || node->skip)
                        continue;
 
                /* insert copy of 'he' for each fmt into the hierarchy */
-               new_he = hierarchy_insert_entry(hists, root, he, fmt);
+               new_he = hierarchy_insert_entry(hists, root, he, &node->hpp);
                if (new_he == NULL) {
                        ret = -1;
                        break;
@@ -1324,6 +1365,7 @@ static void hierarchy_insert_output_entry(struct rb_root *root,
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
+       struct perf_hpp_fmt *fmt;
 
        while (*p != NULL) {
                parent = *p;
@@ -1337,6 +1379,12 @@ static void hierarchy_insert_output_entry(struct rb_root *root,
 
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, root);
+
+       /* update column width of dynamic entry */
+       perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
+               if (perf_hpp__is_dynamic_entry(fmt))
+                       fmt->sort(fmt, he, NULL);
+       }
 }
 
 static void hists__hierarchy_output_resort(struct hists *hists,
@@ -1406,6 +1454,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
        struct rb_node **p = &entries->rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
+       struct perf_hpp_fmt *fmt;
 
        if (use_callchain) {
                if (callchain_param.mode == CHAIN_GRAPH_REL) {
@@ -1432,6 +1481,12 @@ static void __hists__insert_output_entry(struct rb_root *entries,
 
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, entries);
+
+       perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
+               if (perf_hpp__is_dynamic_entry(fmt) &&
+                   perf_hpp__defined_dynamic_entry(fmt, he->hists))
+                       fmt->sort(fmt, he, NULL);  /* update column width */
+       }
 }
 
 static void output_resort(struct hists *hists, struct ui_progress *prog,
@@ -1556,6 +1611,31 @@ struct rb_node *rb_hierarchy_prev(struct rb_node *node)
        return &he->rb_node;
 }
 
+bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
+{
+       struct rb_node *node;
+       struct hist_entry *child;
+       float percent;
+
+       if (he->leaf)
+               return false;
+
+       node = rb_first(&he->hroot_out);
+       child = rb_entry(node, struct hist_entry, rb_node);
+
+       while (node && child->filtered) {
+               node = rb_next(node);
+               child = rb_entry(node, struct hist_entry, rb_node);
+       }
+
+       if (node)
+               percent = hist_entry__get_percent_limit(child);
+       else
+               percent = 0;
+
+       return node && percent >= limit;
+}
+
 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
                                       enum hist_filter filter)
 {
@@ -1574,6 +1654,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
 
                        /* force fold unfiltered entry for simplicity */
                        parent->unfolded = false;
+                       parent->has_no_entry = false;
                        parent->row_offset = 0;
                        parent->nr_rows = 0;
 next:
@@ -1586,6 +1667,7 @@ next:
 
        /* force fold unfiltered entry for simplicity */
        h->unfolded = false;
+       h->has_no_entry = false;
        h->row_offset = 0;
        h->nr_rows = 0;
 
@@ -2033,6 +2115,7 @@ int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
        pthread_mutex_init(&hists->lock, NULL);
        hists->socket_filter = -1;
        hists->hpp_list = hpp_list;
+       INIT_LIST_HEAD(&hists->hpp_formats);
        return 0;
 }
 
@@ -2061,8 +2144,19 @@ static void hists__delete_all_entries(struct hists *hists)
 static void hists_evsel__exit(struct perf_evsel *evsel)
 {
        struct hists *hists = evsel__hists(evsel);
+       struct perf_hpp_fmt *fmt, *pos;
+       struct perf_hpp_list_node *node, *tmp;
 
        hists__delete_all_entries(hists);
+
+       list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
+               perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
+                       list_del(&fmt->list);
+                       free(fmt);
+               }
+               list_del(&node->list);
+               free(node);
+       }
 }
 
 static int hists_evsel__init(struct perf_evsel *evsel)
This page took 0.030367 seconds and 5 git commands to generate.