blob: 08f0fbf5527c357f8502099da5b0cc33d7114ae3 [file] [log] [blame]
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +02001/*
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +01002 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +02003 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +02007 * 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 *
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020010 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +020016#include <math.h>
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020017
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +010018#include "asm/bug.h"
19
Andi Kleen99571ab2013-07-18 15:33:57 -070020#include "hist.h"
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030021#include "util.h"
Namhyung Kim2dc9fb12014-01-14 14:25:35 +090022#include "sort.h"
23#include "machine.h"
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020024#include "callchain.h"
25
Namhyung Kim47260642012-05-31 14:43:26 +090026__thread struct callchain_cursor callchain_cursor;
27
Don Zickuscff6bb42014-04-07 14:55:24 -040028int
29parse_callchain_report_opt(const char *arg)
30{
Namhyung Kime8232f12014-08-14 15:01:38 +090031 char *tok;
Don Zickuscff6bb42014-04-07 14:55:24 -040032 char *endptr;
Namhyung Kime8232f12014-08-14 15:01:38 +090033 bool minpcnt_set = false;
Don Zickuscff6bb42014-04-07 14:55:24 -040034
35 symbol_conf.use_callchain = true;
36
37 if (!arg)
38 return 0;
39
Namhyung Kime8232f12014-08-14 15:01:38 +090040 while ((tok = strtok((char *)arg, ",")) != NULL) {
41 if (!strncmp(tok, "none", strlen(tok))) {
42 callchain_param.mode = CHAIN_NONE;
43 symbol_conf.use_callchain = false;
44 return 0;
45 }
Don Zickuscff6bb42014-04-07 14:55:24 -040046
Namhyung Kime8232f12014-08-14 15:01:38 +090047 /* try to get the output mode */
48 if (!strncmp(tok, "graph", strlen(tok)))
49 callchain_param.mode = CHAIN_GRAPH_ABS;
50 else if (!strncmp(tok, "flat", strlen(tok)))
51 callchain_param.mode = CHAIN_FLAT;
52 else if (!strncmp(tok, "fractal", strlen(tok)))
53 callchain_param.mode = CHAIN_GRAPH_REL;
54 /* try to get the call chain order */
55 else if (!strncmp(tok, "caller", strlen(tok)))
56 callchain_param.order = ORDER_CALLER;
57 else if (!strncmp(tok, "callee", strlen(tok)))
58 callchain_param.order = ORDER_CALLEE;
59 /* try to get the sort key */
60 else if (!strncmp(tok, "function", strlen(tok)))
61 callchain_param.key = CCKEY_FUNCTION;
62 else if (!strncmp(tok, "address", strlen(tok)))
63 callchain_param.key = CCKEY_ADDRESS;
64 /* try to get the min percent */
65 else if (!minpcnt_set) {
66 callchain_param.min_percent = strtod(tok, &endptr);
67 if (tok == endptr)
68 return -1;
69 minpcnt_set = true;
70 } else {
71 /* try print limit at last */
72 callchain_param.print_limit = strtoul(tok, &endptr, 0);
73 if (tok == endptr)
74 return -1;
75 }
Don Zickuscff6bb42014-04-07 14:55:24 -040076
Namhyung Kime8232f12014-08-14 15:01:38 +090077 arg = NULL;
Don Zickuscff6bb42014-04-07 14:55:24 -040078 }
79
Don Zickuscff6bb42014-04-07 14:55:24 -040080 if (callchain_register_param(&callchain_param) < 0) {
81 pr_err("Can't register callchain params\n");
82 return -1;
83 }
84 return 0;
85}
86
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +020087static void
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020088rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
89 enum chain_mode mode)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020090{
91 struct rb_node **p = &root->rb_node;
92 struct rb_node *parent = NULL;
93 struct callchain_node *rnode;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010094 u64 chain_cumul = callchain_cumul_hits(chain);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020095
96 while (*p) {
Frederic Weisbecker19532872009-08-07 07:11:05 +020097 u64 rnode_cumul;
98
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020099 parent = *p;
100 rnode = rb_entry(parent, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100101 rnode_cumul = callchain_cumul_hits(rnode);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200102
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200103 switch (mode) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200104 case CHAIN_FLAT:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200105 if (rnode->hit < chain->hit)
106 p = &(*p)->rb_left;
107 else
108 p = &(*p)->rb_right;
109 break;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200110 case CHAIN_GRAPH_ABS: /* Falldown */
111 case CHAIN_GRAPH_REL:
Frederic Weisbecker19532872009-08-07 07:11:05 +0200112 if (rnode_cumul < chain_cumul)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200113 p = &(*p)->rb_left;
114 else
115 p = &(*p)->rb_right;
116 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200117 case CHAIN_NONE:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200118 default:
119 break;
120 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200121 }
122
123 rb_link_node(&chain->rb_node, parent, p);
124 rb_insert_color(&chain->rb_node, root);
125}
126
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200127static void
128__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
129 u64 min_hit)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200130{
Namhyung Kime3695172013-10-11 14:15:36 +0900131 struct rb_node *n;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200132 struct callchain_node *child;
133
Namhyung Kime3695172013-10-11 14:15:36 +0900134 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
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200139 __sort_chain_flat(rb_root, child, min_hit);
Namhyung Kime3695172013-10-11 14:15:36 +0900140 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200141
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200142 if (node->hit && node->hit >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200143 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200144}
145
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200146/*
147 * Once we get every callchains from the stream, we can now
148 * sort them by hit
149 */
150static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200151sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300152 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200153{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200154 __sort_chain_flat(rb_root, &root->node, min_hit);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200155}
156
157static void __sort_chain_graph_abs(struct callchain_node *node,
158 u64 min_hit)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200159{
Namhyung Kime3695172013-10-11 14:15:36 +0900160 struct rb_node *n;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200161 struct callchain_node *child;
162
163 node->rb_root = RB_ROOT;
Namhyung Kime3695172013-10-11 14:15:36 +0900164 n = rb_first(&node->rb_root_in);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200165
Namhyung Kime3695172013-10-11 14:15:36 +0900166 while (n) {
167 child = rb_entry(n, struct callchain_node, rb_node_in);
168 n = rb_next(n);
169
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200170 __sort_chain_graph_abs(child, min_hit);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100171 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200172 rb_insert_callchain(&node->rb_root, child,
173 CHAIN_GRAPH_ABS);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200174 }
175}
176
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200177static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200178sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300179 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200180{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200181 __sort_chain_graph_abs(&chain_root->node, min_hit);
182 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200183}
184
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200185static void __sort_chain_graph_rel(struct callchain_node *node,
186 double min_percent)
187{
Namhyung Kime3695172013-10-11 14:15:36 +0900188 struct rb_node *n;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200189 struct callchain_node *child;
190 u64 min_hit;
191
192 node->rb_root = RB_ROOT;
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +0200193 min_hit = ceil(node->children_hit * min_percent);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200194
Namhyung Kime3695172013-10-11 14:15:36 +0900195 n = rb_first(&node->rb_root_in);
196 while (n) {
197 child = rb_entry(n, struct callchain_node, rb_node_in);
198 n = rb_next(n);
199
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200200 __sort_chain_graph_rel(child, min_percent);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100201 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200202 rb_insert_callchain(&node->rb_root, child,
203 CHAIN_GRAPH_REL);
204 }
205}
206
207static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200208sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300209 u64 min_hit __maybe_unused, struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200210{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200211 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
212 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200213}
214
Frederic Weisbecker16537f12011-01-14 04:52:00 +0100215int callchain_register_param(struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200216{
217 switch (param->mode) {
218 case CHAIN_GRAPH_ABS:
219 param->sort = sort_chain_graph_abs;
220 break;
221 case CHAIN_GRAPH_REL:
222 param->sort = sort_chain_graph_rel;
223 break;
224 case CHAIN_FLAT:
225 param->sort = sort_chain_flat;
226 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200227 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200228 default:
229 return -1;
230 }
231 return 0;
232}
233
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200234/*
235 * Create a child for a parent. If inherit_children, then the new child
236 * will become the new parent of it's parent children
237 */
238static struct callchain_node *
239create_child(struct callchain_node *parent, bool inherit_children)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200240{
241 struct callchain_node *new;
242
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300243 new = zalloc(sizeof(*new));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200244 if (!new) {
245 perror("not enough memory to create child for code path tree");
246 return NULL;
247 }
248 new->parent = parent;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200249 INIT_LIST_HEAD(&new->val);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200250
251 if (inherit_children) {
Namhyung Kime3695172013-10-11 14:15:36 +0900252 struct rb_node *n;
253 struct callchain_node *child;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200254
Namhyung Kime3695172013-10-11 14:15:36 +0900255 new->rb_root_in = parent->rb_root_in;
256 parent->rb_root_in = RB_ROOT;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200257
Namhyung Kime3695172013-10-11 14:15:36 +0900258 n = rb_first(&new->rb_root_in);
259 while (n) {
260 child = rb_entry(n, struct callchain_node, rb_node_in);
261 child->parent = new;
262 n = rb_next(n);
263 }
264
265 /* make it the first child */
266 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
267 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200268 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200269
270 return new;
271}
272
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300273
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200274/*
275 * Fill the node with callchain values
276 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200277static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100278fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200279{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100280 struct callchain_cursor_node *cursor_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200281
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100282 node->val_nr = cursor->nr - cursor->pos;
283 if (!node->val_nr)
284 pr_warning("Warning: empty node in callchain tree\n");
285
286 cursor_node = callchain_cursor_current(cursor);
287
288 while (cursor_node) {
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200289 struct callchain_list *call;
290
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300291 call = zalloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200292 if (!call) {
293 perror("not enough memory for the code path tree");
294 return;
295 }
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100296 call->ip = cursor_node->ip;
297 call->ms.sym = cursor_node->sym;
298 call->ms.map = cursor_node->map;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200299 list_add_tail(&call->list, &node->val);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100300
301 callchain_cursor_advance(cursor);
302 cursor_node = callchain_cursor_current(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200303 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200304}
305
Namhyung Kime3695172013-10-11 14:15:36 +0900306static struct callchain_node *
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100307add_child(struct callchain_node *parent,
308 struct callchain_cursor *cursor,
309 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200310{
311 struct callchain_node *new;
312
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200313 new = create_child(parent, false);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100314 fill_node(new, cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200315
Frederic Weisbecker19532872009-08-07 07:11:05 +0200316 new->children_hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200317 new->hit = period;
Namhyung Kime3695172013-10-11 14:15:36 +0900318 return new;
319}
320
321static s64 match_chain(struct callchain_cursor_node *node,
322 struct callchain_list *cnode)
323{
324 struct symbol *sym = node->sym;
325
326 if (cnode->ms.sym && sym &&
327 callchain_param.key == CCKEY_FUNCTION)
328 return cnode->ms.sym->start - sym->start;
329 else
330 return cnode->ip - node->ip;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200331}
332
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200333/*
334 * Split the parent in two parts (a new child is created) and
335 * give a part of its callchain to the created child.
336 * Then create another child to host the given callchain of new branch
337 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200338static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100339split_add_child(struct callchain_node *parent,
340 struct callchain_cursor *cursor,
341 struct callchain_list *to_split,
342 u64 idx_parents, u64 idx_local, u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200343{
344 struct callchain_node *new;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200345 struct list_head *old_tail;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200346 unsigned int idx_total = idx_parents + idx_local;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200347
348 /* split */
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200349 new = create_child(parent, true);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200350
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200351 /* split the callchain and move a part to the new child */
352 old_tail = parent->val.prev;
353 list_del_range(&to_split->list, old_tail);
354 new->val.next = &to_split->list;
355 new->val.prev = old_tail;
356 to_split->list.prev = &new->val;
357 old_tail->next = &new->val;
358
359 /* split the hits */
360 new->hit = parent->hit;
Frederic Weisbecker19532872009-08-07 07:11:05 +0200361 new->children_hit = parent->children_hit;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100362 parent->children_hit = callchain_cumul_hits(new);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200363 new->val_nr = parent->val_nr - idx_local;
364 parent->val_nr = idx_local;
365
366 /* create a new child for the new branch if any */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100367 if (idx_total < cursor->nr) {
Namhyung Kime3695172013-10-11 14:15:36 +0900368 struct callchain_node *first;
369 struct callchain_list *cnode;
370 struct callchain_cursor_node *node;
371 struct rb_node *p, **pp;
372
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200373 parent->hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200374 parent->children_hit += period;
Namhyung Kime3695172013-10-11 14:15:36 +0900375
376 node = callchain_cursor_current(cursor);
377 new = add_child(parent, cursor, period);
378
379 /*
380 * This is second child since we moved parent's children
381 * to new (first) child above.
382 */
383 p = parent->rb_root_in.rb_node;
384 first = rb_entry(p, struct callchain_node, rb_node_in);
385 cnode = list_first_entry(&first->val, struct callchain_list,
386 list);
387
388 if (match_chain(node, cnode) < 0)
389 pp = &p->rb_left;
390 else
391 pp = &p->rb_right;
392
393 rb_link_node(&new->rb_node_in, p, pp);
394 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200395 } else {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200396 parent->hit = period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200397 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200398}
399
400static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100401append_chain(struct callchain_node *root,
402 struct callchain_cursor *cursor,
403 u64 period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200404
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200405static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100406append_chain_children(struct callchain_node *root,
407 struct callchain_cursor *cursor,
408 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200409{
410 struct callchain_node *rnode;
Namhyung Kime3695172013-10-11 14:15:36 +0900411 struct callchain_cursor_node *node;
412 struct rb_node **p = &root->rb_root_in.rb_node;
413 struct rb_node *parent = NULL;
414
415 node = callchain_cursor_current(cursor);
416 if (!node)
417 return;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200418
419 /* lookup in childrens */
Namhyung Kime3695172013-10-11 14:15:36 +0900420 while (*p) {
421 s64 ret;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200422
Namhyung Kime3695172013-10-11 14:15:36 +0900423 parent = *p;
424 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
Namhyung Kime3695172013-10-11 14:15:36 +0900425
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100426 /* If at least first entry matches, rely to children */
427 ret = append_chain(rnode, cursor, period);
428 if (ret == 0)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200429 goto inc_children_hit;
Namhyung Kime3695172013-10-11 14:15:36 +0900430
431 if (ret < 0)
432 p = &parent->rb_left;
433 else
434 p = &parent->rb_right;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200435 }
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200436 /* nothing in children, add to the current node */
Namhyung Kime3695172013-10-11 14:15:36 +0900437 rnode = add_child(root, cursor, period);
438 rb_link_node(&rnode->rb_node_in, parent, p);
439 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
Frederic Weisbeckere05b8762009-07-05 07:39:20 +0200440
Frederic Weisbecker19532872009-08-07 07:11:05 +0200441inc_children_hit:
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200442 root->children_hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200443}
444
445static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100446append_chain(struct callchain_node *root,
447 struct callchain_cursor *cursor,
448 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200449{
450 struct callchain_list *cnode;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100451 u64 start = cursor->pos;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200452 bool found = false;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100453 u64 matches;
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100454 int cmp = 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200455
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200456 /*
457 * Lookup in the current node
458 * If we have a symbol, then compare the start to match
Andi Kleen99571ab2013-07-18 15:33:57 -0700459 * anywhere inside a function, unless function
460 * mode is disabled.
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200461 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200462 list_for_each_entry(cnode, &root->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100463 struct callchain_cursor_node *node;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300464
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100465 node = callchain_cursor_current(cursor);
466 if (!node)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200467 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300468
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100469 cmp = match_chain(node, cnode);
470 if (cmp)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200471 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300472
Namhyung Kime3695172013-10-11 14:15:36 +0900473 found = true;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100474
475 callchain_cursor_advance(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200476 }
477
Namhyung Kime3695172013-10-11 14:15:36 +0900478 /* matches not, relay no the parent */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100479 if (!found) {
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100480 WARN_ONCE(!cmp, "Chain comparison error\n");
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100481 return cmp;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100482 }
483
484 matches = cursor->pos - start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200485
486 /* we match only a part of the node. Split it and add the new chain */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100487 if (matches < root->val_nr) {
488 split_add_child(root, cursor, cnode, start, matches, period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200489 return 0;
490 }
491
492 /* we match 100% of the path, increment the hit */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100493 if (matches == root->val_nr && cursor->pos == cursor->nr) {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200494 root->hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200495 return 0;
496 }
497
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200498 /* We match the node and still have a part remaining */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100499 append_chain_children(root, cursor, period);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200500
501 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200502}
503
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100504int callchain_append(struct callchain_root *root,
505 struct callchain_cursor *cursor,
506 u64 period)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300507{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100508 if (!cursor->nr)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300509 return 0;
510
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100511 callchain_cursor_commit(cursor);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300512
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100513 append_chain_children(&root->node, cursor, period);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300514
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100515 if (cursor->nr > root->max_depth)
516 root->max_depth = cursor->nr;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300517
518 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200519}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200520
521static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100522merge_chain_branch(struct callchain_cursor *cursor,
523 struct callchain_node *dst, struct callchain_node *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200524{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100525 struct callchain_cursor_node **old_last = cursor->last;
Namhyung Kime3695172013-10-11 14:15:36 +0900526 struct callchain_node *child;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200527 struct callchain_list *list, *next_list;
Namhyung Kime3695172013-10-11 14:15:36 +0900528 struct rb_node *n;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100529 int old_pos = cursor->nr;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200530 int err = 0;
531
532 list_for_each_entry_safe(list, next_list, &src->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100533 callchain_cursor_append(cursor, list->ip,
534 list->ms.map, list->ms.sym);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200535 list_del(&list->list);
536 free(list);
537 }
538
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100539 if (src->hit) {
540 callchain_cursor_commit(cursor);
541 append_chain_children(dst, cursor, src->hit);
542 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200543
Namhyung Kime3695172013-10-11 14:15:36 +0900544 n = rb_first(&src->rb_root_in);
545 while (n) {
546 child = container_of(n, struct callchain_node, rb_node_in);
547 n = rb_next(n);
548 rb_erase(&child->rb_node_in, &src->rb_root_in);
549
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100550 err = merge_chain_branch(cursor, dst, child);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200551 if (err)
552 break;
553
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200554 free(child);
555 }
556
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100557 cursor->nr = old_pos;
558 cursor->last = old_last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200559
560 return err;
561}
562
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100563int callchain_merge(struct callchain_cursor *cursor,
564 struct callchain_root *dst, struct callchain_root *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200565{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100566 return merge_chain_branch(cursor, &dst->node, &src->node);
567}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200568
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100569int callchain_cursor_append(struct callchain_cursor *cursor,
570 u64 ip, struct map *map, struct symbol *sym)
571{
572 struct callchain_cursor_node *node = *cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200573
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100574 if (!node) {
Paul Gortmaker91b98802013-01-30 20:05:49 -0500575 node = calloc(1, sizeof(*node));
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100576 if (!node)
577 return -ENOMEM;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200578
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100579 *cursor->last = node;
580 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200581
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100582 node->ip = ip;
583 node->map = map;
584 node->sym = sym;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200585
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100586 cursor->nr++;
587
588 cursor->last = &node->next;
589
590 return 0;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200591}
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900592
593int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
594 struct perf_evsel *evsel, struct addr_location *al,
595 int max_stack)
596{
597 if (sample->callchain == NULL)
598 return 0;
599
Namhyung Kim7a13aa22012-09-11 14:13:04 +0900600 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
601 sort__has_parent) {
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900602 return machine__resolve_callchain(al->machine, evsel, al->thread,
603 sample, parent, al, max_stack);
604 }
605 return 0;
606}
607
608int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
609{
Adrian Hunter4d40b052014-07-14 13:02:35 +0300610 if (!symbol_conf.use_callchain || sample->callchain == NULL)
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900611 return 0;
612 return callchain_append(he->callchain, &callchain_cursor, sample->period);
613}
Namhyung Kimc7405d82013-10-31 13:58:30 +0900614
615int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
616 bool hide_unresolved)
617{
618 al->map = node->map;
619 al->sym = node->sym;
620 if (node->map)
621 al->addr = node->map->map_ip(node->map, node->ip);
622 else
623 al->addr = node->ip;
624
625 if (al->sym == NULL) {
626 if (hide_unresolved)
627 return 0;
628 if (al->map == NULL)
629 goto out;
630 }
631
632 if (al->map->groups == &al->machine->kmaps) {
633 if (machine__is_host(al->machine)) {
634 al->cpumode = PERF_RECORD_MISC_KERNEL;
635 al->level = 'k';
636 } else {
637 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
638 al->level = 'g';
639 }
640 } else {
641 if (machine__is_host(al->machine)) {
642 al->cpumode = PERF_RECORD_MISC_USER;
643 al->level = '.';
644 } else if (perf_guest) {
645 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
646 al->level = 'u';
647 } else {
648 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
649 al->level = 'H';
650 }
651 }
652
653out:
654 return 1;
655}