perf tools: callchain: Fix spurious 'perf report' warnings: ignore empty callchains
[safe/jmp/linux-2.6] / tools / perf / util / callchain.c
index c9900fe..a8e67aa 100644 (file)
@@ -26,20 +26,25 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct callchain_node *rnode;
+       u64 chain_cumul = cumul_hits(chain);
 
        while (*p) {
+               u64 rnode_cumul;
+
                parent = *p;
                rnode = rb_entry(parent, struct callchain_node, rb_node);
+               rnode_cumul = cumul_hits(rnode);
 
                switch (mode) {
-               case FLAT:
+               case CHAIN_FLAT:
                        if (rnode->hit < chain->hit)
                                p = &(*p)->rb_left;
                        else
                                p = &(*p)->rb_right;
                        break;
-               case GRAPH:
-                       if (rnode->cumul_hit < chain->cumul_hit)
+               case CHAIN_GRAPH_ABS: /* Falldown */
+               case CHAIN_GRAPH_REL:
+                       if (rnode_cumul < chain_cumul)
                                p = &(*p)->rb_left;
                        else
                                p = &(*p)->rb_right;
@@ -53,45 +58,96 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
        rb_insert_color(&chain->rb_node, root);
 }
 
+static void
+__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+                 u64 min_hit)
+{
+       struct callchain_node *child;
+
+       chain_for_each_child(child, node)
+               __sort_chain_flat(rb_root, child, min_hit);
+
+       if (node->hit && node->hit >= min_hit)
+               rb_insert_callchain(rb_root, node, CHAIN_FLAT);
+}
+
 /*
  * Once we get every callchains from the stream, we can now
  * sort them by hit
  */
-void sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
-                    u64 min_hit)
+static void
+sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+               u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_flat(rb_root, node, min_hit);
+}
+
+static void __sort_chain_graph_abs(struct callchain_node *node,
+                                  u64 min_hit)
 {
        struct callchain_node *child;
 
-       chain_for_each_child(child, node)
-               sort_chain_flat(rb_root, child, min_hit);
+       node->rb_root = RB_ROOT;
 
-       if (node->hit && node->hit >= min_hit)
-               rb_insert_callchain(rb_root, node, FLAT);
+       chain_for_each_child(child, node) {
+               __sort_chain_graph_abs(child, min_hit);
+               if (cumul_hits(child) >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_ABS);
+       }
+}
+
+static void
+sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit, struct callchain_param *param __used)
+{
+       __sort_chain_graph_abs(chain_root, min_hit);
+       rb_root->rb_node = chain_root->rb_root.rb_node;
 }
 
-static void __sort_chain_graph(struct callchain_node *node, u64 min_hit)
+static void __sort_chain_graph_rel(struct callchain_node *node,
+                                  double min_percent)
 {
        struct callchain_node *child;
+       u64 min_hit;
 
        node->rb_root = RB_ROOT;
-       node->cumul_hit = node->hit;
+       min_hit = node->children_hit * min_percent / 100.0;
 
        chain_for_each_child(child, node) {
-               __sort_chain_graph(child, min_hit);
-               if (child->cumul_hit >= min_hit)
-                       rb_insert_callchain(&node->rb_root, child, GRAPH);
-               node->cumul_hit += child->cumul_hit;
+               __sort_chain_graph_rel(child, min_percent);
+               if (cumul_hits(child) >= min_hit)
+                       rb_insert_callchain(&node->rb_root, child,
+                                           CHAIN_GRAPH_REL);
        }
 }
 
-void
-sort_chain_graph(struct rb_root *rb_root, struct callchain_node *chain_root,
-                u64 min_hit)
+static void
+sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
+                    u64 min_hit __used, struct callchain_param *param)
 {
-       __sort_chain_graph(chain_root, min_hit);
+       __sort_chain_graph_rel(chain_root, param->min_percent);
        rb_root->rb_node = chain_root->rb_root.rb_node;
 }
 
+int register_callchain_param(struct callchain_param *param)
+{
+       switch (param->mode) {
+       case CHAIN_GRAPH_ABS:
+               param->sort = sort_chain_graph_abs;
+               break;
+       case CHAIN_GRAPH_REL:
+               param->sort = sort_chain_graph_rel;
+               break;
+       case CHAIN_FLAT:
+               param->sort = sort_chain_flat;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
 /*
  * Create a child for a parent. If inherit_children, then the new child
  * will become the new parent of it's parent children
@@ -159,6 +215,7 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
        new = create_child(parent, false);
        fill_node(new, chain, start, syms);
 
+       new->children_hit = 0;
        new->hit = 1;
 }
 
@@ -189,6 +246,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
 
        /* split the hits */
        new->hit = parent->hit;
+       new->children_hit = parent->children_hit;
+       parent->children_hit = cumul_hits(new);
        new->val_nr = parent->val_nr - idx_local;
        parent->val_nr = idx_local;
 
@@ -196,6 +255,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
        if (idx_total < chain->nr) {
                parent->hit = 0;
                add_child(parent, chain, idx_total, syms);
+               parent->children_hit++;
        } else {
                parent->hit = 1;
        }
@@ -216,10 +276,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
                unsigned int ret = __append_chain(rnode, chain, start, syms);
 
                if (!ret)
-                       return;
+                       goto inc_children_hit;
        }
        /* nothing in children, add to the current node */
        add_child(root, chain, start, syms);
+
+inc_children_hit:
+       root->children_hit++;
 }
 
 static int
@@ -273,5 +336,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
 void append_chain(struct callchain_node *root, struct ip_callchain *chain,
                  struct symbol **syms)
 {
+       if (!chain->nr)
+               return;
        __append_chain_children(root, chain, syms, 0);
 }