diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-08-07 01:11:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-09 06:54:33 -0400 |
commit | 1953287bfe8afcbbd235bd6c42c9df06d52438dc (patch) | |
tree | 7428a4f33fe3509d7a705706df4f3c688266e19f /tools | |
parent | 836179834833272f89098c6d1e1b89e8e69797c2 (diff) |
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>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-report.c | 4 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 27 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 7 |
3 files changed, 24 insertions, 14 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cb58d68a006..da402e186561 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -901,7 +901,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
901 | int i; | 901 | int i; |
902 | 902 | ||
903 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 903 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
904 | new_total = self->cumul_hit; | 904 | new_total = self->children_hit; |
905 | else | 905 | else |
906 | new_total = total_samples; | 906 | new_total = total_samples; |
907 | 907 | ||
@@ -930,7 +930,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
930 | ret += ipchain__fprintf_graph(fp, chain, depth, | 930 | ret += ipchain__fprintf_graph(fp, chain, depth, |
931 | new_depth_mask, i++, | 931 | new_depth_mask, i++, |
932 | new_total, | 932 | new_total, |
933 | child->cumul_hit); | 933 | cumul_hits(child)); |
934 | } | 934 | } |
935 | ret += callchain__fprintf_graph(fp, child, new_total, | 935 | ret += callchain__fprintf_graph(fp, child, new_total, |
936 | depth + 1, | 936 | depth + 1, |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9d3c8141b8c1..98c5627f327b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -26,10 +26,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | |||
26 | struct rb_node **p = &root->rb_node; | 26 | struct rb_node **p = &root->rb_node; |
27 | struct rb_node *parent = NULL; | 27 | struct rb_node *parent = NULL; |
28 | struct callchain_node *rnode; | 28 | struct callchain_node *rnode; |
29 | u64 chain_cumul = cumul_hits(chain); | ||
29 | 30 | ||
30 | while (*p) { | 31 | while (*p) { |
32 | u64 rnode_cumul; | ||
33 | |||
31 | parent = *p; | 34 | parent = *p; |
32 | rnode = rb_entry(parent, struct callchain_node, rb_node); | 35 | rnode = rb_entry(parent, struct callchain_node, rb_node); |
36 | rnode_cumul = cumul_hits(rnode); | ||
33 | 37 | ||
34 | switch (mode) { | 38 | switch (mode) { |
35 | case CHAIN_FLAT: | 39 | case CHAIN_FLAT: |
@@ -40,7 +44,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | |||
40 | break; | 44 | break; |
41 | case CHAIN_GRAPH_ABS: /* Falldown */ | 45 | case CHAIN_GRAPH_ABS: /* Falldown */ |
42 | case CHAIN_GRAPH_REL: | 46 | case CHAIN_GRAPH_REL: |
43 | if (rnode->cumul_hit < chain->cumul_hit) | 47 | if (rnode_cumul < chain_cumul) |
44 | p = &(*p)->rb_left; | 48 | p = &(*p)->rb_left; |
45 | else | 49 | else |
46 | p = &(*p)->rb_right; | 50 | p = &(*p)->rb_right; |
@@ -87,7 +91,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node, | |||
87 | 91 | ||
88 | chain_for_each_child(child, node) { | 92 | chain_for_each_child(child, node) { |
89 | __sort_chain_graph_abs(child, min_hit); | 93 | __sort_chain_graph_abs(child, min_hit); |
90 | if (child->cumul_hit >= min_hit) | 94 | if (cumul_hits(child) >= min_hit) |
91 | rb_insert_callchain(&node->rb_root, child, | 95 | rb_insert_callchain(&node->rb_root, child, |
92 | CHAIN_GRAPH_ABS); | 96 | CHAIN_GRAPH_ABS); |
93 | } | 97 | } |
@@ -108,11 +112,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node, | |||
108 | u64 min_hit; | 112 | u64 min_hit; |
109 | 113 | ||
110 | node->rb_root = RB_ROOT; | 114 | node->rb_root = RB_ROOT; |
111 | min_hit = node->cumul_hit * min_percent / 100.0; | 115 | min_hit = node->children_hit * min_percent / 100.0; |
112 | 116 | ||
113 | chain_for_each_child(child, node) { | 117 | chain_for_each_child(child, node) { |
114 | __sort_chain_graph_rel(child, min_percent); | 118 | __sort_chain_graph_rel(child, min_percent); |
115 | if (child->cumul_hit >= min_hit) | 119 | if (cumul_hits(child) >= min_hit) |
116 | rb_insert_callchain(&node->rb_root, child, | 120 | rb_insert_callchain(&node->rb_root, child, |
117 | CHAIN_GRAPH_REL); | 121 | CHAIN_GRAPH_REL); |
118 | } | 122 | } |
@@ -211,7 +215,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
211 | new = create_child(parent, false); | 215 | new = create_child(parent, false); |
212 | fill_node(new, chain, start, syms); | 216 | fill_node(new, chain, start, syms); |
213 | 217 | ||
214 | new->cumul_hit = new->hit = 1; | 218 | new->children_hit = 0; |
219 | new->hit = 1; | ||
215 | } | 220 | } |
216 | 221 | ||
217 | /* | 222 | /* |
@@ -241,7 +246,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
241 | 246 | ||
242 | /* split the hits */ | 247 | /* split the hits */ |
243 | new->hit = parent->hit; | 248 | new->hit = parent->hit; |
244 | new->cumul_hit = parent->cumul_hit; | 249 | new->children_hit = parent->children_hit; |
250 | parent->children_hit = cumul_hits(new); | ||
245 | new->val_nr = parent->val_nr - idx_local; | 251 | new->val_nr = parent->val_nr - idx_local; |
246 | parent->val_nr = idx_local; | 252 | parent->val_nr = idx_local; |
247 | 253 | ||
@@ -249,6 +255,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
249 | if (idx_total < chain->nr) { | 255 | if (idx_total < chain->nr) { |
250 | parent->hit = 0; | 256 | parent->hit = 0; |
251 | add_child(parent, chain, idx_total, syms); | 257 | add_child(parent, chain, idx_total, syms); |
258 | parent->children_hit++; | ||
252 | } else { | 259 | } else { |
253 | parent->hit = 1; | 260 | parent->hit = 1; |
254 | } | 261 | } |
@@ -269,13 +276,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain, | |||
269 | unsigned int ret = __append_chain(rnode, chain, start, syms); | 276 | unsigned int ret = __append_chain(rnode, chain, start, syms); |
270 | 277 | ||
271 | if (!ret) | 278 | if (!ret) |
272 | goto cumul; | 279 | goto inc_children_hit; |
273 | } | 280 | } |
274 | /* nothing in children, add to the current node */ | 281 | /* nothing in children, add to the current node */ |
275 | add_child(root, chain, start, syms); | 282 | add_child(root, chain, start, syms); |
276 | 283 | ||
277 | cumul: | 284 | inc_children_hit: |
278 | root->cumul_hit++; | 285 | root->children_hit++; |
279 | } | 286 | } |
280 | 287 | ||
281 | static int | 288 | static int |
@@ -317,8 +324,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain, | |||
317 | /* we match 100% of the path, increment the hit */ | 324 | /* we match 100% of the path, increment the hit */ |
318 | if (i - start == root->val_nr && i == chain->nr) { | 325 | if (i - start == root->val_nr && i == chain->nr) { |
319 | root->hit++; | 326 | root->hit++; |
320 | root->cumul_hit++; | ||
321 | |||
322 | return 0; | 327 | return 0; |
323 | } | 328 | } |
324 | 329 | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 7812122bea1d..b2d128e07c88 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -21,7 +21,7 @@ struct callchain_node { | |||
21 | struct rb_root rb_root; /* sorted tree of children */ | 21 | struct rb_root rb_root; /* sorted tree of children */ |
22 | unsigned int val_nr; | 22 | unsigned int val_nr; |
23 | u64 hit; | 23 | u64 hit; |
24 | u64 cumul_hit; /* hit + hits of children */ | 24 | u64 children_hit; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | struct callchain_param; | 27 | struct callchain_param; |
@@ -48,6 +48,11 @@ static inline void callchain_init(struct callchain_node *node) | |||
48 | INIT_LIST_HEAD(&node->val); | 48 | INIT_LIST_HEAD(&node->val); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline u64 cumul_hits(struct callchain_node *node) | ||
52 | { | ||
53 | return node->hit + node->children_hit; | ||
54 | } | ||
55 | |||
51 | int register_callchain_param(struct callchain_param *param); | 56 | int register_callchain_param(struct callchain_param *param); |
52 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, | 57 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, |
53 | struct symbol **syms); | 58 | struct symbol **syms); |