blob: 9f7106a8d9a48cb6f9600beac10bfa3a38bd9be5 [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
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030018#include "util.h"
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020019#include "callchain.h"
20
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020021bool ip_callchain__valid(struct ip_callchain *chain,
22 const union perf_event *event)
Arnaldo Carvalho de Melo139633c2010-05-09 11:47:13 -030023{
24 unsigned int chain_size = event->header.size;
25 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
26 return chain->nr * sizeof(u64) <= chain_size;
27}
28
Frederic Weisbecker14f46542009-07-02 17:58:19 +020029#define chain_for_each_child(child, parent) \
Frederic Weisbecker529363b2011-01-14 04:52:01 +010030 list_for_each_entry(child, &parent->children, siblings)
Frederic Weisbecker14f46542009-07-02 17:58:19 +020031
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +020032#define chain_for_each_child_safe(child, next, parent) \
Frederic Weisbecker529363b2011-01-14 04:52:01 +010033 list_for_each_entry_safe(child, next, &parent->children, siblings)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +020034
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +020035static void
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020036rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
37 enum chain_mode mode)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020038{
39 struct rb_node **p = &root->rb_node;
40 struct rb_node *parent = NULL;
41 struct callchain_node *rnode;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010042 u64 chain_cumul = callchain_cumul_hits(chain);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020043
44 while (*p) {
Frederic Weisbecker19532872009-08-07 07:11:05 +020045 u64 rnode_cumul;
46
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020047 parent = *p;
48 rnode = rb_entry(parent, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010049 rnode_cumul = callchain_cumul_hits(rnode);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020050
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020051 switch (mode) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +020052 case CHAIN_FLAT:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020053 if (rnode->hit < chain->hit)
54 p = &(*p)->rb_left;
55 else
56 p = &(*p)->rb_right;
57 break;
Frederic Weisbecker805d1272009-07-05 07:39:21 +020058 case CHAIN_GRAPH_ABS: /* Falldown */
59 case CHAIN_GRAPH_REL:
Frederic Weisbecker19532872009-08-07 07:11:05 +020060 if (rnode_cumul < chain_cumul)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020061 p = &(*p)->rb_left;
62 else
63 p = &(*p)->rb_right;
64 break;
Ingo Molnar83a09442009-08-15 12:26:57 +020065 case CHAIN_NONE:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020066 default:
67 break;
68 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020069 }
70
71 rb_link_node(&chain->rb_node, parent, p);
72 rb_insert_color(&chain->rb_node, root);
73}
74
Frederic Weisbecker805d1272009-07-05 07:39:21 +020075static void
76__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
77 u64 min_hit)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020078{
79 struct callchain_node *child;
80
Frederic Weisbecker14f46542009-07-02 17:58:19 +020081 chain_for_each_child(child, node)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020082 __sort_chain_flat(rb_root, child, min_hit);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020083
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +020084 if (node->hit && node->hit >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020085 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020086}
87
Frederic Weisbecker805d1272009-07-05 07:39:21 +020088/*
89 * Once we get every callchains from the stream, we can now
90 * sort them by hit
91 */
92static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020093sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
Frederic Weisbecker805d1272009-07-05 07:39:21 +020094 u64 min_hit, struct callchain_param *param __used)
95{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020096 __sort_chain_flat(rb_root, &root->node, min_hit);
Frederic Weisbecker805d1272009-07-05 07:39:21 +020097}
98
99static void __sort_chain_graph_abs(struct callchain_node *node,
100 u64 min_hit)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200101{
102 struct callchain_node *child;
103
104 node->rb_root = RB_ROOT;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200105
106 chain_for_each_child(child, node) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200107 __sort_chain_graph_abs(child, min_hit);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100108 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200109 rb_insert_callchain(&node->rb_root, child,
110 CHAIN_GRAPH_ABS);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200111 }
112}
113
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200114static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200115sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200116 u64 min_hit, struct callchain_param *param __used)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200117{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200118 __sort_chain_graph_abs(&chain_root->node, min_hit);
119 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200120}
121
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200122static void __sort_chain_graph_rel(struct callchain_node *node,
123 double min_percent)
124{
125 struct callchain_node *child;
126 u64 min_hit;
127
128 node->rb_root = RB_ROOT;
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +0200129 min_hit = ceil(node->children_hit * min_percent);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200130
131 chain_for_each_child(child, node) {
132 __sort_chain_graph_rel(child, min_percent);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100133 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200134 rb_insert_callchain(&node->rb_root, child,
135 CHAIN_GRAPH_REL);
136 }
137}
138
139static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200140sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200141 u64 min_hit __used, struct callchain_param *param)
142{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200143 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
144 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200145}
146
Frederic Weisbecker16537f12011-01-14 04:52:00 +0100147int callchain_register_param(struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200148{
149 switch (param->mode) {
150 case CHAIN_GRAPH_ABS:
151 param->sort = sort_chain_graph_abs;
152 break;
153 case CHAIN_GRAPH_REL:
154 param->sort = sort_chain_graph_rel;
155 break;
156 case CHAIN_FLAT:
157 param->sort = sort_chain_flat;
158 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200159 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200160 default:
161 return -1;
162 }
163 return 0;
164}
165
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200166/*
167 * Create a child for a parent. If inherit_children, then the new child
168 * will become the new parent of it's parent children
169 */
170static struct callchain_node *
171create_child(struct callchain_node *parent, bool inherit_children)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200172{
173 struct callchain_node *new;
174
Arnaldo Carvalho de Melocdd5b752010-05-10 10:56:50 -0300175 new = zalloc(sizeof(*new));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200176 if (!new) {
177 perror("not enough memory to create child for code path tree");
178 return NULL;
179 }
180 new->parent = parent;
181 INIT_LIST_HEAD(&new->children);
182 INIT_LIST_HEAD(&new->val);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200183
184 if (inherit_children) {
185 struct callchain_node *next;
186
187 list_splice(&parent->children, &new->children);
188 INIT_LIST_HEAD(&parent->children);
189
Frederic Weisbecker14f46542009-07-02 17:58:19 +0200190 chain_for_each_child(next, new)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200191 next->parent = new;
192 }
Frederic Weisbecker529363b2011-01-14 04:52:01 +0100193 list_add_tail(&new->siblings, &parent->children);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200194
195 return new;
196}
197
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300198
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200199/*
200 * Fill the node with callchain values
201 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200202static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100203fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200204{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100205 struct callchain_cursor_node *cursor_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200206
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100207 node->val_nr = cursor->nr - cursor->pos;
208 if (!node->val_nr)
209 pr_warning("Warning: empty node in callchain tree\n");
210
211 cursor_node = callchain_cursor_current(cursor);
212
213 while (cursor_node) {
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200214 struct callchain_list *call;
215
Arnaldo Carvalho de Melocdd5b752010-05-10 10:56:50 -0300216 call = zalloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200217 if (!call) {
218 perror("not enough memory for the code path tree");
219 return;
220 }
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100221 call->ip = cursor_node->ip;
222 call->ms.sym = cursor_node->sym;
223 call->ms.map = cursor_node->map;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200224 list_add_tail(&call->list, &node->val);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100225
226 callchain_cursor_advance(cursor);
227 cursor_node = callchain_cursor_current(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200228 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200229}
230
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200231static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100232add_child(struct callchain_node *parent,
233 struct callchain_cursor *cursor,
234 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200235{
236 struct callchain_node *new;
237
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200238 new = create_child(parent, false);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100239 fill_node(new, cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200240
Frederic Weisbecker19532872009-08-07 07:11:05 +0200241 new->children_hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200242 new->hit = period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200243}
244
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200245/*
246 * Split the parent in two parts (a new child is created) and
247 * give a part of its callchain to the created child.
248 * Then create another child to host the given callchain of new branch
249 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200250static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100251split_add_child(struct callchain_node *parent,
252 struct callchain_cursor *cursor,
253 struct callchain_list *to_split,
254 u64 idx_parents, u64 idx_local, u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200255{
256 struct callchain_node *new;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200257 struct list_head *old_tail;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200258 unsigned int idx_total = idx_parents + idx_local;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200259
260 /* split */
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200261 new = create_child(parent, true);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200262
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200263 /* split the callchain and move a part to the new child */
264 old_tail = parent->val.prev;
265 list_del_range(&to_split->list, old_tail);
266 new->val.next = &to_split->list;
267 new->val.prev = old_tail;
268 to_split->list.prev = &new->val;
269 old_tail->next = &new->val;
270
271 /* split the hits */
272 new->hit = parent->hit;
Frederic Weisbecker19532872009-08-07 07:11:05 +0200273 new->children_hit = parent->children_hit;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100274 parent->children_hit = callchain_cumul_hits(new);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200275 new->val_nr = parent->val_nr - idx_local;
276 parent->val_nr = idx_local;
277
278 /* create a new child for the new branch if any */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100279 if (idx_total < cursor->nr) {
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200280 parent->hit = 0;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100281 add_child(parent, cursor, period);
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200282 parent->children_hit += period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200283 } else {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200284 parent->hit = period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200285 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200286}
287
288static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100289append_chain(struct callchain_node *root,
290 struct callchain_cursor *cursor,
291 u64 period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200292
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200293static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100294append_chain_children(struct callchain_node *root,
295 struct callchain_cursor *cursor,
296 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200297{
298 struct callchain_node *rnode;
299
300 /* lookup in childrens */
Frederic Weisbecker14f46542009-07-02 17:58:19 +0200301 chain_for_each_child(rnode, root) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100302 unsigned int ret = append_chain(rnode, cursor, period);
Ingo Molnarf37a2912009-07-01 12:37:06 +0200303
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200304 if (!ret)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200305 goto inc_children_hit;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200306 }
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200307 /* nothing in children, add to the current node */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100308 add_child(root, cursor, period);
Frederic Weisbeckere05b8762009-07-05 07:39:20 +0200309
Frederic Weisbecker19532872009-08-07 07:11:05 +0200310inc_children_hit:
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200311 root->children_hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200312}
313
314static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100315append_chain(struct callchain_node *root,
316 struct callchain_cursor *cursor,
317 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200318{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100319 struct callchain_cursor_node *curr_snap = cursor->curr;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200320 struct callchain_list *cnode;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100321 u64 start = cursor->pos;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200322 bool found = false;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100323 u64 matches;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200324
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200325 /*
326 * Lookup in the current node
327 * If we have a symbol, then compare the start to match
328 * anywhere inside a function.
329 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200330 list_for_each_entry(cnode, &root->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100331 struct callchain_cursor_node *node;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300332 struct symbol *sym;
333
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100334 node = callchain_cursor_current(cursor);
335 if (!node)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200336 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300337
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100338 sym = node->sym;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300339
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300340 if (cnode->ms.sym && sym) {
341 if (cnode->ms.sym->start != sym->start)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200342 break;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100343 } else if (cnode->ip != node->ip)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200344 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300345
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200346 if (!found)
347 found = true;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100348
349 callchain_cursor_advance(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200350 }
351
352 /* matches not, relay on the parent */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100353 if (!found) {
354 cursor->curr = curr_snap;
355 cursor->pos = start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200356 return -1;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100357 }
358
359 matches = cursor->pos - start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200360
361 /* we match only a part of the node. Split it and add the new chain */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100362 if (matches < root->val_nr) {
363 split_add_child(root, cursor, cnode, start, matches, period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200364 return 0;
365 }
366
367 /* we match 100% of the path, increment the hit */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100368 if (matches == root->val_nr && cursor->pos == cursor->nr) {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200369 root->hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200370 return 0;
371 }
372
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200373 /* We match the node and still have a part remaining */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100374 append_chain_children(root, cursor, period);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200375
376 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200377}
378
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100379int callchain_append(struct callchain_root *root,
380 struct callchain_cursor *cursor,
381 u64 period)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300382{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100383 if (!cursor->nr)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300384 return 0;
385
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100386 callchain_cursor_commit(cursor);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300387
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100388 append_chain_children(&root->node, cursor, period);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300389
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100390 if (cursor->nr > root->max_depth)
391 root->max_depth = cursor->nr;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300392
393 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200394}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200395
396static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100397merge_chain_branch(struct callchain_cursor *cursor,
398 struct callchain_node *dst, struct callchain_node *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200399{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100400 struct callchain_cursor_node **old_last = cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200401 struct callchain_node *child, *next_child;
402 struct callchain_list *list, *next_list;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100403 int old_pos = cursor->nr;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200404 int err = 0;
405
406 list_for_each_entry_safe(list, next_list, &src->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100407 callchain_cursor_append(cursor, list->ip,
408 list->ms.map, list->ms.sym);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200409 list_del(&list->list);
410 free(list);
411 }
412
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100413 if (src->hit) {
414 callchain_cursor_commit(cursor);
415 append_chain_children(dst, cursor, src->hit);
416 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200417
418 chain_for_each_child_safe(child, next_child, src) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100419 err = merge_chain_branch(cursor, dst, child);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200420 if (err)
421 break;
422
Frederic Weisbecker529363b2011-01-14 04:52:01 +0100423 list_del(&child->siblings);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200424 free(child);
425 }
426
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100427 cursor->nr = old_pos;
428 cursor->last = old_last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200429
430 return err;
431}
432
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100433int callchain_merge(struct callchain_cursor *cursor,
434 struct callchain_root *dst, struct callchain_root *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200435{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100436 return merge_chain_branch(cursor, &dst->node, &src->node);
437}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200438
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100439int callchain_cursor_append(struct callchain_cursor *cursor,
440 u64 ip, struct map *map, struct symbol *sym)
441{
442 struct callchain_cursor_node *node = *cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200443
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100444 if (!node) {
445 node = calloc(sizeof(*node), 1);
446 if (!node)
447 return -ENOMEM;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200448
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100449 *cursor->last = node;
450 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200451
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100452 node->ip = ip;
453 node->map = map;
454 node->sym = sym;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200455
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100456 cursor->nr++;
457
458 cursor->last = &node->next;
459
460 return 0;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200461}