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;
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
new = create_child(parent, false);
fill_node(new, chain, start, syms);
+ new->children_hit = 0;
new->hit = 1;
}
/* 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;
if (idx_total < chain->nr) {
parent->hit = 0;
add_child(parent, chain, idx_total, syms);
+ parent->children_hit++;
} else {
parent->hit = 1;
}
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
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);
}