blob: e3970e3eaacf45bc7a10db4a86314c2fdd79fbb5 [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
Andi Kleen99571ab2013-07-18 15:33:57 -070018#include "hist.h"
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030019#include "util.h"
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020020#include "callchain.h"
21
Namhyung Kim47260642012-05-31 14:43:26 +090022__thread struct callchain_cursor callchain_cursor;
23
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +020024static void
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020025rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
26 enum chain_mode mode)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020027{
28 struct rb_node **p = &root->rb_node;
29 struct rb_node *parent = NULL;
30 struct callchain_node *rnode;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010031 u64 chain_cumul = callchain_cumul_hits(chain);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020032
33 while (*p) {
Frederic Weisbecker19532872009-08-07 07:11:05 +020034 u64 rnode_cumul;
35
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020036 parent = *p;
37 rnode = rb_entry(parent, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010038 rnode_cumul = callchain_cumul_hits(rnode);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020039
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020040 switch (mode) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +020041 case CHAIN_FLAT:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020042 if (rnode->hit < chain->hit)
43 p = &(*p)->rb_left;
44 else
45 p = &(*p)->rb_right;
46 break;
Frederic Weisbecker805d1272009-07-05 07:39:21 +020047 case CHAIN_GRAPH_ABS: /* Falldown */
48 case CHAIN_GRAPH_REL:
Frederic Weisbecker19532872009-08-07 07:11:05 +020049 if (rnode_cumul < chain_cumul)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020050 p = &(*p)->rb_left;
51 else
52 p = &(*p)->rb_right;
53 break;
Ingo Molnar83a09442009-08-15 12:26:57 +020054 case CHAIN_NONE:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020055 default:
56 break;
57 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020058 }
59
60 rb_link_node(&chain->rb_node, parent, p);
61 rb_insert_color(&chain->rb_node, root);
62}
63
Frederic Weisbecker805d1272009-07-05 07:39:21 +020064static void
65__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
66 u64 min_hit)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020067{
Namhyung Kime3695172013-10-11 14:15:36 +090068 struct rb_node *n;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020069 struct callchain_node *child;
70
Namhyung Kime3695172013-10-11 14:15:36 +090071 n = rb_first(&node->rb_root_in);
72 while (n) {
73 child = rb_entry(n, struct callchain_node, rb_node_in);
74 n = rb_next(n);
75
Frederic Weisbecker805d1272009-07-05 07:39:21 +020076 __sort_chain_flat(rb_root, child, min_hit);
Namhyung Kime3695172013-10-11 14:15:36 +090077 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020078
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +020079 if (node->hit && node->hit >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020080 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020081}
82
Frederic Weisbecker805d1272009-07-05 07:39:21 +020083/*
84 * Once we get every callchains from the stream, we can now
85 * sort them by hit
86 */
87static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020088sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030089 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020090{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020091 __sort_chain_flat(rb_root, &root->node, min_hit);
Frederic Weisbecker805d1272009-07-05 07:39:21 +020092}
93
94static void __sort_chain_graph_abs(struct callchain_node *node,
95 u64 min_hit)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020096{
Namhyung Kime3695172013-10-11 14:15:36 +090097 struct rb_node *n;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020098 struct callchain_node *child;
99
100 node->rb_root = RB_ROOT;
Namhyung Kime3695172013-10-11 14:15:36 +0900101 n = rb_first(&node->rb_root_in);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200102
Namhyung Kime3695172013-10-11 14:15:36 +0900103 while (n) {
104 child = rb_entry(n, struct callchain_node, rb_node_in);
105 n = rb_next(n);
106
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,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300116 u64 min_hit, struct callchain_param *param __maybe_unused)
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{
Namhyung Kime3695172013-10-11 14:15:36 +0900125 struct rb_node *n;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200126 struct callchain_node *child;
127 u64 min_hit;
128
129 node->rb_root = RB_ROOT;
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +0200130 min_hit = ceil(node->children_hit * min_percent);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200131
Namhyung Kime3695172013-10-11 14:15:36 +0900132 n = rb_first(&node->rb_root_in);
133 while (n) {
134 child = rb_entry(n, struct callchain_node, rb_node_in);
135 n = rb_next(n);
136
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200137 __sort_chain_graph_rel(child, min_percent);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100138 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200139 rb_insert_callchain(&node->rb_root, child,
140 CHAIN_GRAPH_REL);
141 }
142}
143
144static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200145sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300146 u64 min_hit __maybe_unused, struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200147{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200148 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
149 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200150}
151
Frederic Weisbecker16537f12011-01-14 04:52:00 +0100152int callchain_register_param(struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200153{
154 switch (param->mode) {
155 case CHAIN_GRAPH_ABS:
156 param->sort = sort_chain_graph_abs;
157 break;
158 case CHAIN_GRAPH_REL:
159 param->sort = sort_chain_graph_rel;
160 break;
161 case CHAIN_FLAT:
162 param->sort = sort_chain_flat;
163 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200164 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200165 default:
166 return -1;
167 }
168 return 0;
169}
170
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200171/*
172 * Create a child for a parent. If inherit_children, then the new child
173 * will become the new parent of it's parent children
174 */
175static struct callchain_node *
176create_child(struct callchain_node *parent, bool inherit_children)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200177{
178 struct callchain_node *new;
179
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300180 new = zalloc(sizeof(*new));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200181 if (!new) {
182 perror("not enough memory to create child for code path tree");
183 return NULL;
184 }
185 new->parent = parent;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200186 INIT_LIST_HEAD(&new->val);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200187
188 if (inherit_children) {
Namhyung Kime3695172013-10-11 14:15:36 +0900189 struct rb_node *n;
190 struct callchain_node *child;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200191
Namhyung Kime3695172013-10-11 14:15:36 +0900192 new->rb_root_in = parent->rb_root_in;
193 parent->rb_root_in = RB_ROOT;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200194
Namhyung Kime3695172013-10-11 14:15:36 +0900195 n = rb_first(&new->rb_root_in);
196 while (n) {
197 child = rb_entry(n, struct callchain_node, rb_node_in);
198 child->parent = new;
199 n = rb_next(n);
200 }
201
202 /* make it the first child */
203 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
204 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200205 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200206
207 return new;
208}
209
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300210
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200211/*
212 * Fill the node with callchain values
213 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200214static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100215fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200216{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100217 struct callchain_cursor_node *cursor_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200218
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100219 node->val_nr = cursor->nr - cursor->pos;
220 if (!node->val_nr)
221 pr_warning("Warning: empty node in callchain tree\n");
222
223 cursor_node = callchain_cursor_current(cursor);
224
225 while (cursor_node) {
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200226 struct callchain_list *call;
227
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300228 call = zalloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200229 if (!call) {
230 perror("not enough memory for the code path tree");
231 return;
232 }
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100233 call->ip = cursor_node->ip;
234 call->ms.sym = cursor_node->sym;
235 call->ms.map = cursor_node->map;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200236 list_add_tail(&call->list, &node->val);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100237
238 callchain_cursor_advance(cursor);
239 cursor_node = callchain_cursor_current(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200240 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200241}
242
Namhyung Kime3695172013-10-11 14:15:36 +0900243static struct callchain_node *
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100244add_child(struct callchain_node *parent,
245 struct callchain_cursor *cursor,
246 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200247{
248 struct callchain_node *new;
249
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200250 new = create_child(parent, false);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100251 fill_node(new, cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200252
Frederic Weisbecker19532872009-08-07 07:11:05 +0200253 new->children_hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200254 new->hit = period;
Namhyung Kime3695172013-10-11 14:15:36 +0900255 return new;
256}
257
258static s64 match_chain(struct callchain_cursor_node *node,
259 struct callchain_list *cnode)
260{
261 struct symbol *sym = node->sym;
262
263 if (cnode->ms.sym && sym &&
264 callchain_param.key == CCKEY_FUNCTION)
265 return cnode->ms.sym->start - sym->start;
266 else
267 return cnode->ip - node->ip;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200268}
269
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200270/*
271 * Split the parent in two parts (a new child is created) and
272 * give a part of its callchain to the created child.
273 * Then create another child to host the given callchain of new branch
274 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200275static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100276split_add_child(struct callchain_node *parent,
277 struct callchain_cursor *cursor,
278 struct callchain_list *to_split,
279 u64 idx_parents, u64 idx_local, u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200280{
281 struct callchain_node *new;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200282 struct list_head *old_tail;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200283 unsigned int idx_total = idx_parents + idx_local;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200284
285 /* split */
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200286 new = create_child(parent, true);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200287
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200288 /* split the callchain and move a part to the new child */
289 old_tail = parent->val.prev;
290 list_del_range(&to_split->list, old_tail);
291 new->val.next = &to_split->list;
292 new->val.prev = old_tail;
293 to_split->list.prev = &new->val;
294 old_tail->next = &new->val;
295
296 /* split the hits */
297 new->hit = parent->hit;
Frederic Weisbecker19532872009-08-07 07:11:05 +0200298 new->children_hit = parent->children_hit;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100299 parent->children_hit = callchain_cumul_hits(new);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200300 new->val_nr = parent->val_nr - idx_local;
301 parent->val_nr = idx_local;
302
303 /* create a new child for the new branch if any */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100304 if (idx_total < cursor->nr) {
Namhyung Kime3695172013-10-11 14:15:36 +0900305 struct callchain_node *first;
306 struct callchain_list *cnode;
307 struct callchain_cursor_node *node;
308 struct rb_node *p, **pp;
309
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200310 parent->hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200311 parent->children_hit += period;
Namhyung Kime3695172013-10-11 14:15:36 +0900312
313 node = callchain_cursor_current(cursor);
314 new = add_child(parent, cursor, period);
315
316 /*
317 * This is second child since we moved parent's children
318 * to new (first) child above.
319 */
320 p = parent->rb_root_in.rb_node;
321 first = rb_entry(p, struct callchain_node, rb_node_in);
322 cnode = list_first_entry(&first->val, struct callchain_list,
323 list);
324
325 if (match_chain(node, cnode) < 0)
326 pp = &p->rb_left;
327 else
328 pp = &p->rb_right;
329
330 rb_link_node(&new->rb_node_in, p, pp);
331 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200332 } else {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200333 parent->hit = period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200334 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200335}
336
337static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100338append_chain(struct callchain_node *root,
339 struct callchain_cursor *cursor,
340 u64 period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200341
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200342static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100343append_chain_children(struct callchain_node *root,
344 struct callchain_cursor *cursor,
345 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200346{
347 struct callchain_node *rnode;
Namhyung Kime3695172013-10-11 14:15:36 +0900348 struct callchain_cursor_node *node;
349 struct rb_node **p = &root->rb_root_in.rb_node;
350 struct rb_node *parent = NULL;
351
352 node = callchain_cursor_current(cursor);
353 if (!node)
354 return;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200355
356 /* lookup in childrens */
Namhyung Kime3695172013-10-11 14:15:36 +0900357 while (*p) {
358 s64 ret;
359 struct callchain_list *cnode;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200360
Namhyung Kime3695172013-10-11 14:15:36 +0900361 parent = *p;
362 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 cnode = list_first_entry(&rnode->val, struct callchain_list,
364 list);
365
366 /* just check first entry */
367 ret = match_chain(node, cnode);
368 if (ret == 0) {
369 append_chain(rnode, cursor, period);
Frederic Weisbecker19532872009-08-07 07:11:05 +0200370 goto inc_children_hit;
Namhyung Kime3695172013-10-11 14:15:36 +0900371 }
372
373 if (ret < 0)
374 p = &parent->rb_left;
375 else
376 p = &parent->rb_right;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200377 }
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200378 /* nothing in children, add to the current node */
Namhyung Kime3695172013-10-11 14:15:36 +0900379 rnode = add_child(root, cursor, period);
380 rb_link_node(&rnode->rb_node_in, parent, p);
381 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
Frederic Weisbeckere05b8762009-07-05 07:39:20 +0200382
Frederic Weisbecker19532872009-08-07 07:11:05 +0200383inc_children_hit:
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200384 root->children_hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200385}
386
387static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100388append_chain(struct callchain_node *root,
389 struct callchain_cursor *cursor,
390 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200391{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100392 struct callchain_cursor_node *curr_snap = cursor->curr;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200393 struct callchain_list *cnode;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100394 u64 start = cursor->pos;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200395 bool found = false;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100396 u64 matches;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200397
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200398 /*
399 * Lookup in the current node
400 * If we have a symbol, then compare the start to match
Andi Kleen99571ab2013-07-18 15:33:57 -0700401 * anywhere inside a function, unless function
402 * mode is disabled.
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200403 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200404 list_for_each_entry(cnode, &root->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100405 struct callchain_cursor_node *node;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300406
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100407 node = callchain_cursor_current(cursor);
408 if (!node)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200409 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300410
Namhyung Kime3695172013-10-11 14:15:36 +0900411 if (match_chain(node, cnode) != 0)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200412 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300413
Namhyung Kime3695172013-10-11 14:15:36 +0900414 found = true;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100415
416 callchain_cursor_advance(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200417 }
418
Namhyung Kime3695172013-10-11 14:15:36 +0900419 /* matches not, relay no the parent */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100420 if (!found) {
421 cursor->curr = curr_snap;
422 cursor->pos = start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200423 return -1;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100424 }
425
426 matches = cursor->pos - start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200427
428 /* we match only a part of the node. Split it and add the new chain */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100429 if (matches < root->val_nr) {
430 split_add_child(root, cursor, cnode, start, matches, period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200431 return 0;
432 }
433
434 /* we match 100% of the path, increment the hit */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100435 if (matches == root->val_nr && cursor->pos == cursor->nr) {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200436 root->hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200437 return 0;
438 }
439
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200440 /* We match the node and still have a part remaining */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100441 append_chain_children(root, cursor, period);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200442
443 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200444}
445
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100446int callchain_append(struct callchain_root *root,
447 struct callchain_cursor *cursor,
448 u64 period)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300449{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100450 if (!cursor->nr)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300451 return 0;
452
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100453 callchain_cursor_commit(cursor);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300454
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100455 append_chain_children(&root->node, cursor, period);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300456
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100457 if (cursor->nr > root->max_depth)
458 root->max_depth = cursor->nr;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300459
460 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200461}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200462
463static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100464merge_chain_branch(struct callchain_cursor *cursor,
465 struct callchain_node *dst, struct callchain_node *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200466{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100467 struct callchain_cursor_node **old_last = cursor->last;
Namhyung Kime3695172013-10-11 14:15:36 +0900468 struct callchain_node *child;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200469 struct callchain_list *list, *next_list;
Namhyung Kime3695172013-10-11 14:15:36 +0900470 struct rb_node *n;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100471 int old_pos = cursor->nr;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200472 int err = 0;
473
474 list_for_each_entry_safe(list, next_list, &src->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100475 callchain_cursor_append(cursor, list->ip,
476 list->ms.map, list->ms.sym);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200477 list_del(&list->list);
478 free(list);
479 }
480
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100481 if (src->hit) {
482 callchain_cursor_commit(cursor);
483 append_chain_children(dst, cursor, src->hit);
484 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200485
Namhyung Kime3695172013-10-11 14:15:36 +0900486 n = rb_first(&src->rb_root_in);
487 while (n) {
488 child = container_of(n, struct callchain_node, rb_node_in);
489 n = rb_next(n);
490 rb_erase(&child->rb_node_in, &src->rb_root_in);
491
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100492 err = merge_chain_branch(cursor, dst, child);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200493 if (err)
494 break;
495
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200496 free(child);
497 }
498
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100499 cursor->nr = old_pos;
500 cursor->last = old_last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200501
502 return err;
503}
504
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100505int callchain_merge(struct callchain_cursor *cursor,
506 struct callchain_root *dst, struct callchain_root *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200507{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100508 return merge_chain_branch(cursor, &dst->node, &src->node);
509}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200510
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100511int callchain_cursor_append(struct callchain_cursor *cursor,
512 u64 ip, struct map *map, struct symbol *sym)
513{
514 struct callchain_cursor_node *node = *cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200515
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100516 if (!node) {
Paul Gortmaker91b98802013-01-30 20:05:49 -0500517 node = calloc(1, sizeof(*node));
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100518 if (!node)
519 return -ENOMEM;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200520
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100521 *cursor->last = node;
522 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200523
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100524 node->ip = ip;
525 node->map = map;
526 node->sym = sym;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200527
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100528 cursor->nr++;
529
530 cursor->last = &node->next;
531
532 return 0;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200533}