blob: 64b377e591e457746138173cfa59533f887e3d56 [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
Namhyung Kimf7f084f2014-09-23 10:01:42 +090028#ifdef HAVE_DWARF_UNWIND_SUPPORT
29static int get_stack_size(const char *str, unsigned long *_size)
30{
31 char *endptr;
32 unsigned long size;
33 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
34
35 size = strtoul(str, &endptr, 0);
36
37 do {
38 if (*endptr)
39 break;
40
41 size = round_up(size, sizeof(u64));
42 if (!size || size > max_size)
43 break;
44
45 *_size = size;
46 return 0;
47
48 } while (0);
49
50 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
51 max_size, str);
52 return -1;
53}
54#endif /* HAVE_DWARF_UNWIND_SUPPORT */
55
56int parse_callchain_record_opt(const char *arg)
57{
58 char *tok, *name, *saveptr = NULL;
59 char *buf;
60 int ret = -1;
61
62 /* We need buffer that we know we can write to. */
63 buf = malloc(strlen(arg) + 1);
64 if (!buf)
65 return -ENOMEM;
66
67 strcpy(buf, arg);
68
69 tok = strtok_r((char *)buf, ",", &saveptr);
70 name = tok ? : (char *)buf;
71
72 do {
73 /* Framepointer style */
74 if (!strncmp(name, "fp", sizeof("fp"))) {
75 if (!strtok_r(NULL, ",", &saveptr)) {
76 callchain_param.record_mode = CALLCHAIN_FP;
77 ret = 0;
78 } else
79 pr_err("callchain: No more arguments "
Kan Liangf70b4e32014-12-02 10:06:52 -050080 "needed for --call-graph fp\n");
Namhyung Kimf7f084f2014-09-23 10:01:42 +090081 break;
82
83#ifdef HAVE_DWARF_UNWIND_SUPPORT
84 /* Dwarf style */
85 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
86 const unsigned long default_stack_dump_size = 8192;
87
88 ret = 0;
89 callchain_param.record_mode = CALLCHAIN_DWARF;
90 callchain_param.dump_size = default_stack_dump_size;
91
92 tok = strtok_r(NULL, ",", &saveptr);
93 if (tok) {
94 unsigned long size = 0;
95
96 ret = get_stack_size(tok, &size);
97 callchain_param.dump_size = size;
98 }
99#endif /* HAVE_DWARF_UNWIND_SUPPORT */
100 } else {
101 pr_err("callchain: Unknown --call-graph option "
102 "value: %s\n", arg);
103 break;
104 }
105
106 } while (0);
107
108 free(buf);
109 return ret;
110}
111
Namhyung Kim2b9240c2014-09-23 10:01:43 +0900112static int parse_callchain_mode(const char *value)
113{
114 if (!strncmp(value, "graph", strlen(value))) {
115 callchain_param.mode = CHAIN_GRAPH_ABS;
116 return 0;
117 }
118 if (!strncmp(value, "flat", strlen(value))) {
119 callchain_param.mode = CHAIN_FLAT;
120 return 0;
121 }
122 if (!strncmp(value, "fractal", strlen(value))) {
123 callchain_param.mode = CHAIN_GRAPH_REL;
124 return 0;
125 }
126 return -1;
127}
128
129static int parse_callchain_order(const char *value)
130{
131 if (!strncmp(value, "caller", strlen(value))) {
132 callchain_param.order = ORDER_CALLER;
133 return 0;
134 }
135 if (!strncmp(value, "callee", strlen(value))) {
136 callchain_param.order = ORDER_CALLEE;
137 return 0;
138 }
139 return -1;
140}
141
142static int parse_callchain_sort_key(const char *value)
143{
144 if (!strncmp(value, "function", strlen(value))) {
145 callchain_param.key = CCKEY_FUNCTION;
146 return 0;
147 }
148 if (!strncmp(value, "address", strlen(value))) {
149 callchain_param.key = CCKEY_ADDRESS;
150 return 0;
151 }
Andi Kleen8b7bad52014-11-12 18:05:20 -0800152 if (!strncmp(value, "branch", strlen(value))) {
153 callchain_param.branch_callstack = 1;
154 return 0;
155 }
Namhyung Kim2b9240c2014-09-23 10:01:43 +0900156 return -1;
157}
158
Don Zickuscff6bb42014-04-07 14:55:24 -0400159int
160parse_callchain_report_opt(const char *arg)
161{
Namhyung Kime8232f12014-08-14 15:01:38 +0900162 char *tok;
Don Zickuscff6bb42014-04-07 14:55:24 -0400163 char *endptr;
Namhyung Kime8232f12014-08-14 15:01:38 +0900164 bool minpcnt_set = false;
Don Zickuscff6bb42014-04-07 14:55:24 -0400165
166 symbol_conf.use_callchain = true;
167
168 if (!arg)
169 return 0;
170
Namhyung Kime8232f12014-08-14 15:01:38 +0900171 while ((tok = strtok((char *)arg, ",")) != NULL) {
172 if (!strncmp(tok, "none", strlen(tok))) {
173 callchain_param.mode = CHAIN_NONE;
174 symbol_conf.use_callchain = false;
175 return 0;
176 }
Don Zickuscff6bb42014-04-07 14:55:24 -0400177
Namhyung Kim2b9240c2014-09-23 10:01:43 +0900178 if (!parse_callchain_mode(tok) ||
179 !parse_callchain_order(tok) ||
180 !parse_callchain_sort_key(tok)) {
181 /* parsing ok - move on to the next */
182 } else if (!minpcnt_set) {
183 /* try to get the min percent */
Namhyung Kime8232f12014-08-14 15:01:38 +0900184 callchain_param.min_percent = strtod(tok, &endptr);
185 if (tok == endptr)
186 return -1;
187 minpcnt_set = true;
188 } else {
189 /* try print limit at last */
190 callchain_param.print_limit = strtoul(tok, &endptr, 0);
191 if (tok == endptr)
192 return -1;
193 }
Don Zickuscff6bb42014-04-07 14:55:24 -0400194
Namhyung Kime8232f12014-08-14 15:01:38 +0900195 arg = NULL;
Don Zickuscff6bb42014-04-07 14:55:24 -0400196 }
197
Don Zickuscff6bb42014-04-07 14:55:24 -0400198 if (callchain_register_param(&callchain_param) < 0) {
199 pr_err("Can't register callchain params\n");
200 return -1;
201 }
202 return 0;
203}
204
Namhyung Kim2b9240c2014-09-23 10:01:43 +0900205int perf_callchain_config(const char *var, const char *value)
206{
207 char *endptr;
208
209 if (prefixcmp(var, "call-graph."))
210 return 0;
211 var += sizeof("call-graph.") - 1;
212
213 if (!strcmp(var, "record-mode"))
214 return parse_callchain_record_opt(value);
215#ifdef HAVE_DWARF_UNWIND_SUPPORT
216 if (!strcmp(var, "dump-size")) {
217 unsigned long size = 0;
218 int ret;
219
220 ret = get_stack_size(value, &size);
221 callchain_param.dump_size = size;
222
223 return ret;
224 }
225#endif
226 if (!strcmp(var, "print-type"))
227 return parse_callchain_mode(value);
228 if (!strcmp(var, "order"))
229 return parse_callchain_order(value);
230 if (!strcmp(var, "sort-key"))
231 return parse_callchain_sort_key(value);
232 if (!strcmp(var, "threshold")) {
233 callchain_param.min_percent = strtod(value, &endptr);
234 if (value == endptr)
235 return -1;
236 }
237 if (!strcmp(var, "print-limit")) {
238 callchain_param.print_limit = strtod(value, &endptr);
239 if (value == endptr)
240 return -1;
241 }
242
243 return 0;
244}
245
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200246static void
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200247rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
248 enum chain_mode mode)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200249{
250 struct rb_node **p = &root->rb_node;
251 struct rb_node *parent = NULL;
252 struct callchain_node *rnode;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100253 u64 chain_cumul = callchain_cumul_hits(chain);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200254
255 while (*p) {
Frederic Weisbecker19532872009-08-07 07:11:05 +0200256 u64 rnode_cumul;
257
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200258 parent = *p;
259 rnode = rb_entry(parent, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100260 rnode_cumul = callchain_cumul_hits(rnode);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200261
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200262 switch (mode) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200263 case CHAIN_FLAT:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200264 if (rnode->hit < chain->hit)
265 p = &(*p)->rb_left;
266 else
267 p = &(*p)->rb_right;
268 break;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200269 case CHAIN_GRAPH_ABS: /* Falldown */
270 case CHAIN_GRAPH_REL:
Frederic Weisbecker19532872009-08-07 07:11:05 +0200271 if (rnode_cumul < chain_cumul)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200272 p = &(*p)->rb_left;
273 else
274 p = &(*p)->rb_right;
275 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200276 case CHAIN_NONE:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200277 default:
278 break;
279 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200280 }
281
282 rb_link_node(&chain->rb_node, parent, p);
283 rb_insert_color(&chain->rb_node, root);
284}
285
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200286static void
287__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
288 u64 min_hit)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200289{
Namhyung Kime3695172013-10-11 14:15:36 +0900290 struct rb_node *n;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200291 struct callchain_node *child;
292
Namhyung Kime3695172013-10-11 14:15:36 +0900293 n = rb_first(&node->rb_root_in);
294 while (n) {
295 child = rb_entry(n, struct callchain_node, rb_node_in);
296 n = rb_next(n);
297
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200298 __sort_chain_flat(rb_root, child, min_hit);
Namhyung Kime3695172013-10-11 14:15:36 +0900299 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200300
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200301 if (node->hit && node->hit >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200302 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200303}
304
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200305/*
306 * Once we get every callchains from the stream, we can now
307 * sort them by hit
308 */
309static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200310sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300311 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200312{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200313 __sort_chain_flat(rb_root, &root->node, min_hit);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200314}
315
316static void __sort_chain_graph_abs(struct callchain_node *node,
317 u64 min_hit)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200318{
Namhyung Kime3695172013-10-11 14:15:36 +0900319 struct rb_node *n;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200320 struct callchain_node *child;
321
322 node->rb_root = RB_ROOT;
Namhyung Kime3695172013-10-11 14:15:36 +0900323 n = rb_first(&node->rb_root_in);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200324
Namhyung Kime3695172013-10-11 14:15:36 +0900325 while (n) {
326 child = rb_entry(n, struct callchain_node, rb_node_in);
327 n = rb_next(n);
328
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200329 __sort_chain_graph_abs(child, min_hit);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100330 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200331 rb_insert_callchain(&node->rb_root, child,
332 CHAIN_GRAPH_ABS);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200333 }
334}
335
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200336static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200337sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300338 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200339{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200340 __sort_chain_graph_abs(&chain_root->node, min_hit);
341 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200342}
343
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200344static void __sort_chain_graph_rel(struct callchain_node *node,
345 double min_percent)
346{
Namhyung Kime3695172013-10-11 14:15:36 +0900347 struct rb_node *n;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200348 struct callchain_node *child;
349 u64 min_hit;
350
351 node->rb_root = RB_ROOT;
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +0200352 min_hit = ceil(node->children_hit * min_percent);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200353
Namhyung Kime3695172013-10-11 14:15:36 +0900354 n = rb_first(&node->rb_root_in);
355 while (n) {
356 child = rb_entry(n, struct callchain_node, rb_node_in);
357 n = rb_next(n);
358
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200359 __sort_chain_graph_rel(child, min_percent);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100360 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200361 rb_insert_callchain(&node->rb_root, child,
362 CHAIN_GRAPH_REL);
363 }
364}
365
366static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200367sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300368 u64 min_hit __maybe_unused, struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200369{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200370 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
371 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200372}
373
Frederic Weisbecker16537f12011-01-14 04:52:00 +0100374int callchain_register_param(struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200375{
376 switch (param->mode) {
377 case CHAIN_GRAPH_ABS:
378 param->sort = sort_chain_graph_abs;
379 break;
380 case CHAIN_GRAPH_REL:
381 param->sort = sort_chain_graph_rel;
382 break;
383 case CHAIN_FLAT:
384 param->sort = sort_chain_flat;
385 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200386 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200387 default:
388 return -1;
389 }
390 return 0;
391}
392
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200393/*
394 * Create a child for a parent. If inherit_children, then the new child
395 * will become the new parent of it's parent children
396 */
397static struct callchain_node *
398create_child(struct callchain_node *parent, bool inherit_children)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200399{
400 struct callchain_node *new;
401
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300402 new = zalloc(sizeof(*new));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200403 if (!new) {
404 perror("not enough memory to create child for code path tree");
405 return NULL;
406 }
407 new->parent = parent;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200408 INIT_LIST_HEAD(&new->val);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200409
410 if (inherit_children) {
Namhyung Kime3695172013-10-11 14:15:36 +0900411 struct rb_node *n;
412 struct callchain_node *child;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200413
Namhyung Kime3695172013-10-11 14:15:36 +0900414 new->rb_root_in = parent->rb_root_in;
415 parent->rb_root_in = RB_ROOT;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200416
Namhyung Kime3695172013-10-11 14:15:36 +0900417 n = rb_first(&new->rb_root_in);
418 while (n) {
419 child = rb_entry(n, struct callchain_node, rb_node_in);
420 child->parent = new;
421 n = rb_next(n);
422 }
423
424 /* make it the first child */
425 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
426 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200427 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200428
429 return new;
430}
431
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300432
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200433/*
434 * Fill the node with callchain values
435 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200436static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100437fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200438{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100439 struct callchain_cursor_node *cursor_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200440
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100441 node->val_nr = cursor->nr - cursor->pos;
442 if (!node->val_nr)
443 pr_warning("Warning: empty node in callchain tree\n");
444
445 cursor_node = callchain_cursor_current(cursor);
446
447 while (cursor_node) {
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200448 struct callchain_list *call;
449
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300450 call = zalloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200451 if (!call) {
452 perror("not enough memory for the code path tree");
453 return;
454 }
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100455 call->ip = cursor_node->ip;
456 call->ms.sym = cursor_node->sym;
457 call->ms.map = cursor_node->map;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200458 list_add_tail(&call->list, &node->val);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100459
460 callchain_cursor_advance(cursor);
461 cursor_node = callchain_cursor_current(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200462 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200463}
464
Namhyung Kime3695172013-10-11 14:15:36 +0900465static struct callchain_node *
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100466add_child(struct callchain_node *parent,
467 struct callchain_cursor *cursor,
468 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200469{
470 struct callchain_node *new;
471
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200472 new = create_child(parent, false);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100473 fill_node(new, cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200474
Frederic Weisbecker19532872009-08-07 07:11:05 +0200475 new->children_hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200476 new->hit = period;
Namhyung Kime3695172013-10-11 14:15:36 +0900477 return new;
478}
479
480static s64 match_chain(struct callchain_cursor_node *node,
481 struct callchain_list *cnode)
482{
483 struct symbol *sym = node->sym;
484
485 if (cnode->ms.sym && sym &&
486 callchain_param.key == CCKEY_FUNCTION)
487 return cnode->ms.sym->start - sym->start;
488 else
489 return cnode->ip - node->ip;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200490}
491
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200492/*
493 * Split the parent in two parts (a new child is created) and
494 * give a part of its callchain to the created child.
495 * Then create another child to host the given callchain of new branch
496 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200497static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100498split_add_child(struct callchain_node *parent,
499 struct callchain_cursor *cursor,
500 struct callchain_list *to_split,
501 u64 idx_parents, u64 idx_local, u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200502{
503 struct callchain_node *new;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200504 struct list_head *old_tail;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200505 unsigned int idx_total = idx_parents + idx_local;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200506
507 /* split */
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200508 new = create_child(parent, true);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200509
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200510 /* split the callchain and move a part to the new child */
511 old_tail = parent->val.prev;
512 list_del_range(&to_split->list, old_tail);
513 new->val.next = &to_split->list;
514 new->val.prev = old_tail;
515 to_split->list.prev = &new->val;
516 old_tail->next = &new->val;
517
518 /* split the hits */
519 new->hit = parent->hit;
Frederic Weisbecker19532872009-08-07 07:11:05 +0200520 new->children_hit = parent->children_hit;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100521 parent->children_hit = callchain_cumul_hits(new);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200522 new->val_nr = parent->val_nr - idx_local;
523 parent->val_nr = idx_local;
524
525 /* create a new child for the new branch if any */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100526 if (idx_total < cursor->nr) {
Namhyung Kime3695172013-10-11 14:15:36 +0900527 struct callchain_node *first;
528 struct callchain_list *cnode;
529 struct callchain_cursor_node *node;
530 struct rb_node *p, **pp;
531
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200532 parent->hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200533 parent->children_hit += period;
Namhyung Kime3695172013-10-11 14:15:36 +0900534
535 node = callchain_cursor_current(cursor);
536 new = add_child(parent, cursor, period);
537
538 /*
539 * This is second child since we moved parent's children
540 * to new (first) child above.
541 */
542 p = parent->rb_root_in.rb_node;
543 first = rb_entry(p, struct callchain_node, rb_node_in);
544 cnode = list_first_entry(&first->val, struct callchain_list,
545 list);
546
547 if (match_chain(node, cnode) < 0)
548 pp = &p->rb_left;
549 else
550 pp = &p->rb_right;
551
552 rb_link_node(&new->rb_node_in, p, pp);
553 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200554 } else {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200555 parent->hit = period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200556 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200557}
558
559static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100560append_chain(struct callchain_node *root,
561 struct callchain_cursor *cursor,
562 u64 period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200563
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200564static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100565append_chain_children(struct callchain_node *root,
566 struct callchain_cursor *cursor,
567 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200568{
569 struct callchain_node *rnode;
Namhyung Kime3695172013-10-11 14:15:36 +0900570 struct callchain_cursor_node *node;
571 struct rb_node **p = &root->rb_root_in.rb_node;
572 struct rb_node *parent = NULL;
573
574 node = callchain_cursor_current(cursor);
575 if (!node)
576 return;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200577
578 /* lookup in childrens */
Namhyung Kime3695172013-10-11 14:15:36 +0900579 while (*p) {
580 s64 ret;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200581
Namhyung Kime3695172013-10-11 14:15:36 +0900582 parent = *p;
583 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
Namhyung Kime3695172013-10-11 14:15:36 +0900584
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100585 /* If at least first entry matches, rely to children */
586 ret = append_chain(rnode, cursor, period);
587 if (ret == 0)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200588 goto inc_children_hit;
Namhyung Kime3695172013-10-11 14:15:36 +0900589
590 if (ret < 0)
591 p = &parent->rb_left;
592 else
593 p = &parent->rb_right;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200594 }
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200595 /* nothing in children, add to the current node */
Namhyung Kime3695172013-10-11 14:15:36 +0900596 rnode = add_child(root, cursor, period);
597 rb_link_node(&rnode->rb_node_in, parent, p);
598 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
Frederic Weisbeckere05b8762009-07-05 07:39:20 +0200599
Frederic Weisbecker19532872009-08-07 07:11:05 +0200600inc_children_hit:
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200601 root->children_hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200602}
603
604static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100605append_chain(struct callchain_node *root,
606 struct callchain_cursor *cursor,
607 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200608{
609 struct callchain_list *cnode;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100610 u64 start = cursor->pos;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200611 bool found = false;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100612 u64 matches;
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100613 int cmp = 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200614
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200615 /*
616 * Lookup in the current node
617 * If we have a symbol, then compare the start to match
Andi Kleen99571ab2013-07-18 15:33:57 -0700618 * anywhere inside a function, unless function
619 * mode is disabled.
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200620 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200621 list_for_each_entry(cnode, &root->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100622 struct callchain_cursor_node *node;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300623
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100624 node = callchain_cursor_current(cursor);
625 if (!node)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200626 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300627
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100628 cmp = match_chain(node, cnode);
629 if (cmp)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200630 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300631
Namhyung Kime3695172013-10-11 14:15:36 +0900632 found = true;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100633
634 callchain_cursor_advance(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200635 }
636
Namhyung Kime3695172013-10-11 14:15:36 +0900637 /* matches not, relay no the parent */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100638 if (!found) {
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100639 WARN_ONCE(!cmp, "Chain comparison error\n");
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100640 return cmp;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100641 }
642
643 matches = cursor->pos - start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200644
645 /* we match only a part of the node. Split it and add the new chain */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100646 if (matches < root->val_nr) {
647 split_add_child(root, cursor, cnode, start, matches, period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200648 return 0;
649 }
650
651 /* we match 100% of the path, increment the hit */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100652 if (matches == root->val_nr && cursor->pos == cursor->nr) {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200653 root->hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200654 return 0;
655 }
656
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200657 /* We match the node and still have a part remaining */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100658 append_chain_children(root, cursor, period);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200659
660 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200661}
662
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100663int callchain_append(struct callchain_root *root,
664 struct callchain_cursor *cursor,
665 u64 period)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300666{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100667 if (!cursor->nr)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300668 return 0;
669
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100670 callchain_cursor_commit(cursor);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300671
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100672 append_chain_children(&root->node, cursor, period);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300673
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100674 if (cursor->nr > root->max_depth)
675 root->max_depth = cursor->nr;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300676
677 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200678}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200679
680static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100681merge_chain_branch(struct callchain_cursor *cursor,
682 struct callchain_node *dst, struct callchain_node *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200683{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100684 struct callchain_cursor_node **old_last = cursor->last;
Namhyung Kime3695172013-10-11 14:15:36 +0900685 struct callchain_node *child;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200686 struct callchain_list *list, *next_list;
Namhyung Kime3695172013-10-11 14:15:36 +0900687 struct rb_node *n;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100688 int old_pos = cursor->nr;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200689 int err = 0;
690
691 list_for_each_entry_safe(list, next_list, &src->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100692 callchain_cursor_append(cursor, list->ip,
693 list->ms.map, list->ms.sym);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200694 list_del(&list->list);
695 free(list);
696 }
697
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100698 if (src->hit) {
699 callchain_cursor_commit(cursor);
700 append_chain_children(dst, cursor, src->hit);
701 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200702
Namhyung Kime3695172013-10-11 14:15:36 +0900703 n = rb_first(&src->rb_root_in);
704 while (n) {
705 child = container_of(n, struct callchain_node, rb_node_in);
706 n = rb_next(n);
707 rb_erase(&child->rb_node_in, &src->rb_root_in);
708
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100709 err = merge_chain_branch(cursor, dst, child);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200710 if (err)
711 break;
712
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200713 free(child);
714 }
715
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100716 cursor->nr = old_pos;
717 cursor->last = old_last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200718
719 return err;
720}
721
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100722int callchain_merge(struct callchain_cursor *cursor,
723 struct callchain_root *dst, struct callchain_root *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200724{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100725 return merge_chain_branch(cursor, &dst->node, &src->node);
726}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200727
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100728int callchain_cursor_append(struct callchain_cursor *cursor,
729 u64 ip, struct map *map, struct symbol *sym)
730{
731 struct callchain_cursor_node *node = *cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200732
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100733 if (!node) {
Paul Gortmaker91b98802013-01-30 20:05:49 -0500734 node = calloc(1, sizeof(*node));
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100735 if (!node)
736 return -ENOMEM;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200737
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100738 *cursor->last = node;
739 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200740
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100741 node->ip = ip;
742 node->map = map;
743 node->sym = sym;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200744
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100745 cursor->nr++;
746
747 cursor->last = &node->next;
748
749 return 0;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200750}
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900751
752int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
753 struct perf_evsel *evsel, struct addr_location *al,
754 int max_stack)
755{
756 if (sample->callchain == NULL)
757 return 0;
758
Namhyung Kim7a13aa22012-09-11 14:13:04 +0900759 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
760 sort__has_parent) {
Arnaldo Carvalho de Melocc8b7c22014-10-23 15:26:17 -0300761 return thread__resolve_callchain(al->thread, evsel, sample,
762 parent, al, max_stack);
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900763 }
764 return 0;
765}
766
767int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
768{
Adrian Hunter4d40b052014-07-14 13:02:35 +0300769 if (!symbol_conf.use_callchain || sample->callchain == NULL)
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900770 return 0;
771 return callchain_append(he->callchain, &callchain_cursor, sample->period);
772}
Namhyung Kimc7405d82013-10-31 13:58:30 +0900773
774int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
775 bool hide_unresolved)
776{
777 al->map = node->map;
778 al->sym = node->sym;
779 if (node->map)
780 al->addr = node->map->map_ip(node->map, node->ip);
781 else
782 al->addr = node->ip;
783
784 if (al->sym == NULL) {
785 if (hide_unresolved)
786 return 0;
787 if (al->map == NULL)
788 goto out;
789 }
790
791 if (al->map->groups == &al->machine->kmaps) {
792 if (machine__is_host(al->machine)) {
793 al->cpumode = PERF_RECORD_MISC_KERNEL;
794 al->level = 'k';
795 } else {
796 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
797 al->level = 'g';
798 }
799 } else {
800 if (machine__is_host(al->machine)) {
801 al->cpumode = PERF_RECORD_MISC_USER;
802 al->level = '.';
803 } else if (perf_guest) {
804 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
805 al->level = 'u';
806 } else {
807 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
808 al->level = 'H';
809 }
810 }
811
812out:
813 return 1;
814}
Andi Kleen2989cca2014-11-12 18:05:23 -0800815
816char *callchain_list__sym_name(struct callchain_list *cl,
817 char *bf, size_t bfsize, bool show_dso)
818{
819 int printed;
820
821 if (cl->ms.sym) {
Andi Kleen23f09812014-11-12 18:05:24 -0800822 if (callchain_param.key == CCKEY_ADDRESS &&
823 cl->ms.map && !cl->srcline)
824 cl->srcline = get_srcline(cl->ms.map->dso,
825 map__rip_2objdump(cl->ms.map,
Andi Kleen85c116a2014-11-12 18:05:27 -0800826 cl->ip),
827 cl->ms.sym, false);
Andi Kleen23f09812014-11-12 18:05:24 -0800828 if (cl->srcline)
829 printed = scnprintf(bf, bfsize, "%s %s",
830 cl->ms.sym->name, cl->srcline);
831 else
832 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
Andi Kleen2989cca2014-11-12 18:05:23 -0800833 } else
834 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
835
836 if (show_dso)
837 scnprintf(bf + printed, bfsize - printed, " %s",
838 cl->ms.map ?
839 cl->ms.map->dso->short_name :
840 "unknown");
841
842 return bf;
843}