perf tools: Fix call-chain cumul hit based sub-total (fractal mode)
The callchain fractal mode builds each new total hits in a new
branch of profiling by using the parent's hits of the current
branch plus the hits of the children.
This is wrong, the total hits of a branch should be made of the
sum of every children hits, we must ignore the parent hits in
this scope.
This patch also fixes another mistake with the hit counting.
Now the rates are correct.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9d3c814..98c5627 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -26,10 +26,14 @@
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 CHAIN_FLAT:
@@ -40,7 +44,7 @@
break;
case CHAIN_GRAPH_ABS: /* Falldown */
case CHAIN_GRAPH_REL:
- if (rnode->cumul_hit < chain->cumul_hit)
+ if (rnode_cumul < chain_cumul)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -87,7 +91,7 @@
chain_for_each_child(child, node) {
__sort_chain_graph_abs(child, min_hit);
- if (child->cumul_hit >= min_hit)
+ if (cumul_hits(child) >= min_hit)
rb_insert_callchain(&node->rb_root, child,
CHAIN_GRAPH_ABS);
}
@@ -108,11 +112,11 @@
u64 min_hit;
node->rb_root = RB_ROOT;
- min_hit = node->cumul_hit * min_percent / 100.0;
+ min_hit = node->children_hit * min_percent / 100.0;
chain_for_each_child(child, node) {
__sort_chain_graph_rel(child, min_percent);
- if (child->cumul_hit >= min_hit)
+ if (cumul_hits(child) >= min_hit)
rb_insert_callchain(&node->rb_root, child,
CHAIN_GRAPH_REL);
}
@@ -211,7 +215,8 @@
new = create_child(parent, false);
fill_node(new, chain, start, syms);
- new->cumul_hit = new->hit = 1;
+ new->children_hit = 0;
+ new->hit = 1;
}
/*
@@ -241,7 +246,8 @@
/* split the hits */
new->hit = parent->hit;
- new->cumul_hit = parent->cumul_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;
@@ -249,6 +255,7 @@
if (idx_total < chain->nr) {
parent->hit = 0;
add_child(parent, chain, idx_total, syms);
+ parent->children_hit++;
} else {
parent->hit = 1;
}
@@ -269,13 +276,13 @@
unsigned int ret = __append_chain(rnode, chain, start, syms);
if (!ret)
- goto cumul;
+ goto inc_children_hit;
}
/* nothing in children, add to the current node */
add_child(root, chain, start, syms);
-cumul:
- root->cumul_hit++;
+inc_children_hit:
+ root->children_hit++;
}
static int
@@ -317,8 +324,6 @@
/* we match 100% of the path, increment the hit */
if (i - start == root->val_nr && i == chain->nr) {
root->hit++;
- root->cumul_hit++;
-
return 0;
}