]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/util/callchain.c
perf tools: Do proper comm override error handling
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / callchain.c
CommitLineData
8cb76d99 1/*
1b3a0e95 2 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
8cb76d99
FW
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
deac911c
FW
7 * Using a radix for code path provides a fast retrieval and factorizes
8 * memory use. Also that lets us use the paths in a hierarchical graph view.
9 *
8cb76d99
FW
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
c0a8865e 16#include <math.h>
8cb76d99 17
99571ab3 18#include "hist.h"
b36f19d5 19#include "util.h"
2dc9fb1a
NK
20#include "sort.h"
21#include "machine.h"
8cb76d99
FW
22#include "callchain.h"
23
47260645
NK
24__thread struct callchain_cursor callchain_cursor;
25
deac911c 26static void
4eb3e478
FW
27rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
28 enum chain_mode mode)
8cb76d99
FW
29{
30 struct rb_node **p = &root->rb_node;
31 struct rb_node *parent = NULL;
32 struct callchain_node *rnode;
f08c3154 33 u64 chain_cumul = callchain_cumul_hits(chain);
8cb76d99
FW
34
35 while (*p) {
1953287b
FW
36 u64 rnode_cumul;
37
8cb76d99
FW
38 parent = *p;
39 rnode = rb_entry(parent, struct callchain_node, rb_node);
f08c3154 40 rnode_cumul = callchain_cumul_hits(rnode);
8cb76d99 41
4eb3e478 42 switch (mode) {
805d127d 43 case CHAIN_FLAT:
4eb3e478
FW
44 if (rnode->hit < chain->hit)
45 p = &(*p)->rb_left;
46 else
47 p = &(*p)->rb_right;
48 break;
805d127d
FW
49 case CHAIN_GRAPH_ABS: /* Falldown */
50 case CHAIN_GRAPH_REL:
1953287b 51 if (rnode_cumul < chain_cumul)
4eb3e478
FW
52 p = &(*p)->rb_left;
53 else
54 p = &(*p)->rb_right;
55 break;
83a0944f 56 case CHAIN_NONE:
4eb3e478
FW
57 default:
58 break;
59 }
8cb76d99
FW
60 }
61
62 rb_link_node(&chain->rb_node, parent, p);
63 rb_insert_color(&chain->rb_node, root);
64}
65
805d127d
FW
66static void
67__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
68 u64 min_hit)
69{
e369517c 70 struct rb_node *n;
805d127d
FW
71 struct callchain_node *child;
72
e369517c
NK
73 n = rb_first(&node->rb_root_in);
74 while (n) {
75 child = rb_entry(n, struct callchain_node, rb_node_in);
76 n = rb_next(n);
77
805d127d 78 __sort_chain_flat(rb_root, child, min_hit);
e369517c 79 }
805d127d
FW
80
81 if (node->hit && node->hit >= min_hit)
82 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
83}
84
8cb76d99
FW
85/*
86 * Once we get every callchains from the stream, we can now
87 * sort them by hit
88 */
805d127d 89static void
d2009c51 90sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
1d037ca1 91 u64 min_hit, struct callchain_param *param __maybe_unused)
805d127d 92{
d2009c51 93 __sort_chain_flat(rb_root, &root->node, min_hit);
805d127d
FW
94}
95
96static void __sort_chain_graph_abs(struct callchain_node *node,
97 u64 min_hit)
8cb76d99 98{
e369517c 99 struct rb_node *n;
8cb76d99
FW
100 struct callchain_node *child;
101
805d127d 102 node->rb_root = RB_ROOT;
e369517c
NK
103 n = rb_first(&node->rb_root_in);
104
105 while (n) {
106 child = rb_entry(n, struct callchain_node, rb_node_in);
107 n = rb_next(n);
8cb76d99 108
805d127d 109 __sort_chain_graph_abs(child, min_hit);
f08c3154 110 if (callchain_cumul_hits(child) >= min_hit)
805d127d
FW
111 rb_insert_callchain(&node->rb_root, child,
112 CHAIN_GRAPH_ABS);
113 }
114}
115
116static void
d2009c51 117sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
1d037ca1 118 u64 min_hit, struct callchain_param *param __maybe_unused)
805d127d 119{
d2009c51
FW
120 __sort_chain_graph_abs(&chain_root->node, min_hit);
121 rb_root->rb_node = chain_root->node.rb_root.rb_node;
4eb3e478
FW
122}
123
805d127d
FW
124static void __sort_chain_graph_rel(struct callchain_node *node,
125 double min_percent)
4eb3e478 126{
e369517c 127 struct rb_node *n;
4eb3e478 128 struct callchain_node *child;
805d127d 129 u64 min_hit;
4eb3e478
FW
130
131 node->rb_root = RB_ROOT;
c0a8865e 132 min_hit = ceil(node->children_hit * min_percent);
4eb3e478 133
e369517c
NK
134 n = rb_first(&node->rb_root_in);
135 while (n) {
136 child = rb_entry(n, struct callchain_node, rb_node_in);
137 n = rb_next(n);
138
805d127d 139 __sort_chain_graph_rel(child, min_percent);
f08c3154 140 if (callchain_cumul_hits(child) >= min_hit)
805d127d
FW
141 rb_insert_callchain(&node->rb_root, child,
142 CHAIN_GRAPH_REL);
4eb3e478
FW
143 }
144}
145
805d127d 146static void
d2009c51 147sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
1d037ca1 148 u64 min_hit __maybe_unused, struct callchain_param *param)
4eb3e478 149{
d2009c51
FW
150 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
151 rb_root->rb_node = chain_root->node.rb_root.rb_node;
8cb76d99
FW
152}
153
16537f13 154int callchain_register_param(struct callchain_param *param)
805d127d
FW
155{
156 switch (param->mode) {
157 case CHAIN_GRAPH_ABS:
158 param->sort = sort_chain_graph_abs;
159 break;
160 case CHAIN_GRAPH_REL:
161 param->sort = sort_chain_graph_rel;
162 break;
163 case CHAIN_FLAT:
164 param->sort = sort_chain_flat;
165 break;
83a0944f 166 case CHAIN_NONE:
805d127d
FW
167 default:
168 return -1;
169 }
170 return 0;
171}
172
deac911c
FW
173/*
174 * Create a child for a parent. If inherit_children, then the new child
175 * will become the new parent of it's parent children
176 */
177static struct callchain_node *
178create_child(struct callchain_node *parent, bool inherit_children)
8cb76d99
FW
179{
180 struct callchain_node *new;
181
cdd5b75b 182 new = zalloc(sizeof(*new));
8cb76d99
FW
183 if (!new) {
184 perror("not enough memory to create child for code path tree");
185 return NULL;
186 }
187 new->parent = parent;
8cb76d99 188 INIT_LIST_HEAD(&new->val);
deac911c
FW
189
190 if (inherit_children) {
e369517c
NK
191 struct rb_node *n;
192 struct callchain_node *child;
193
194 new->rb_root_in = parent->rb_root_in;
195 parent->rb_root_in = RB_ROOT;
deac911c 196
e369517c
NK
197 n = rb_first(&new->rb_root_in);
198 while (n) {
199 child = rb_entry(n, struct callchain_node, rb_node_in);
200 child->parent = new;
201 n = rb_next(n);
202 }
deac911c 203
e369517c
NK
204 /* make it the first child */
205 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
206 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
deac911c 207 }
8cb76d99
FW
208
209 return new;
210}
211
301fde27 212
deac911c
FW
213/*
214 * Fill the node with callchain values
215 */
8cb76d99 216static void
1b3a0e95 217fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
8cb76d99 218{
1b3a0e95
FW
219 struct callchain_cursor_node *cursor_node;
220
221 node->val_nr = cursor->nr - cursor->pos;
222 if (!node->val_nr)
223 pr_warning("Warning: empty node in callchain tree\n");
8cb76d99 224
1b3a0e95
FW
225 cursor_node = callchain_cursor_current(cursor);
226
227 while (cursor_node) {
8cb76d99
FW
228 struct callchain_list *call;
229
cdd5b75b 230 call = zalloc(sizeof(*call));
8cb76d99
FW
231 if (!call) {
232 perror("not enough memory for the code path tree");
233 return;
234 }
1b3a0e95
FW
235 call->ip = cursor_node->ip;
236 call->ms.sym = cursor_node->sym;
237 call->ms.map = cursor_node->map;
8cb76d99 238 list_add_tail(&call->list, &node->val);
1b3a0e95
FW
239
240 callchain_cursor_advance(cursor);
241 cursor_node = callchain_cursor_current(cursor);
8cb76d99 242 }
8cb76d99
FW
243}
244
e369517c 245static struct callchain_node *
1b3a0e95
FW
246add_child(struct callchain_node *parent,
247 struct callchain_cursor *cursor,
248 u64 period)
8cb76d99
FW
249{
250 struct callchain_node *new;
251
deac911c 252 new = create_child(parent, false);
1b3a0e95 253 fill_node(new, cursor);
8cb76d99 254
1953287b 255 new->children_hit = 0;
108553e1 256 new->hit = period;
e369517c
NK
257 return new;
258}
259
260static s64 match_chain(struct callchain_cursor_node *node,
261 struct callchain_list *cnode)
262{
263 struct symbol *sym = node->sym;
264
265 if (cnode->ms.sym && sym &&
266 callchain_param.key == CCKEY_FUNCTION)
267 return cnode->ms.sym->start - sym->start;
268 else
269 return cnode->ip - node->ip;
8cb76d99
FW
270}
271
deac911c
FW
272/*
273 * Split the parent in two parts (a new child is created) and
274 * give a part of its callchain to the created child.
275 * Then create another child to host the given callchain of new branch
276 */
8cb76d99 277static void
1b3a0e95
FW
278split_add_child(struct callchain_node *parent,
279 struct callchain_cursor *cursor,
280 struct callchain_list *to_split,
281 u64 idx_parents, u64 idx_local, u64 period)
8cb76d99
FW
282{
283 struct callchain_node *new;
deac911c 284 struct list_head *old_tail;
f37a291c 285 unsigned int idx_total = idx_parents + idx_local;
8cb76d99
FW
286
287 /* split */
deac911c
FW
288 new = create_child(parent, true);
289
290 /* split the callchain and move a part to the new child */
291 old_tail = parent->val.prev;
292 list_del_range(&to_split->list, old_tail);
293 new->val.next = &to_split->list;
294 new->val.prev = old_tail;
295 to_split->list.prev = &new->val;
296 old_tail->next = &new->val;
8cb76d99 297
deac911c
FW
298 /* split the hits */
299 new->hit = parent->hit;
1953287b 300 new->children_hit = parent->children_hit;
f08c3154 301 parent->children_hit = callchain_cumul_hits(new);
deac911c
FW
302 new->val_nr = parent->val_nr - idx_local;
303 parent->val_nr = idx_local;
304
305 /* create a new child for the new branch if any */
1b3a0e95 306 if (idx_total < cursor->nr) {
e369517c
NK
307 struct callchain_node *first;
308 struct callchain_list *cnode;
309 struct callchain_cursor_node *node;
310 struct rb_node *p, **pp;
311
deac911c 312 parent->hit = 0;
108553e1 313 parent->children_hit += period;
e369517c
NK
314
315 node = callchain_cursor_current(cursor);
316 new = add_child(parent, cursor, period);
317
318 /*
319 * This is second child since we moved parent's children
320 * to new (first) child above.
321 */
322 p = parent->rb_root_in.rb_node;
323 first = rb_entry(p, struct callchain_node, rb_node_in);
324 cnode = list_first_entry(&first->val, struct callchain_list,
325 list);
326
327 if (match_chain(node, cnode) < 0)
328 pp = &p->rb_left;
329 else
330 pp = &p->rb_right;
331
332 rb_link_node(&new->rb_node_in, p, pp);
333 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
deac911c 334 } else {
108553e1 335 parent->hit = period;
deac911c 336 }
8cb76d99
FW
337}
338
339static int
1b3a0e95
FW
340append_chain(struct callchain_node *root,
341 struct callchain_cursor *cursor,
342 u64 period);
8cb76d99 343
deac911c 344static void
1b3a0e95
FW
345append_chain_children(struct callchain_node *root,
346 struct callchain_cursor *cursor,
347 u64 period)
8cb76d99
FW
348{
349 struct callchain_node *rnode;
e369517c
NK
350 struct callchain_cursor_node *node;
351 struct rb_node **p = &root->rb_root_in.rb_node;
352 struct rb_node *parent = NULL;
353
354 node = callchain_cursor_current(cursor);
355 if (!node)
356 return;
8cb76d99
FW
357
358 /* lookup in childrens */
e369517c
NK
359 while (*p) {
360 s64 ret;
361 struct callchain_list *cnode;
f37a291c 362
e369517c
NK
363 parent = *p;
364 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
365 cnode = list_first_entry(&rnode->val, struct callchain_list,
366 list);
367
368 /* just check first entry */
369 ret = match_chain(node, cnode);
370 if (ret == 0) {
371 append_chain(rnode, cursor, period);
1953287b 372 goto inc_children_hit;
e369517c
NK
373 }
374
375 if (ret < 0)
376 p = &parent->rb_left;
377 else
378 p = &parent->rb_right;
8cb76d99 379 }
deac911c 380 /* nothing in children, add to the current node */
e369517c
NK
381 rnode = add_child(root, cursor, period);
382 rb_link_node(&rnode->rb_node_in, parent, p);
383 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
e05b876c 384
1953287b 385inc_children_hit:
108553e1 386 root->children_hit += period;
8cb76d99
FW
387}
388
389static int
1b3a0e95
FW
390append_chain(struct callchain_node *root,
391 struct callchain_cursor *cursor,
392 u64 period)
8cb76d99 393{
1b3a0e95 394 struct callchain_cursor_node *curr_snap = cursor->curr;
8cb76d99 395 struct callchain_list *cnode;
1b3a0e95 396 u64 start = cursor->pos;
8cb76d99 397 bool found = false;
1b3a0e95 398 u64 matches;
8cb76d99 399
deac911c
FW
400 /*
401 * Lookup in the current node
402 * If we have a symbol, then compare the start to match
99571ab3
AK
403 * anywhere inside a function, unless function
404 * mode is disabled.
deac911c 405 */
8cb76d99 406 list_for_each_entry(cnode, &root->val, list) {
1b3a0e95 407 struct callchain_cursor_node *node;
301fde27 408
1b3a0e95
FW
409 node = callchain_cursor_current(cursor);
410 if (!node)
deac911c 411 break;
301fde27 412
e369517c 413 if (match_chain(node, cnode) != 0)
8cb76d99 414 break;
301fde27 415
e369517c 416 found = true;
1b3a0e95
FW
417
418 callchain_cursor_advance(cursor);
8cb76d99
FW
419 }
420
e369517c 421 /* matches not, relay no the parent */
1b3a0e95
FW
422 if (!found) {
423 cursor->curr = curr_snap;
424 cursor->pos = start;
8cb76d99 425 return -1;
1b3a0e95
FW
426 }
427
428 matches = cursor->pos - start;
8cb76d99
FW
429
430 /* we match only a part of the node. Split it and add the new chain */
1b3a0e95
FW
431 if (matches < root->val_nr) {
432 split_add_child(root, cursor, cnode, start, matches, period);
8cb76d99
FW
433 return 0;
434 }
435
436 /* we match 100% of the path, increment the hit */
1b3a0e95 437 if (matches == root->val_nr && cursor->pos == cursor->nr) {
108553e1 438 root->hit += period;
8cb76d99
FW
439 return 0;
440 }
441
deac911c 442 /* We match the node and still have a part remaining */
1b3a0e95 443 append_chain_children(root, cursor, period);
deac911c
FW
444
445 return 0;
8cb76d99
FW
446}
447
1b3a0e95
FW
448int callchain_append(struct callchain_root *root,
449 struct callchain_cursor *cursor,
450 u64 period)
8cb76d99 451{
1b3a0e95 452 if (!cursor->nr)
301fde27
FW
453 return 0;
454
1b3a0e95 455 callchain_cursor_commit(cursor);
301fde27 456
1b3a0e95 457 append_chain_children(&root->node, cursor, period);
d2009c51 458
1b3a0e95
FW
459 if (cursor->nr > root->max_depth)
460 root->max_depth = cursor->nr;
301fde27
FW
461
462 return 0;
8cb76d99 463}
612d4fd7
FW
464
465static int
1b3a0e95
FW
466merge_chain_branch(struct callchain_cursor *cursor,
467 struct callchain_node *dst, struct callchain_node *src)
612d4fd7 468{
1b3a0e95 469 struct callchain_cursor_node **old_last = cursor->last;
e369517c 470 struct callchain_node *child;
612d4fd7 471 struct callchain_list *list, *next_list;
e369517c 472 struct rb_node *n;
1b3a0e95 473 int old_pos = cursor->nr;
612d4fd7
FW
474 int err = 0;
475
476 list_for_each_entry_safe(list, next_list, &src->val, list) {
1b3a0e95
FW
477 callchain_cursor_append(cursor, list->ip,
478 list->ms.map, list->ms.sym);
612d4fd7
FW
479 list_del(&list->list);
480 free(list);
481 }
482
1b3a0e95
FW
483 if (src->hit) {
484 callchain_cursor_commit(cursor);
485 append_chain_children(dst, cursor, src->hit);
486 }
612d4fd7 487
e369517c
NK
488 n = rb_first(&src->rb_root_in);
489 while (n) {
490 child = container_of(n, struct callchain_node, rb_node_in);
491 n = rb_next(n);
492 rb_erase(&child->rb_node_in, &src->rb_root_in);
493
1b3a0e95 494 err = merge_chain_branch(cursor, dst, child);
612d4fd7
FW
495 if (err)
496 break;
497
612d4fd7
FW
498 free(child);
499 }
500
1b3a0e95
FW
501 cursor->nr = old_pos;
502 cursor->last = old_last;
612d4fd7
FW
503
504 return err;
505}
506
1b3a0e95
FW
507int callchain_merge(struct callchain_cursor *cursor,
508 struct callchain_root *dst, struct callchain_root *src)
509{
510 return merge_chain_branch(cursor, &dst->node, &src->node);
511}
512
513int callchain_cursor_append(struct callchain_cursor *cursor,
514 u64 ip, struct map *map, struct symbol *sym)
612d4fd7 515{
1b3a0e95 516 struct callchain_cursor_node *node = *cursor->last;
612d4fd7 517
1b3a0e95 518 if (!node) {
91b98804 519 node = calloc(1, sizeof(*node));
1b3a0e95
FW
520 if (!node)
521 return -ENOMEM;
612d4fd7 522
1b3a0e95
FW
523 *cursor->last = node;
524 }
612d4fd7 525
1b3a0e95
FW
526 node->ip = ip;
527 node->map = map;
528 node->sym = sym;
612d4fd7 529
1b3a0e95 530 cursor->nr++;
612d4fd7 531
1b3a0e95
FW
532 cursor->last = &node->next;
533
534 return 0;
612d4fd7 535}
2dc9fb1a
NK
536
537int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
538 struct perf_evsel *evsel, struct addr_location *al,
539 int max_stack)
540{
541 if (sample->callchain == NULL)
542 return 0;
543
544 if (symbol_conf.use_callchain || sort__has_parent) {
545 return machine__resolve_callchain(al->machine, evsel, al->thread,
546 sample, parent, al, max_stack);
547 }
548 return 0;
549}
550
551int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
552{
553 if (!symbol_conf.use_callchain)
554 return 0;
555 return callchain_append(he->callchain, &callchain_cursor, sample->period);
556}