blob: 8d9db454f1a9740c44c4136146c5c6dd308a6281 [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
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +020028static void
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020029rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
30 enum chain_mode mode)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020031{
32 struct rb_node **p = &root->rb_node;
33 struct rb_node *parent = NULL;
34 struct callchain_node *rnode;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010035 u64 chain_cumul = callchain_cumul_hits(chain);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020036
37 while (*p) {
Frederic Weisbecker19532872009-08-07 07:11:05 +020038 u64 rnode_cumul;
39
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020040 parent = *p;
41 rnode = rb_entry(parent, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +010042 rnode_cumul = callchain_cumul_hits(rnode);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020043
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020044 switch (mode) {
Frederic Weisbecker805d1272009-07-05 07:39:21 +020045 case CHAIN_FLAT:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020046 if (rnode->hit < chain->hit)
47 p = &(*p)->rb_left;
48 else
49 p = &(*p)->rb_right;
50 break;
Frederic Weisbecker805d1272009-07-05 07:39:21 +020051 case CHAIN_GRAPH_ABS: /* Falldown */
52 case CHAIN_GRAPH_REL:
Frederic Weisbecker19532872009-08-07 07:11:05 +020053 if (rnode_cumul < chain_cumul)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020054 p = &(*p)->rb_left;
55 else
56 p = &(*p)->rb_right;
57 break;
Ingo Molnar83a09442009-08-15 12:26:57 +020058 case CHAIN_NONE:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020059 default:
60 break;
61 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020062 }
63
64 rb_link_node(&chain->rb_node, parent, p);
65 rb_insert_color(&chain->rb_node, root);
66}
67
Frederic Weisbecker805d1272009-07-05 07:39:21 +020068static void
69__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
70 u64 min_hit)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020071{
Namhyung Kime3695172013-10-11 14:15:36 +090072 struct rb_node *n;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020073 struct callchain_node *child;
74
Namhyung Kime3695172013-10-11 14:15:36 +090075 n = rb_first(&node->rb_root_in);
76 while (n) {
77 child = rb_entry(n, struct callchain_node, rb_node_in);
78 n = rb_next(n);
79
Frederic Weisbecker805d1272009-07-05 07:39:21 +020080 __sort_chain_flat(rb_root, child, min_hit);
Namhyung Kime3695172013-10-11 14:15:36 +090081 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020082
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +020083 if (node->hit && node->hit >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020084 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020085}
86
Frederic Weisbecker805d1272009-07-05 07:39:21 +020087/*
88 * Once we get every callchains from the stream, we can now
89 * sort them by hit
90 */
91static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020092sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030093 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker805d1272009-07-05 07:39:21 +020094{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +020095 __sort_chain_flat(rb_root, &root->node, min_hit);
Frederic Weisbecker805d1272009-07-05 07:39:21 +020096}
97
98static void __sort_chain_graph_abs(struct callchain_node *node,
99 u64 min_hit)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200100{
Namhyung Kime3695172013-10-11 14:15:36 +0900101 struct rb_node *n;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200102 struct callchain_node *child;
103
104 node->rb_root = RB_ROOT;
Namhyung Kime3695172013-10-11 14:15:36 +0900105 n = rb_first(&node->rb_root_in);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200106
Namhyung Kime3695172013-10-11 14:15:36 +0900107 while (n) {
108 child = rb_entry(n, struct callchain_node, rb_node_in);
109 n = rb_next(n);
110
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200111 __sort_chain_graph_abs(child, min_hit);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100112 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200113 rb_insert_callchain(&node->rb_root, child,
114 CHAIN_GRAPH_ABS);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200115 }
116}
117
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200118static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200119sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300120 u64 min_hit, struct callchain_param *param __maybe_unused)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200121{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200122 __sort_chain_graph_abs(&chain_root->node, min_hit);
123 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200124}
125
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200126static void __sort_chain_graph_rel(struct callchain_node *node,
127 double min_percent)
128{
Namhyung Kime3695172013-10-11 14:15:36 +0900129 struct rb_node *n;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200130 struct callchain_node *child;
131 u64 min_hit;
132
133 node->rb_root = RB_ROOT;
Frederic Weisbeckerc0a88652009-08-09 04:19:15 +0200134 min_hit = ceil(node->children_hit * min_percent);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200135
Namhyung Kime3695172013-10-11 14:15:36 +0900136 n = rb_first(&node->rb_root_in);
137 while (n) {
138 child = rb_entry(n, struct callchain_node, rb_node_in);
139 n = rb_next(n);
140
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200141 __sort_chain_graph_rel(child, min_percent);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100142 if (callchain_cumul_hits(child) >= min_hit)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200143 rb_insert_callchain(&node->rb_root, child,
144 CHAIN_GRAPH_REL);
145 }
146}
147
148static void
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200149sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300150 u64 min_hit __maybe_unused, struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200151{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200152 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
153 rb_root->rb_node = chain_root->node.rb_root.rb_node;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200154}
155
Frederic Weisbecker16537f12011-01-14 04:52:00 +0100156int callchain_register_param(struct callchain_param *param)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200157{
158 switch (param->mode) {
159 case CHAIN_GRAPH_ABS:
160 param->sort = sort_chain_graph_abs;
161 break;
162 case CHAIN_GRAPH_REL:
163 param->sort = sort_chain_graph_rel;
164 break;
165 case CHAIN_FLAT:
166 param->sort = sort_chain_flat;
167 break;
Ingo Molnar83a09442009-08-15 12:26:57 +0200168 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200169 default:
170 return -1;
171 }
172 return 0;
173}
174
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200175/*
176 * Create a child for a parent. If inherit_children, then the new child
177 * will become the new parent of it's parent children
178 */
179static struct callchain_node *
180create_child(struct callchain_node *parent, bool inherit_children)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200181{
182 struct callchain_node *new;
183
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300184 new = zalloc(sizeof(*new));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200185 if (!new) {
186 perror("not enough memory to create child for code path tree");
187 return NULL;
188 }
189 new->parent = parent;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200190 INIT_LIST_HEAD(&new->val);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200191
192 if (inherit_children) {
Namhyung Kime3695172013-10-11 14:15:36 +0900193 struct rb_node *n;
194 struct callchain_node *child;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200195
Namhyung Kime3695172013-10-11 14:15:36 +0900196 new->rb_root_in = parent->rb_root_in;
197 parent->rb_root_in = RB_ROOT;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200198
Namhyung Kime3695172013-10-11 14:15:36 +0900199 n = rb_first(&new->rb_root_in);
200 while (n) {
201 child = rb_entry(n, struct callchain_node, rb_node_in);
202 child->parent = new;
203 n = rb_next(n);
204 }
205
206 /* make it the first child */
207 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
208 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200209 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200210
211 return new;
212}
213
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300214
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200215/*
216 * Fill the node with callchain values
217 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200218static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100219fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200220{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100221 struct callchain_cursor_node *cursor_node;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200222
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100223 node->val_nr = cursor->nr - cursor->pos;
224 if (!node->val_nr)
225 pr_warning("Warning: empty node in callchain tree\n");
226
227 cursor_node = callchain_cursor_current(cursor);
228
229 while (cursor_node) {
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200230 struct callchain_list *call;
231
Arnaldo Carvalho de Melocdd5b75b2010-05-10 10:56:50 -0300232 call = zalloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200233 if (!call) {
234 perror("not enough memory for the code path tree");
235 return;
236 }
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100237 call->ip = cursor_node->ip;
238 call->ms.sym = cursor_node->sym;
239 call->ms.map = cursor_node->map;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200240 list_add_tail(&call->list, &node->val);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100241
242 callchain_cursor_advance(cursor);
243 cursor_node = callchain_cursor_current(cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200244 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200245}
246
Namhyung Kime3695172013-10-11 14:15:36 +0900247static struct callchain_node *
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100248add_child(struct callchain_node *parent,
249 struct callchain_cursor *cursor,
250 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200251{
252 struct callchain_node *new;
253
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200254 new = create_child(parent, false);
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100255 fill_node(new, cursor);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200256
Frederic Weisbecker19532872009-08-07 07:11:05 +0200257 new->children_hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200258 new->hit = period;
Namhyung Kime3695172013-10-11 14:15:36 +0900259 return new;
260}
261
262static s64 match_chain(struct callchain_cursor_node *node,
263 struct callchain_list *cnode)
264{
265 struct symbol *sym = node->sym;
266
267 if (cnode->ms.sym && sym &&
268 callchain_param.key == CCKEY_FUNCTION)
269 return cnode->ms.sym->start - sym->start;
270 else
271 return cnode->ip - node->ip;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200272}
273
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200274/*
275 * Split the parent in two parts (a new child is created) and
276 * give a part of its callchain to the created child.
277 * Then create another child to host the given callchain of new branch
278 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200279static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100280split_add_child(struct callchain_node *parent,
281 struct callchain_cursor *cursor,
282 struct callchain_list *to_split,
283 u64 idx_parents, u64 idx_local, u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200284{
285 struct callchain_node *new;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200286 struct list_head *old_tail;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200287 unsigned int idx_total = idx_parents + idx_local;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200288
289 /* split */
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200290 new = create_child(parent, true);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200291
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200292 /* split the callchain and move a part to the new child */
293 old_tail = parent->val.prev;
294 list_del_range(&to_split->list, old_tail);
295 new->val.next = &to_split->list;
296 new->val.prev = old_tail;
297 to_split->list.prev = &new->val;
298 old_tail->next = &new->val;
299
300 /* split the hits */
301 new->hit = parent->hit;
Frederic Weisbecker19532872009-08-07 07:11:05 +0200302 new->children_hit = parent->children_hit;
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100303 parent->children_hit = callchain_cumul_hits(new);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200304 new->val_nr = parent->val_nr - idx_local;
305 parent->val_nr = idx_local;
306
307 /* create a new child for the new branch if any */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100308 if (idx_total < cursor->nr) {
Namhyung Kime3695172013-10-11 14:15:36 +0900309 struct callchain_node *first;
310 struct callchain_list *cnode;
311 struct callchain_cursor_node *node;
312 struct rb_node *p, **pp;
313
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200314 parent->hit = 0;
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200315 parent->children_hit += period;
Namhyung Kime3695172013-10-11 14:15:36 +0900316
317 node = callchain_cursor_current(cursor);
318 new = add_child(parent, cursor, period);
319
320 /*
321 * This is second child since we moved parent's children
322 * to new (first) child above.
323 */
324 p = parent->rb_root_in.rb_node;
325 first = rb_entry(p, struct callchain_node, rb_node_in);
326 cnode = list_first_entry(&first->val, struct callchain_list,
327 list);
328
329 if (match_chain(node, cnode) < 0)
330 pp = &p->rb_left;
331 else
332 pp = &p->rb_right;
333
334 rb_link_node(&new->rb_node_in, p, pp);
335 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200336 } else {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200337 parent->hit = period;
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200338 }
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200339}
340
341static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100342append_chain(struct callchain_node *root,
343 struct callchain_cursor *cursor,
344 u64 period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200345
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200346static void
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100347append_chain_children(struct callchain_node *root,
348 struct callchain_cursor *cursor,
349 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200350{
351 struct callchain_node *rnode;
Namhyung Kime3695172013-10-11 14:15:36 +0900352 struct callchain_cursor_node *node;
353 struct rb_node **p = &root->rb_root_in.rb_node;
354 struct rb_node *parent = NULL;
355
356 node = callchain_cursor_current(cursor);
357 if (!node)
358 return;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200359
360 /* lookup in childrens */
Namhyung Kime3695172013-10-11 14:15:36 +0900361 while (*p) {
362 s64 ret;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200363
Namhyung Kime3695172013-10-11 14:15:36 +0900364 parent = *p;
365 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
Namhyung Kime3695172013-10-11 14:15:36 +0900366
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100367 /* If at least first entry matches, rely to children */
368 ret = append_chain(rnode, cursor, period);
369 if (ret == 0)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200370 goto inc_children_hit;
Namhyung Kime3695172013-10-11 14:15:36 +0900371
372 if (ret < 0)
373 p = &parent->rb_left;
374 else
375 p = &parent->rb_right;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200376 }
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200377 /* nothing in children, add to the current node */
Namhyung Kime3695172013-10-11 14:15:36 +0900378 rnode = add_child(root, cursor, period);
379 rb_link_node(&rnode->rb_node_in, parent, p);
380 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
Frederic Weisbeckere05b8762009-07-05 07:39:20 +0200381
Frederic Weisbecker19532872009-08-07 07:11:05 +0200382inc_children_hit:
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200383 root->children_hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200384}
385
386static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100387append_chain(struct callchain_node *root,
388 struct callchain_cursor *cursor,
389 u64 period)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200390{
391 struct callchain_list *cnode;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100392 u64 start = cursor->pos;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200393 bool found = false;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100394 u64 matches;
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100395 int cmp = 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200396
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200397 /*
398 * Lookup in the current node
399 * If we have a symbol, then compare the start to match
Andi Kleen99571ab2013-07-18 15:33:57 -0700400 * anywhere inside a function, unless function
401 * mode is disabled.
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200402 */
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200403 list_for_each_entry(cnode, &root->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100404 struct callchain_cursor_node *node;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300405
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100406 node = callchain_cursor_current(cursor);
407 if (!node)
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200408 break;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300409
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100410 cmp = match_chain(node, cnode);
411 if (cmp)
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) {
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100421 WARN_ONCE(!cmp, "Chain comparison error\n");
Frederic Weisbeckerb965bb42014-01-14 16:37:15 +0100422 return cmp;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100423 }
424
425 matches = cursor->pos - start;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200426
427 /* we match only a part of the node. Split it and add the new chain */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100428 if (matches < root->val_nr) {
429 split_add_child(root, cursor, cnode, start, matches, period);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200430 return 0;
431 }
432
433 /* we match 100% of the path, increment the hit */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100434 if (matches == root->val_nr && cursor->pos == cursor->nr) {
Frederic Weisbecker108553e2010-07-08 03:41:46 +0200435 root->hit += period;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200436 return 0;
437 }
438
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200439 /* We match the node and still have a part remaining */
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100440 append_chain_children(root, cursor, period);
Frederic Weisbeckerdeac9112009-07-01 05:35:15 +0200441
442 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200443}
444
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100445int callchain_append(struct callchain_root *root,
446 struct callchain_cursor *cursor,
447 u64 period)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300448{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100449 if (!cursor->nr)
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300450 return 0;
451
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100452 callchain_cursor_commit(cursor);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300453
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100454 append_chain_children(&root->node, cursor, period);
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300455
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100456 if (cursor->nr > root->max_depth)
457 root->max_depth = cursor->nr;
Frederic Weisbecker301fde22010-03-22 13:09:33 -0300458
459 return 0;
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200460}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200461
462static int
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100463merge_chain_branch(struct callchain_cursor *cursor,
464 struct callchain_node *dst, struct callchain_node *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200465{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100466 struct callchain_cursor_node **old_last = cursor->last;
Namhyung Kime3695172013-10-11 14:15:36 +0900467 struct callchain_node *child;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200468 struct callchain_list *list, *next_list;
Namhyung Kime3695172013-10-11 14:15:36 +0900469 struct rb_node *n;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100470 int old_pos = cursor->nr;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200471 int err = 0;
472
473 list_for_each_entry_safe(list, next_list, &src->val, list) {
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100474 callchain_cursor_append(cursor, list->ip,
475 list->ms.map, list->ms.sym);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200476 list_del(&list->list);
477 free(list);
478 }
479
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100480 if (src->hit) {
481 callchain_cursor_commit(cursor);
482 append_chain_children(dst, cursor, src->hit);
483 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200484
Namhyung Kime3695172013-10-11 14:15:36 +0900485 n = rb_first(&src->rb_root_in);
486 while (n) {
487 child = container_of(n, struct callchain_node, rb_node_in);
488 n = rb_next(n);
489 rb_erase(&child->rb_node_in, &src->rb_root_in);
490
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100491 err = merge_chain_branch(cursor, dst, child);
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200492 if (err)
493 break;
494
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200495 free(child);
496 }
497
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100498 cursor->nr = old_pos;
499 cursor->last = old_last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200500
501 return err;
502}
503
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100504int callchain_merge(struct callchain_cursor *cursor,
505 struct callchain_root *dst, struct callchain_root *src)
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200506{
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100507 return merge_chain_branch(cursor, &dst->node, &src->node);
508}
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200509
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100510int callchain_cursor_append(struct callchain_cursor *cursor,
511 u64 ip, struct map *map, struct symbol *sym)
512{
513 struct callchain_cursor_node *node = *cursor->last;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200514
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100515 if (!node) {
Paul Gortmaker91b98802013-01-30 20:05:49 -0500516 node = calloc(1, sizeof(*node));
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100517 if (!node)
518 return -ENOMEM;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200519
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100520 *cursor->last = node;
521 }
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200522
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100523 node->ip = ip;
524 node->map = map;
525 node->sym = sym;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200526
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100527 cursor->nr++;
528
529 cursor->last = &node->next;
530
531 return 0;
Frederic Weisbecker612d4fd2010-08-22 21:10:35 +0200532}
Namhyung Kim2dc9fb12014-01-14 14:25:35 +0900533
534int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
535 struct perf_evsel *evsel, struct addr_location *al,
536 int max_stack)
537{
538 if (sample->callchain == NULL)
539 return 0;
540
541 if (symbol_conf.use_callchain || sort__has_parent) {
542 return machine__resolve_callchain(al->machine, evsel, al->thread,
543 sample, parent, al, max_stack);
544 }
545 return 0;
546}
547
548int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
549{
550 if (!symbol_conf.use_callchain)
551 return 0;
552 return callchain_append(he->callchain, &callchain_cursor, sample->period);
553}