]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/util/callchain.c
perf report: Drop cycles 0 for LBR print
[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
b965bb41
FW
18#include "asm/bug.h"
19
99571ab3 20#include "hist.h"
b36f19d5 21#include "util.h"
2dc9fb1a
NK
22#include "sort.h"
23#include "machine.h"
8cb76d99
FW
24#include "callchain.h"
25
47260645
NK
26__thread struct callchain_cursor callchain_cursor;
27
c3a6a8c4 28int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
f7f084f4 29{
076a30c4 30 return parse_callchain_record(arg, param);
f7f084f4
NK
31}
32
2b9240ca
NK
33static int parse_callchain_mode(const char *value)
34{
35 if (!strncmp(value, "graph", strlen(value))) {
36 callchain_param.mode = CHAIN_GRAPH_ABS;
37 return 0;
38 }
39 if (!strncmp(value, "flat", strlen(value))) {
40 callchain_param.mode = CHAIN_FLAT;
41 return 0;
42 }
43 if (!strncmp(value, "fractal", strlen(value))) {
44 callchain_param.mode = CHAIN_GRAPH_REL;
45 return 0;
46 }
26e77924
NK
47 if (!strncmp(value, "folded", strlen(value))) {
48 callchain_param.mode = CHAIN_FOLDED;
49 return 0;
50 }
ecc4c561
ACM
51
52 pr_err("Invalid callchain mode: %s\n", value);
2b9240ca
NK
53 return -1;
54}
55
56static int parse_callchain_order(const char *value)
57{
58 if (!strncmp(value, "caller", strlen(value))) {
59 callchain_param.order = ORDER_CALLER;
792aeafa 60 callchain_param.order_set = true;
2b9240ca
NK
61 return 0;
62 }
63 if (!strncmp(value, "callee", strlen(value))) {
64 callchain_param.order = ORDER_CALLEE;
792aeafa 65 callchain_param.order_set = true;
2b9240ca
NK
66 return 0;
67 }
ecc4c561
ACM
68
69 pr_err("Invalid callchain order: %s\n", value);
2b9240ca
NK
70 return -1;
71}
72
73static int parse_callchain_sort_key(const char *value)
74{
75 if (!strncmp(value, "function", strlen(value))) {
76 callchain_param.key = CCKEY_FUNCTION;
77 return 0;
78 }
79 if (!strncmp(value, "address", strlen(value))) {
80 callchain_param.key = CCKEY_ADDRESS;
81 return 0;
82 }
5dfa210e
MW
83 if (!strncmp(value, "srcline", strlen(value))) {
84 callchain_param.key = CCKEY_SRCLINE;
85 return 0;
86 }
8b7bad58
AK
87 if (!strncmp(value, "branch", strlen(value))) {
88 callchain_param.branch_callstack = 1;
89 return 0;
90 }
ecc4c561
ACM
91
92 pr_err("Invalid callchain sort key: %s\n", value);
2b9240ca
NK
93 return -1;
94}
95
f2af0086
NK
96static int parse_callchain_value(const char *value)
97{
98 if (!strncmp(value, "percent", strlen(value))) {
99 callchain_param.value = CCVAL_PERCENT;
100 return 0;
101 }
102 if (!strncmp(value, "period", strlen(value))) {
103 callchain_param.value = CCVAL_PERIOD;
104 return 0;
105 }
106 if (!strncmp(value, "count", strlen(value))) {
107 callchain_param.value = CCVAL_COUNT;
108 return 0;
109 }
ecc4c561
ACM
110
111 pr_err("Invalid callchain config key: %s\n", value);
f2af0086
NK
112 return -1;
113}
114
a2c10d39
NK
115static int
116__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
cff6bb46 117{
e8232f1a 118 char *tok;
cff6bb46 119 char *endptr;
e8232f1a 120 bool minpcnt_set = false;
a2c10d39
NK
121 bool record_opt_set = false;
122 bool try_stack_size = false;
cff6bb46 123
30234f09 124 callchain_param.enabled = true;
cff6bb46
DZ
125 symbol_conf.use_callchain = true;
126
127 if (!arg)
128 return 0;
129
e8232f1a
NK
130 while ((tok = strtok((char *)arg, ",")) != NULL) {
131 if (!strncmp(tok, "none", strlen(tok))) {
132 callchain_param.mode = CHAIN_NONE;
30234f09 133 callchain_param.enabled = false;
e8232f1a
NK
134 symbol_conf.use_callchain = false;
135 return 0;
136 }
137
2b9240ca
NK
138 if (!parse_callchain_mode(tok) ||
139 !parse_callchain_order(tok) ||
f2af0086
NK
140 !parse_callchain_sort_key(tok) ||
141 !parse_callchain_value(tok)) {
2b9240ca 142 /* parsing ok - move on to the next */
a2c10d39
NK
143 try_stack_size = false;
144 goto next;
145 } else if (allow_record_opt && !record_opt_set) {
146 if (parse_callchain_record(tok, &callchain_param))
147 goto try_numbers;
148
149 /* assume that number followed by 'dwarf' is stack size */
150 if (callchain_param.record_mode == CALLCHAIN_DWARF)
151 try_stack_size = true;
152
153 record_opt_set = true;
154 goto next;
155 }
156
157try_numbers:
158 if (try_stack_size) {
159 unsigned long size = 0;
160
161 if (get_stack_size(tok, &size) < 0)
162 return -1;
163 callchain_param.dump_size = size;
164 try_stack_size = false;
2b9240ca
NK
165 } else if (!minpcnt_set) {
166 /* try to get the min percent */
e8232f1a
NK
167 callchain_param.min_percent = strtod(tok, &endptr);
168 if (tok == endptr)
169 return -1;
170 minpcnt_set = true;
171 } else {
172 /* try print limit at last */
173 callchain_param.print_limit = strtoul(tok, &endptr, 0);
174 if (tok == endptr)
175 return -1;
176 }
a2c10d39 177next:
e8232f1a 178 arg = NULL;
cff6bb46
DZ
179 }
180
cff6bb46
DZ
181 if (callchain_register_param(&callchain_param) < 0) {
182 pr_err("Can't register callchain params\n");
183 return -1;
184 }
185 return 0;
186}
187
a2c10d39
NK
188int parse_callchain_report_opt(const char *arg)
189{
190 return __parse_callchain_report_opt(arg, false);
191}
192
193int parse_callchain_top_opt(const char *arg)
194{
195 return __parse_callchain_report_opt(arg, true);
196}
197
2b9240ca
NK
198int perf_callchain_config(const char *var, const char *value)
199{
200 char *endptr;
201
202 if (prefixcmp(var, "call-graph."))
203 return 0;
204 var += sizeof("call-graph.") - 1;
205
206 if (!strcmp(var, "record-mode"))
c3a6a8c4 207 return parse_callchain_record_opt(value, &callchain_param);
2b9240ca
NK
208 if (!strcmp(var, "dump-size")) {
209 unsigned long size = 0;
210 int ret;
211
212 ret = get_stack_size(value, &size);
213 callchain_param.dump_size = size;
214
215 return ret;
216 }
2b9240ca
NK
217 if (!strcmp(var, "print-type"))
218 return parse_callchain_mode(value);
219 if (!strcmp(var, "order"))
220 return parse_callchain_order(value);
221 if (!strcmp(var, "sort-key"))
222 return parse_callchain_sort_key(value);
223 if (!strcmp(var, "threshold")) {
224 callchain_param.min_percent = strtod(value, &endptr);
ecc4c561
ACM
225 if (value == endptr) {
226 pr_err("Invalid callchain threshold: %s\n", value);
2b9240ca 227 return -1;
ecc4c561 228 }
2b9240ca
NK
229 }
230 if (!strcmp(var, "print-limit")) {
231 callchain_param.print_limit = strtod(value, &endptr);
ecc4c561
ACM
232 if (value == endptr) {
233 pr_err("Invalid callchain print limit: %s\n", value);
2b9240ca 234 return -1;
ecc4c561 235 }
2b9240ca
NK
236 }
237
238 return 0;
239}
240
deac911c 241static void
4eb3e478
FW
242rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
243 enum chain_mode mode)
8cb76d99
FW
244{
245 struct rb_node **p = &root->rb_node;
246 struct rb_node *parent = NULL;
247 struct callchain_node *rnode;
f08c3154 248 u64 chain_cumul = callchain_cumul_hits(chain);
8cb76d99
FW
249
250 while (*p) {
1953287b
FW
251 u64 rnode_cumul;
252
8cb76d99
FW
253 parent = *p;
254 rnode = rb_entry(parent, struct callchain_node, rb_node);
f08c3154 255 rnode_cumul = callchain_cumul_hits(rnode);
8cb76d99 256
4eb3e478 257 switch (mode) {
805d127d 258 case CHAIN_FLAT:
26e77924 259 case CHAIN_FOLDED:
4eb3e478
FW
260 if (rnode->hit < chain->hit)
261 p = &(*p)->rb_left;
262 else
263 p = &(*p)->rb_right;
264 break;
805d127d
FW
265 case CHAIN_GRAPH_ABS: /* Falldown */
266 case CHAIN_GRAPH_REL:
1953287b 267 if (rnode_cumul < chain_cumul)
4eb3e478
FW
268 p = &(*p)->rb_left;
269 else
270 p = &(*p)->rb_right;
271 break;
83a0944f 272 case CHAIN_NONE:
4eb3e478
FW
273 default:
274 break;
275 }
8cb76d99
FW
276 }
277
278 rb_link_node(&chain->rb_node, parent, p);
279 rb_insert_color(&chain->rb_node, root);
280}
281
805d127d
FW
282static void
283__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
284 u64 min_hit)
285{
e369517c 286 struct rb_node *n;
805d127d
FW
287 struct callchain_node *child;
288
e369517c
NK
289 n = rb_first(&node->rb_root_in);
290 while (n) {
291 child = rb_entry(n, struct callchain_node, rb_node_in);
292 n = rb_next(n);
293
805d127d 294 __sort_chain_flat(rb_root, child, min_hit);
e369517c 295 }
805d127d
FW
296
297 if (node->hit && node->hit >= min_hit)
298 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
299}
300
8cb76d99
FW
301/*
302 * Once we get every callchains from the stream, we can now
303 * sort them by hit
304 */
805d127d 305static void
d2009c51 306sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
1d037ca1 307 u64 min_hit, struct callchain_param *param __maybe_unused)
805d127d 308{
0356218a 309 *rb_root = RB_ROOT;
d2009c51 310 __sort_chain_flat(rb_root, &root->node, min_hit);
805d127d
FW
311}
312
313static void __sort_chain_graph_abs(struct callchain_node *node,
314 u64 min_hit)
8cb76d99 315{
e369517c 316 struct rb_node *n;
8cb76d99
FW
317 struct callchain_node *child;
318
805d127d 319 node->rb_root = RB_ROOT;
e369517c
NK
320 n = rb_first(&node->rb_root_in);
321
322 while (n) {
323 child = rb_entry(n, struct callchain_node, rb_node_in);
324 n = rb_next(n);
8cb76d99 325
805d127d 326 __sort_chain_graph_abs(child, min_hit);
f08c3154 327 if (callchain_cumul_hits(child) >= min_hit)
805d127d
FW
328 rb_insert_callchain(&node->rb_root, child,
329 CHAIN_GRAPH_ABS);
330 }
331}
332
333static void
d2009c51 334sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
1d037ca1 335 u64 min_hit, struct callchain_param *param __maybe_unused)
805d127d 336{
d2009c51
FW
337 __sort_chain_graph_abs(&chain_root->node, min_hit);
338 rb_root->rb_node = chain_root->node.rb_root.rb_node;
4eb3e478
FW
339}
340
805d127d
FW
341static void __sort_chain_graph_rel(struct callchain_node *node,
342 double min_percent)
4eb3e478 343{
e369517c 344 struct rb_node *n;
4eb3e478 345 struct callchain_node *child;
805d127d 346 u64 min_hit;
4eb3e478
FW
347
348 node->rb_root = RB_ROOT;
c0a8865e 349 min_hit = ceil(node->children_hit * min_percent);
4eb3e478 350
e369517c
NK
351 n = rb_first(&node->rb_root_in);
352 while (n) {
353 child = rb_entry(n, struct callchain_node, rb_node_in);
354 n = rb_next(n);
355
805d127d 356 __sort_chain_graph_rel(child, min_percent);
f08c3154 357 if (callchain_cumul_hits(child) >= min_hit)
805d127d
FW
358 rb_insert_callchain(&node->rb_root, child,
359 CHAIN_GRAPH_REL);
4eb3e478
FW
360 }
361}
362
805d127d 363static void
d2009c51 364sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
1d037ca1 365 u64 min_hit __maybe_unused, struct callchain_param *param)
4eb3e478 366{
d2009c51
FW
367 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
368 rb_root->rb_node = chain_root->node.rb_root.rb_node;
8cb76d99
FW
369}
370
16537f13 371int callchain_register_param(struct callchain_param *param)
805d127d
FW
372{
373 switch (param->mode) {
374 case CHAIN_GRAPH_ABS:
375 param->sort = sort_chain_graph_abs;
376 break;
377 case CHAIN_GRAPH_REL:
378 param->sort = sort_chain_graph_rel;
379 break;
380 case CHAIN_FLAT:
26e77924 381 case CHAIN_FOLDED:
805d127d
FW
382 param->sort = sort_chain_flat;
383 break;
83a0944f 384 case CHAIN_NONE:
805d127d
FW
385 default:
386 return -1;
387 }
388 return 0;
389}
390
deac911c
FW
391/*
392 * Create a child for a parent. If inherit_children, then the new child
393 * will become the new parent of it's parent children
394 */
395static struct callchain_node *
396create_child(struct callchain_node *parent, bool inherit_children)
8cb76d99
FW
397{
398 struct callchain_node *new;
399
cdd5b75b 400 new = zalloc(sizeof(*new));
8cb76d99
FW
401 if (!new) {
402 perror("not enough memory to create child for code path tree");
403 return NULL;
404 }
405 new->parent = parent;
8cb76d99 406 INIT_LIST_HEAD(&new->val);
4b3a3212 407 INIT_LIST_HEAD(&new->parent_val);
deac911c
FW
408
409 if (inherit_children) {
e369517c
NK
410 struct rb_node *n;
411 struct callchain_node *child;
412
413 new->rb_root_in = parent->rb_root_in;
414 parent->rb_root_in = RB_ROOT;
deac911c 415
e369517c
NK
416 n = rb_first(&new->rb_root_in);
417 while (n) {
418 child = rb_entry(n, struct callchain_node, rb_node_in);
419 child->parent = new;
420 n = rb_next(n);
421 }
deac911c 422
e369517c
NK
423 /* make it the first child */
424 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
425 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
deac911c 426 }
8cb76d99
FW
427
428 return new;
429}
430
301fde27 431
deac911c
FW
432/*
433 * Fill the node with callchain values
434 */
8451cbb9 435static int
1b3a0e95 436fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
8cb76d99 437{
1b3a0e95
FW
438 struct callchain_cursor_node *cursor_node;
439
440 node->val_nr = cursor->nr - cursor->pos;
441 if (!node->val_nr)
442 pr_warning("Warning: empty node in callchain tree\n");
8cb76d99 443
1b3a0e95
FW
444 cursor_node = callchain_cursor_current(cursor);
445
446 while (cursor_node) {
8cb76d99
FW
447 struct callchain_list *call;
448
cdd5b75b 449 call = zalloc(sizeof(*call));
8cb76d99
FW
450 if (!call) {
451 perror("not enough memory for the code path tree");
8451cbb9 452 return -1;
8cb76d99 453 }
1b3a0e95
FW
454 call->ip = cursor_node->ip;
455 call->ms.sym = cursor_node->sym;
9c68ae98 456 call->ms.map = map__get(cursor_node->map);
3dd029ef
JY
457
458 if (cursor_node->branch) {
459 call->branch_count = 1;
460
461 if (cursor_node->branch_flags.predicted)
462 call->predicted_count = 1;
463
464 if (cursor_node->branch_flags.abort)
465 call->abort_count = 1;
466
467 call->cycles_count = cursor_node->branch_flags.cycles;
468 call->iter_count = cursor_node->nr_loop_iter;
469 call->samples_count = cursor_node->samples;
470 }
471
8cb76d99 472 list_add_tail(&call->list, &node->val);
1b3a0e95
FW
473
474 callchain_cursor_advance(cursor);
475 cursor_node = callchain_cursor_current(cursor);
8cb76d99 476 }
8451cbb9 477 return 0;
8cb76d99
FW
478}
479
e369517c 480static struct callchain_node *
1b3a0e95
FW
481add_child(struct callchain_node *parent,
482 struct callchain_cursor *cursor,
483 u64 period)
8cb76d99
FW
484{
485 struct callchain_node *new;
486
deac911c 487 new = create_child(parent, false);
7565bd39
NK
488 if (new == NULL)
489 return NULL;
490
8451cbb9
NK
491 if (fill_node(new, cursor) < 0) {
492 struct callchain_list *call, *tmp;
493
494 list_for_each_entry_safe(call, tmp, &new->val, list) {
495 list_del(&call->list);
9c68ae98 496 map__zput(call->ms.map);
8451cbb9
NK
497 free(call);
498 }
499 free(new);
500 return NULL;
501 }
8cb76d99 502
1953287b 503 new->children_hit = 0;
108553e1 504 new->hit = period;
5e47f8ff
NK
505 new->children_count = 0;
506 new->count = 1;
e369517c
NK
507 return new;
508}
509
2d713b80
NK
510enum match_result {
511 MATCH_ERROR = -1,
512 MATCH_EQ,
513 MATCH_LT,
514 MATCH_GT,
515};
516
5dfa210e
MW
517static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
518 struct callchain_list *cnode)
519{
520 char *left = get_srcline(cnode->ms.map->dso,
521 map__rip_2objdump(cnode->ms.map, cnode->ip),
522 cnode->ms.sym, true, false);
523 char *right = get_srcline(node->map->dso,
524 map__rip_2objdump(node->map, node->ip),
525 node->sym, true, false);
526 enum match_result ret = MATCH_EQ;
527 int cmp;
528
529 if (left && right)
530 cmp = strcmp(left, right);
531 else if (!left && right)
532 cmp = 1;
533 else if (left && !right)
534 cmp = -1;
535 else if (cnode->ip == node->ip)
536 cmp = 0;
537 else
538 cmp = (cnode->ip < node->ip) ? -1 : 1;
539
540 if (cmp != 0)
541 ret = cmp < 0 ? MATCH_LT : MATCH_GT;
542
543 free_srcline(left);
544 free_srcline(right);
545 return ret;
546}
547
2d713b80
NK
548static enum match_result match_chain(struct callchain_cursor_node *node,
549 struct callchain_list *cnode)
e369517c
NK
550{
551 struct symbol *sym = node->sym;
2d713b80 552 u64 left, right;
e369517c 553
5dfa210e
MW
554 if (callchain_param.key == CCKEY_SRCLINE) {
555 enum match_result match = match_chain_srcline(node, cnode);
556
557 if (match != MATCH_ERROR)
558 return match;
559 }
560
561 if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
2d713b80
NK
562 left = cnode->ms.sym->start;
563 right = sym->start;
564 } else {
565 left = cnode->ip;
566 right = node->ip;
567 }
568
3dd029ef
JY
569 if (left == right) {
570 if (node->branch) {
571 cnode->branch_count++;
572
573 if (node->branch_flags.predicted)
574 cnode->predicted_count++;
575
576 if (node->branch_flags.abort)
577 cnode->abort_count++;
578
579 cnode->cycles_count += node->branch_flags.cycles;
580 cnode->iter_count += node->nr_loop_iter;
581 cnode->samples_count += node->samples;
582 }
583
2d713b80 584 return MATCH_EQ;
3dd029ef 585 }
2d713b80
NK
586
587 return left > right ? MATCH_GT : MATCH_LT;
8cb76d99
FW
588}
589
deac911c
FW
590/*
591 * Split the parent in two parts (a new child is created) and
592 * give a part of its callchain to the created child.
593 * Then create another child to host the given callchain of new branch
594 */
f2bb4c5a 595static int
1b3a0e95
FW
596split_add_child(struct callchain_node *parent,
597 struct callchain_cursor *cursor,
598 struct callchain_list *to_split,
599 u64 idx_parents, u64 idx_local, u64 period)
8cb76d99
FW
600{
601 struct callchain_node *new;
deac911c 602 struct list_head *old_tail;
f37a291c 603 unsigned int idx_total = idx_parents + idx_local;
8cb76d99
FW
604
605 /* split */
deac911c 606 new = create_child(parent, true);
f2bb4c5a
NK
607 if (new == NULL)
608 return -1;
deac911c
FW
609
610 /* split the callchain and move a part to the new child */
611 old_tail = parent->val.prev;
612 list_del_range(&to_split->list, old_tail);
613 new->val.next = &to_split->list;
614 new->val.prev = old_tail;
615 to_split->list.prev = &new->val;
616 old_tail->next = &new->val;
8cb76d99 617
deac911c
FW
618 /* split the hits */
619 new->hit = parent->hit;
1953287b 620 new->children_hit = parent->children_hit;
f08c3154 621 parent->children_hit = callchain_cumul_hits(new);
deac911c
FW
622 new->val_nr = parent->val_nr - idx_local;
623 parent->val_nr = idx_local;
5e47f8ff
NK
624 new->count = parent->count;
625 new->children_count = parent->children_count;
626 parent->children_count = callchain_cumul_counts(new);
deac911c
FW
627
628 /* create a new child for the new branch if any */
1b3a0e95 629 if (idx_total < cursor->nr) {
e369517c
NK
630 struct callchain_node *first;
631 struct callchain_list *cnode;
632 struct callchain_cursor_node *node;
633 struct rb_node *p, **pp;
634
deac911c 635 parent->hit = 0;
108553e1 636 parent->children_hit += period;
5e47f8ff
NK
637 parent->count = 0;
638 parent->children_count += 1;
e369517c
NK
639
640 node = callchain_cursor_current(cursor);
641 new = add_child(parent, cursor, period);
7565bd39 642 if (new == NULL)
f2bb4c5a 643 return -1;
e369517c
NK
644
645 /*
646 * This is second child since we moved parent's children
647 * to new (first) child above.
648 */
649 p = parent->rb_root_in.rb_node;
650 first = rb_entry(p, struct callchain_node, rb_node_in);
651 cnode = list_first_entry(&first->val, struct callchain_list,
652 list);
653
2d713b80 654 if (match_chain(node, cnode) == MATCH_LT)
e369517c
NK
655 pp = &p->rb_left;
656 else
657 pp = &p->rb_right;
658
659 rb_link_node(&new->rb_node_in, p, pp);
660 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
deac911c 661 } else {
108553e1 662 parent->hit = period;
5e47f8ff 663 parent->count = 1;
deac911c 664 }
f2bb4c5a 665 return 0;
8cb76d99
FW
666}
667
2d713b80 668static enum match_result
1b3a0e95
FW
669append_chain(struct callchain_node *root,
670 struct callchain_cursor *cursor,
671 u64 period);
8cb76d99 672
dca0d122 673static int
1b3a0e95
FW
674append_chain_children(struct callchain_node *root,
675 struct callchain_cursor *cursor,
676 u64 period)
8cb76d99
FW
677{
678 struct callchain_node *rnode;
e369517c
NK
679 struct callchain_cursor_node *node;
680 struct rb_node **p = &root->rb_root_in.rb_node;
681 struct rb_node *parent = NULL;
682
683 node = callchain_cursor_current(cursor);
684 if (!node)
dca0d122 685 return -1;
8cb76d99
FW
686
687 /* lookup in childrens */
e369517c 688 while (*p) {
2d713b80 689 enum match_result ret;
f37a291c 690
e369517c
NK
691 parent = *p;
692 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
e369517c 693
b965bb41
FW
694 /* If at least first entry matches, rely to children */
695 ret = append_chain(rnode, cursor, period);
2d713b80 696 if (ret == MATCH_EQ)
1953287b 697 goto inc_children_hit;
dca0d122
NK
698 if (ret == MATCH_ERROR)
699 return -1;
e369517c 700
2d713b80 701 if (ret == MATCH_LT)
e369517c
NK
702 p = &parent->rb_left;
703 else
704 p = &parent->rb_right;
8cb76d99 705 }
deac911c 706 /* nothing in children, add to the current node */
e369517c 707 rnode = add_child(root, cursor, period);
7565bd39 708 if (rnode == NULL)
dca0d122 709 return -1;
7565bd39 710
e369517c
NK
711 rb_link_node(&rnode->rb_node_in, parent, p);
712 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
e05b876c 713
1953287b 714inc_children_hit:
108553e1 715 root->children_hit += period;
5e47f8ff 716 root->children_count++;
dca0d122 717 return 0;
8cb76d99
FW
718}
719
2d713b80 720static enum match_result
1b3a0e95
FW
721append_chain(struct callchain_node *root,
722 struct callchain_cursor *cursor,
723 u64 period)
8cb76d99
FW
724{
725 struct callchain_list *cnode;
1b3a0e95 726 u64 start = cursor->pos;
8cb76d99 727 bool found = false;
1b3a0e95 728 u64 matches;
2d713b80 729 enum match_result cmp = MATCH_ERROR;
8cb76d99 730
deac911c
FW
731 /*
732 * Lookup in the current node
733 * If we have a symbol, then compare the start to match
99571ab3
AK
734 * anywhere inside a function, unless function
735 * mode is disabled.
deac911c 736 */
8cb76d99 737 list_for_each_entry(cnode, &root->val, list) {
1b3a0e95 738 struct callchain_cursor_node *node;
301fde27 739
1b3a0e95
FW
740 node = callchain_cursor_current(cursor);
741 if (!node)
deac911c 742 break;
301fde27 743
b965bb41 744 cmp = match_chain(node, cnode);
2d713b80 745 if (cmp != MATCH_EQ)
8cb76d99 746 break;
301fde27 747
e369517c 748 found = true;
1b3a0e95
FW
749
750 callchain_cursor_advance(cursor);
8cb76d99
FW
751 }
752
e369517c 753 /* matches not, relay no the parent */
1b3a0e95 754 if (!found) {
2d713b80 755 WARN_ONCE(cmp == MATCH_ERROR, "Chain comparison error\n");
b965bb41 756 return cmp;
1b3a0e95
FW
757 }
758
759 matches = cursor->pos - start;
8cb76d99
FW
760
761 /* we match only a part of the node. Split it and add the new chain */
1b3a0e95 762 if (matches < root->val_nr) {
f2bb4c5a
NK
763 if (split_add_child(root, cursor, cnode, start, matches,
764 period) < 0)
765 return MATCH_ERROR;
766
2d713b80 767 return MATCH_EQ;
8cb76d99
FW
768 }
769
770 /* we match 100% of the path, increment the hit */
1b3a0e95 771 if (matches == root->val_nr && cursor->pos == cursor->nr) {
108553e1 772 root->hit += period;
5e47f8ff 773 root->count++;
2d713b80 774 return MATCH_EQ;
8cb76d99
FW
775 }
776
deac911c 777 /* We match the node and still have a part remaining */
dca0d122
NK
778 if (append_chain_children(root, cursor, period) < 0)
779 return MATCH_ERROR;
deac911c 780
2d713b80 781 return MATCH_EQ;
8cb76d99
FW
782}
783
1b3a0e95
FW
784int callchain_append(struct callchain_root *root,
785 struct callchain_cursor *cursor,
786 u64 period)
8cb76d99 787{
1b3a0e95 788 if (!cursor->nr)
301fde27
FW
789 return 0;
790
1b3a0e95 791 callchain_cursor_commit(cursor);
301fde27 792
dca0d122
NK
793 if (append_chain_children(&root->node, cursor, period) < 0)
794 return -1;
d2009c51 795
1b3a0e95
FW
796 if (cursor->nr > root->max_depth)
797 root->max_depth = cursor->nr;
301fde27
FW
798
799 return 0;
8cb76d99 800}
612d4fd7
FW
801
802static int
1b3a0e95
FW
803merge_chain_branch(struct callchain_cursor *cursor,
804 struct callchain_node *dst, struct callchain_node *src)
612d4fd7 805{
1b3a0e95 806 struct callchain_cursor_node **old_last = cursor->last;
e369517c 807 struct callchain_node *child;
612d4fd7 808 struct callchain_list *list, *next_list;
e369517c 809 struct rb_node *n;
1b3a0e95 810 int old_pos = cursor->nr;
612d4fd7
FW
811 int err = 0;
812
813 list_for_each_entry_safe(list, next_list, &src->val, list) {
1b3a0e95 814 callchain_cursor_append(cursor, list->ip,
410024db
JY
815 list->ms.map, list->ms.sym,
816 false, NULL, 0, 0);
612d4fd7 817 list_del(&list->list);
9c68ae98 818 map__zput(list->ms.map);
612d4fd7
FW
819 free(list);
820 }
821
1b3a0e95
FW
822 if (src->hit) {
823 callchain_cursor_commit(cursor);
dca0d122
NK
824 if (append_chain_children(dst, cursor, src->hit) < 0)
825 return -1;
1b3a0e95 826 }
612d4fd7 827
e369517c
NK
828 n = rb_first(&src->rb_root_in);
829 while (n) {
830 child = container_of(n, struct callchain_node, rb_node_in);
831 n = rb_next(n);
832 rb_erase(&child->rb_node_in, &src->rb_root_in);
833
1b3a0e95 834 err = merge_chain_branch(cursor, dst, child);
612d4fd7
FW
835 if (err)
836 break;
837
612d4fd7
FW
838 free(child);
839 }
840
1b3a0e95
FW
841 cursor->nr = old_pos;
842 cursor->last = old_last;
612d4fd7
FW
843
844 return err;
845}
846
1b3a0e95
FW
847int callchain_merge(struct callchain_cursor *cursor,
848 struct callchain_root *dst, struct callchain_root *src)
849{
850 return merge_chain_branch(cursor, &dst->node, &src->node);
851}
852
853int callchain_cursor_append(struct callchain_cursor *cursor,
410024db
JY
854 u64 ip, struct map *map, struct symbol *sym,
855 bool branch, struct branch_flags *flags,
856 int nr_loop_iter, int samples)
612d4fd7 857{
1b3a0e95 858 struct callchain_cursor_node *node = *cursor->last;
612d4fd7 859
1b3a0e95 860 if (!node) {
91b98804 861 node = calloc(1, sizeof(*node));
1b3a0e95
FW
862 if (!node)
863 return -ENOMEM;
612d4fd7 864
1b3a0e95
FW
865 *cursor->last = node;
866 }
612d4fd7 867
1b3a0e95 868 node->ip = ip;
9c68ae98
KJ
869 map__zput(node->map);
870 node->map = map__get(map);
1b3a0e95 871 node->sym = sym;
410024db
JY
872 node->branch = branch;
873 node->nr_loop_iter = nr_loop_iter;
874 node->samples = samples;
875
876 if (flags)
877 memcpy(&node->branch_flags, flags,
878 sizeof(struct branch_flags));
612d4fd7 879
1b3a0e95 880 cursor->nr++;
612d4fd7 881
1b3a0e95
FW
882 cursor->last = &node->next;
883
884 return 0;
612d4fd7 885}
2dc9fb1a 886
91d7b2de
ACM
887int sample__resolve_callchain(struct perf_sample *sample,
888 struct callchain_cursor *cursor, struct symbol **parent,
2dc9fb1a
NK
889 struct perf_evsel *evsel, struct addr_location *al,
890 int max_stack)
891{
892 if (sample->callchain == NULL)
893 return 0;
894
7a13aa28 895 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
de7e6a7c 896 perf_hpp_list.parent) {
91d7b2de 897 return thread__resolve_callchain(al->thread, cursor, evsel, sample,
cc8b7c2b 898 parent, al, max_stack);
2dc9fb1a
NK
899 }
900 return 0;
901}
902
903int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
904{
4d40b051 905 if (!symbol_conf.use_callchain || sample->callchain == NULL)
2dc9fb1a
NK
906 return 0;
907 return callchain_append(he->callchain, &callchain_cursor, sample->period);
908}
c7405d85
NK
909
910int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
911 bool hide_unresolved)
912{
913 al->map = node->map;
914 al->sym = node->sym;
915 if (node->map)
916 al->addr = node->map->map_ip(node->map, node->ip);
917 else
918 al->addr = node->ip;
919
920 if (al->sym == NULL) {
921 if (hide_unresolved)
922 return 0;
923 if (al->map == NULL)
924 goto out;
925 }
926
927 if (al->map->groups == &al->machine->kmaps) {
928 if (machine__is_host(al->machine)) {
929 al->cpumode = PERF_RECORD_MISC_KERNEL;
930 al->level = 'k';
931 } else {
932 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
933 al->level = 'g';
934 }
935 } else {
936 if (machine__is_host(al->machine)) {
937 al->cpumode = PERF_RECORD_MISC_USER;
938 al->level = '.';
939 } else if (perf_guest) {
940 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
941 al->level = 'u';
942 } else {
943 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
944 al->level = 'H';
945 }
946 }
947
948out:
949 return 1;
950}
2989ccaa
AK
951
952char *callchain_list__sym_name(struct callchain_list *cl,
953 char *bf, size_t bfsize, bool show_dso)
954{
5dfa210e
MW
955 bool show_addr = callchain_param.key == CCKEY_ADDRESS;
956 bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE;
2989ccaa
AK
957 int printed;
958
959 if (cl->ms.sym) {
5dfa210e 960 if (show_srcline && cl->ms.map && !cl->srcline)
23f0981b
AK
961 cl->srcline = get_srcline(cl->ms.map->dso,
962 map__rip_2objdump(cl->ms.map,
85c116a6 963 cl->ip),
5dfa210e 964 cl->ms.sym, false, show_addr);
23f0981b
AK
965 if (cl->srcline)
966 printed = scnprintf(bf, bfsize, "%s %s",
967 cl->ms.sym->name, cl->srcline);
968 else
969 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
2989ccaa
AK
970 } else
971 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
972
973 if (show_dso)
974 scnprintf(bf + printed, bfsize - printed, " %s",
975 cl->ms.map ?
976 cl->ms.map->dso->short_name :
977 "unknown");
978
979 return bf;
980}
d114960c 981
5ab250ca
NK
982char *callchain_node__scnprintf_value(struct callchain_node *node,
983 char *bf, size_t bfsize, u64 total)
984{
985 double percent = 0.0;
986 u64 period = callchain_cumul_hits(node);
f2af0086 987 unsigned count = callchain_cumul_counts(node);
5ab250ca 988
f2af0086 989 if (callchain_param.mode == CHAIN_FOLDED) {
5ab250ca 990 period = node->hit;
f2af0086
NK
991 count = node->count;
992 }
5ab250ca 993
f2af0086
NK
994 switch (callchain_param.value) {
995 case CCVAL_PERIOD:
996 scnprintf(bf, bfsize, "%"PRIu64, period);
997 break;
998 case CCVAL_COUNT:
999 scnprintf(bf, bfsize, "%u", count);
1000 break;
1001 case CCVAL_PERCENT:
1002 default:
1003 if (total)
1004 percent = period * 100.0 / total;
1005 scnprintf(bf, bfsize, "%.2f%%", percent);
1006 break;
1007 }
5ab250ca
NK
1008 return bf;
1009}
1010
1011int callchain_node__fprintf_value(struct callchain_node *node,
1012 FILE *fp, u64 total)
1013{
1014 double percent = 0.0;
1015 u64 period = callchain_cumul_hits(node);
f2af0086 1016 unsigned count = callchain_cumul_counts(node);
5ab250ca 1017
f2af0086 1018 if (callchain_param.mode == CHAIN_FOLDED) {
5ab250ca 1019 period = node->hit;
f2af0086
NK
1020 count = node->count;
1021 }
5ab250ca 1022
f2af0086
NK
1023 switch (callchain_param.value) {
1024 case CCVAL_PERIOD:
1025 return fprintf(fp, "%"PRIu64, period);
1026 case CCVAL_COUNT:
1027 return fprintf(fp, "%u", count);
1028 case CCVAL_PERCENT:
1029 default:
1030 if (total)
1031 percent = period * 100.0 / total;
1032 return percent_color_fprintf(fp, "%.2f%%", percent);
1033 }
1034 return 0;
5ab250ca
NK
1035}
1036
3dd029ef
JY
1037static void callchain_counts_value(struct callchain_node *node,
1038 u64 *branch_count, u64 *predicted_count,
1039 u64 *abort_count, u64 *cycles_count)
1040{
1041 struct callchain_list *clist;
1042
1043 list_for_each_entry(clist, &node->val, list) {
1044 if (branch_count)
1045 *branch_count += clist->branch_count;
1046
1047 if (predicted_count)
1048 *predicted_count += clist->predicted_count;
1049
1050 if (abort_count)
1051 *abort_count += clist->abort_count;
1052
1053 if (cycles_count)
1054 *cycles_count += clist->cycles_count;
1055 }
1056}
1057
1058static int callchain_node_branch_counts_cumul(struct callchain_node *node,
1059 u64 *branch_count,
1060 u64 *predicted_count,
1061 u64 *abort_count,
1062 u64 *cycles_count)
1063{
1064 struct callchain_node *child;
1065 struct rb_node *n;
1066
1067 n = rb_first(&node->rb_root_in);
1068 while (n) {
1069 child = rb_entry(n, struct callchain_node, rb_node_in);
1070 n = rb_next(n);
1071
1072 callchain_node_branch_counts_cumul(child, branch_count,
1073 predicted_count,
1074 abort_count,
1075 cycles_count);
1076
1077 callchain_counts_value(child, branch_count,
1078 predicted_count, abort_count,
1079 cycles_count);
1080 }
1081
1082 return 0;
1083}
1084
1085int callchain_branch_counts(struct callchain_root *root,
1086 u64 *branch_count, u64 *predicted_count,
1087 u64 *abort_count, u64 *cycles_count)
1088{
1089 if (branch_count)
1090 *branch_count = 0;
1091
1092 if (predicted_count)
1093 *predicted_count = 0;
1094
1095 if (abort_count)
1096 *abort_count = 0;
1097
1098 if (cycles_count)
1099 *cycles_count = 0;
1100
1101 return callchain_node_branch_counts_cumul(&root->node,
1102 branch_count,
1103 predicted_count,
1104 abort_count,
1105 cycles_count);
1106}
1107
c1dfcfad
JY
1108static int counts_str_build(char *bf, int bfsize,
1109 u64 branch_count, u64 predicted_count,
1110 u64 abort_count, u64 cycles_count,
1111 u64 iter_count, u64 samples_count)
3dd029ef
JY
1112{
1113 double predicted_percent = 0.0;
1114 const char *null_str = "";
1115 char iter_str[32];
c1dfcfad
JY
1116 char cycle_str[32];
1117 char *istr, *cstr;
1118 u64 cycles;
3dd029ef 1119
c1dfcfad 1120 if (branch_count == 0)
3dd029ef 1121 return scnprintf(bf, bfsize, " (calltrace)");
c1dfcfad
JY
1122
1123 cycles = cycles_count / branch_count;
3dd029ef
JY
1124
1125 if (iter_count && samples_count) {
c1dfcfad
JY
1126 if (cycles > 0)
1127 scnprintf(iter_str, sizeof(iter_str),
1128 " iterations:%" PRId64 "",
1129 iter_count / samples_count);
1130 else
1131 scnprintf(iter_str, sizeof(iter_str),
1132 "iterations:%" PRId64 "",
1133 iter_count / samples_count);
1134 istr = iter_str;
1135 } else
1136 istr = (char *)null_str;
1137
1138 if (cycles > 0) {
1139 scnprintf(cycle_str, sizeof(cycle_str),
1140 "cycles:%" PRId64 "", cycles);
1141 cstr = cycle_str;
3dd029ef 1142 } else
c1dfcfad 1143 cstr = (char *)null_str;
3dd029ef
JY
1144
1145 predicted_percent = predicted_count * 100.0 / branch_count;
3dd029ef 1146
c1dfcfad
JY
1147 if ((predicted_count == branch_count) && (abort_count == 0)) {
1148 if ((cycles > 0) || (istr != (char *)null_str))
1149 return scnprintf(bf, bfsize, " (%s%s)", cstr, istr);
1150 else
1151 return scnprintf(bf, bfsize, "%s", (char *)null_str);
1152 }
3dd029ef 1153
c1dfcfad
JY
1154 if ((predicted_count < branch_count) && (abort_count == 0)) {
1155 if ((cycles > 0) || (istr != (char *)null_str))
1156 return scnprintf(bf, bfsize,
1157 " (predicted:%.1f%% %s%s)",
1158 predicted_percent, cstr, istr);
1159 else {
1160 return scnprintf(bf, bfsize,
1161 " (predicted:%.1f%%)",
1162 predicted_percent);
1163 }
3dd029ef
JY
1164 }
1165
c1dfcfad
JY
1166 if ((predicted_count == branch_count) && (abort_count > 0)) {
1167 if ((cycles > 0) || (istr != (char *)null_str))
1168 return scnprintf(bf, bfsize,
1169 " (abort:%" PRId64 " %s%s)",
1170 abort_count, cstr, istr);
1171 else
1172 return scnprintf(bf, bfsize,
1173 " (abort:%" PRId64 ")",
1174 abort_count);
1175 }
3dd029ef 1176
c1dfcfad 1177 if ((cycles > 0) || (istr != (char *)null_str))
3dd029ef 1178 return scnprintf(bf, bfsize,
c1dfcfad
JY
1179 " (predicted:%.1f%% abort:%" PRId64 " %s%s)",
1180 predicted_percent, abort_count, cstr, istr);
1181
1182 return scnprintf(bf, bfsize,
1183 " (predicted:%.1f%% abort:%" PRId64 ")",
1184 predicted_percent, abort_count);
1185}
1186
1187static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
1188 u64 branch_count, u64 predicted_count,
1189 u64 abort_count, u64 cycles_count,
1190 u64 iter_count, u64 samples_count)
1191{
1192 char str[128];
1193
1194 counts_str_build(str, sizeof(str), branch_count,
1195 predicted_count, abort_count, cycles_count,
1196 iter_count, samples_count);
3dd029ef
JY
1197
1198 if (fp)
c1dfcfad 1199 return fprintf(fp, "%s", str);
3dd029ef 1200
c1dfcfad 1201 return scnprintf(bf, bfsize, "%s", str);
3dd029ef
JY
1202}
1203
1204int callchain_list_counts__printf_value(struct callchain_node *node,
1205 struct callchain_list *clist,
1206 FILE *fp, char *bf, int bfsize)
1207{
1208 u64 branch_count, predicted_count;
1209 u64 abort_count, cycles_count;
1210 u64 iter_count = 0, samples_count = 0;
1211
1212 branch_count = clist->branch_count;
1213 predicted_count = clist->predicted_count;
1214 abort_count = clist->abort_count;
1215 cycles_count = clist->cycles_count;
1216
1217 if (node) {
1218 struct callchain_list *call;
1219
1220 list_for_each_entry(call, &node->val, list) {
1221 iter_count += call->iter_count;
1222 samples_count += call->samples_count;
1223 }
1224 }
1225
1226 return callchain_counts_printf(fp, bf, bfsize, branch_count,
1227 predicted_count, abort_count,
1228 cycles_count, iter_count, samples_count);
1229}
1230
d114960c
NK
1231static void free_callchain_node(struct callchain_node *node)
1232{
1233 struct callchain_list *list, *tmp;
1234 struct callchain_node *child;
1235 struct rb_node *n;
1236
4b3a3212
NK
1237 list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
1238 list_del(&list->list);
9c68ae98 1239 map__zput(list->ms.map);
4b3a3212
NK
1240 free(list);
1241 }
1242
d114960c
NK
1243 list_for_each_entry_safe(list, tmp, &node->val, list) {
1244 list_del(&list->list);
9c68ae98 1245 map__zput(list->ms.map);
d114960c
NK
1246 free(list);
1247 }
1248
1249 n = rb_first(&node->rb_root_in);
1250 while (n) {
1251 child = container_of(n, struct callchain_node, rb_node_in);
1252 n = rb_next(n);
1253 rb_erase(&child->rb_node_in, &node->rb_root_in);
1254
1255 free_callchain_node(child);
1256 free(child);
1257 }
1258}
1259
1260void free_callchain(struct callchain_root *root)
1261{
1262 if (!symbol_conf.use_callchain)
1263 return;
1264
1265 free_callchain_node(&root->node);
1266}
4b3a3212 1267
42b276a2
NK
1268static u64 decay_callchain_node(struct callchain_node *node)
1269{
1270 struct callchain_node *child;
1271 struct rb_node *n;
1272 u64 child_hits = 0;
1273
1274 n = rb_first(&node->rb_root_in);
1275 while (n) {
1276 child = container_of(n, struct callchain_node, rb_node_in);
1277
1278 child_hits += decay_callchain_node(child);
1279 n = rb_next(n);
1280 }
1281
1282 node->hit = (node->hit * 7) / 8;
1283 node->children_hit = child_hits;
1284
1285 return node->hit;
1286}
1287
1288void decay_callchain(struct callchain_root *root)
1289{
1290 if (!symbol_conf.use_callchain)
1291 return;
1292
1293 decay_callchain_node(&root->node);
1294}
1295
4b3a3212
NK
1296int callchain_node__make_parent_list(struct callchain_node *node)
1297{
1298 struct callchain_node *parent = node->parent;
1299 struct callchain_list *chain, *new;
1300 LIST_HEAD(head);
1301
1302 while (parent) {
1303 list_for_each_entry_reverse(chain, &parent->val, list) {
1304 new = malloc(sizeof(*new));
1305 if (new == NULL)
1306 goto out;
1307 *new = *chain;
1308 new->has_children = false;
9c68ae98 1309 map__get(new->ms.map);
4b3a3212
NK
1310 list_add_tail(&new->list, &head);
1311 }
1312 parent = parent->parent;
1313 }
1314
1315 list_for_each_entry_safe_reverse(chain, new, &head, list)
1316 list_move_tail(&chain->list, &node->parent_val);
1317
1318 if (!list_empty(&node->parent_val)) {
1319 chain = list_first_entry(&node->parent_val, struct callchain_list, list);
1320 chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
1321
1322 chain = list_first_entry(&node->val, struct callchain_list, list);
1323 chain->has_children = false;
1324 }
1325 return 0;
1326
1327out:
1328 list_for_each_entry_safe(chain, new, &head, list) {
1329 list_del(&chain->list);
9c68ae98 1330 map__zput(chain->ms.map);
4b3a3212
NK
1331 free(chain);
1332 }
1333 return -ENOMEM;
1334}
571f1eb9
NK
1335
1336int callchain_cursor__copy(struct callchain_cursor *dst,
1337 struct callchain_cursor *src)
1338{
1339 int rc = 0;
1340
1341 callchain_cursor_reset(dst);
1342 callchain_cursor_commit(src);
1343
1344 while (true) {
1345 struct callchain_cursor_node *node;
1346
1347 node = callchain_cursor_current(src);
1348 if (node == NULL)
1349 break;
1350
1351 rc = callchain_cursor_append(dst, node->ip, node->map, node->sym,
1352 node->branch, &node->branch_flags,
1353 node->nr_loop_iter, node->samples);
1354 if (rc)
1355 break;
1356
1357 callchain_cursor_advance(src);
1358 }
1359
1360 return rc;
1361}