packaging: release out (3.8.3)
[profile/ivi/kernel-adaptation-intel-automotive.git] / tools / perf / util / callchain.c
1 /*
2  * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3  *
4  * Handle the callchains from the stream in an ad-hoc radix tree and then
5  * sort them in an rbtree.
6  *
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  *
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <errno.h>
16 #include <math.h>
17
18 #include "util.h"
19 #include "callchain.h"
20
21 __thread struct callchain_cursor callchain_cursor;
22
23 bool ip_callchain__valid(struct ip_callchain *chain,
24                          const union perf_event *event)
25 {
26         unsigned int chain_size = event->header.size;
27         chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
28         return chain->nr * sizeof(u64) <= chain_size;
29 }
30
31 #define chain_for_each_child(child, parent)     \
32         list_for_each_entry(child, &parent->children, siblings)
33
34 #define chain_for_each_child_safe(child, next, parent)  \
35         list_for_each_entry_safe(child, next, &parent->children, siblings)
36
37 static void
38 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
39                     enum chain_mode mode)
40 {
41         struct rb_node **p = &root->rb_node;
42         struct rb_node *parent = NULL;
43         struct callchain_node *rnode;
44         u64 chain_cumul = callchain_cumul_hits(chain);
45
46         while (*p) {
47                 u64 rnode_cumul;
48
49                 parent = *p;
50                 rnode = rb_entry(parent, struct callchain_node, rb_node);
51                 rnode_cumul = callchain_cumul_hits(rnode);
52
53                 switch (mode) {
54                 case CHAIN_FLAT:
55                         if (rnode->hit < chain->hit)
56                                 p = &(*p)->rb_left;
57                         else
58                                 p = &(*p)->rb_right;
59                         break;
60                 case CHAIN_GRAPH_ABS: /* Falldown */
61                 case CHAIN_GRAPH_REL:
62                         if (rnode_cumul < chain_cumul)
63                                 p = &(*p)->rb_left;
64                         else
65                                 p = &(*p)->rb_right;
66                         break;
67                 case CHAIN_NONE:
68                 default:
69                         break;
70                 }
71         }
72
73         rb_link_node(&chain->rb_node, parent, p);
74         rb_insert_color(&chain->rb_node, root);
75 }
76
77 static void
78 __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
79                   u64 min_hit)
80 {
81         struct callchain_node *child;
82
83         chain_for_each_child(child, node)
84                 __sort_chain_flat(rb_root, child, min_hit);
85
86         if (node->hit && node->hit >= min_hit)
87                 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
88 }
89
90 /*
91  * Once we get every callchains from the stream, we can now
92  * sort them by hit
93  */
94 static void
95 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
96                 u64 min_hit, struct callchain_param *param __maybe_unused)
97 {
98         __sort_chain_flat(rb_root, &root->node, min_hit);
99 }
100
101 static void __sort_chain_graph_abs(struct callchain_node *node,
102                                    u64 min_hit)
103 {
104         struct callchain_node *child;
105
106         node->rb_root = RB_ROOT;
107
108         chain_for_each_child(child, node) {
109                 __sort_chain_graph_abs(child, min_hit);
110                 if (callchain_cumul_hits(child) >= min_hit)
111                         rb_insert_callchain(&node->rb_root, child,
112                                             CHAIN_GRAPH_ABS);
113         }
114 }
115
116 static void
117 sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
118                      u64 min_hit, struct callchain_param *param __maybe_unused)
119 {
120         __sort_chain_graph_abs(&chain_root->node, min_hit);
121         rb_root->rb_node = chain_root->node.rb_root.rb_node;
122 }
123
124 static void __sort_chain_graph_rel(struct callchain_node *node,
125                                    double min_percent)
126 {
127         struct callchain_node *child;
128         u64 min_hit;
129
130         node->rb_root = RB_ROOT;
131         min_hit = ceil(node->children_hit * min_percent);
132
133         chain_for_each_child(child, node) {
134                 __sort_chain_graph_rel(child, min_percent);
135                 if (callchain_cumul_hits(child) >= min_hit)
136                         rb_insert_callchain(&node->rb_root, child,
137                                             CHAIN_GRAPH_REL);
138         }
139 }
140
141 static void
142 sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
143                      u64 min_hit __maybe_unused, struct callchain_param *param)
144 {
145         __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
146         rb_root->rb_node = chain_root->node.rb_root.rb_node;
147 }
148
149 int callchain_register_param(struct callchain_param *param)
150 {
151         switch (param->mode) {
152         case CHAIN_GRAPH_ABS:
153                 param->sort = sort_chain_graph_abs;
154                 break;
155         case CHAIN_GRAPH_REL:
156                 param->sort = sort_chain_graph_rel;
157                 break;
158         case CHAIN_FLAT:
159                 param->sort = sort_chain_flat;
160                 break;
161         case CHAIN_NONE:
162         default:
163                 return -1;
164         }
165         return 0;
166 }
167
168 /*
169  * Create a child for a parent. If inherit_children, then the new child
170  * will become the new parent of it's parent children
171  */
172 static struct callchain_node *
173 create_child(struct callchain_node *parent, bool inherit_children)
174 {
175         struct callchain_node *new;
176
177         new = zalloc(sizeof(*new));
178         if (!new) {
179                 perror("not enough memory to create child for code path tree");
180                 return NULL;
181         }
182         new->parent = parent;
183         INIT_LIST_HEAD(&new->children);
184         INIT_LIST_HEAD(&new->val);
185
186         if (inherit_children) {
187                 struct callchain_node *next;
188
189                 list_splice(&parent->children, &new->children);
190                 INIT_LIST_HEAD(&parent->children);
191
192                 chain_for_each_child(next, new)
193                         next->parent = new;
194         }
195         list_add_tail(&new->siblings, &parent->children);
196
197         return new;
198 }
199
200
201 /*
202  * Fill the node with callchain values
203  */
204 static void
205 fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
206 {
207         struct callchain_cursor_node *cursor_node;
208
209         node->val_nr = cursor->nr - cursor->pos;
210         if (!node->val_nr)
211                 pr_warning("Warning: empty node in callchain tree\n");
212
213         cursor_node = callchain_cursor_current(cursor);
214
215         while (cursor_node) {
216                 struct callchain_list *call;
217
218                 call = zalloc(sizeof(*call));
219                 if (!call) {
220                         perror("not enough memory for the code path tree");
221                         return;
222                 }
223                 call->ip = cursor_node->ip;
224                 call->ms.sym = cursor_node->sym;
225                 call->ms.map = cursor_node->map;
226                 list_add_tail(&call->list, &node->val);
227
228                 callchain_cursor_advance(cursor);
229                 cursor_node = callchain_cursor_current(cursor);
230         }
231 }
232
233 static void
234 add_child(struct callchain_node *parent,
235           struct callchain_cursor *cursor,
236           u64 period)
237 {
238         struct callchain_node *new;
239
240         new = create_child(parent, false);
241         fill_node(new, cursor);
242
243         new->children_hit = 0;
244         new->hit = period;
245 }
246
247 /*
248  * Split the parent in two parts (a new child is created) and
249  * give a part of its callchain to the created child.
250  * Then create another child to host the given callchain of new branch
251  */
252 static void
253 split_add_child(struct callchain_node *parent,
254                 struct callchain_cursor *cursor,
255                 struct callchain_list *to_split,
256                 u64 idx_parents, u64 idx_local, u64 period)
257 {
258         struct callchain_node *new;
259         struct list_head *old_tail;
260         unsigned int idx_total = idx_parents + idx_local;
261
262         /* split */
263         new = create_child(parent, true);
264
265         /* split the callchain and move a part to the new child */
266         old_tail = parent->val.prev;
267         list_del_range(&to_split->list, old_tail);
268         new->val.next = &to_split->list;
269         new->val.prev = old_tail;
270         to_split->list.prev = &new->val;
271         old_tail->next = &new->val;
272
273         /* split the hits */
274         new->hit = parent->hit;
275         new->children_hit = parent->children_hit;
276         parent->children_hit = callchain_cumul_hits(new);
277         new->val_nr = parent->val_nr - idx_local;
278         parent->val_nr = idx_local;
279
280         /* create a new child for the new branch if any */
281         if (idx_total < cursor->nr) {
282                 parent->hit = 0;
283                 add_child(parent, cursor, period);
284                 parent->children_hit += period;
285         } else {
286                 parent->hit = period;
287         }
288 }
289
290 static int
291 append_chain(struct callchain_node *root,
292              struct callchain_cursor *cursor,
293              u64 period);
294
295 static void
296 append_chain_children(struct callchain_node *root,
297                       struct callchain_cursor *cursor,
298                       u64 period)
299 {
300         struct callchain_node *rnode;
301
302         /* lookup in childrens */
303         chain_for_each_child(rnode, root) {
304                 unsigned int ret = append_chain(rnode, cursor, period);
305
306                 if (!ret)
307                         goto inc_children_hit;
308         }
309         /* nothing in children, add to the current node */
310         add_child(root, cursor, period);
311
312 inc_children_hit:
313         root->children_hit += period;
314 }
315
316 static int
317 append_chain(struct callchain_node *root,
318              struct callchain_cursor *cursor,
319              u64 period)
320 {
321         struct callchain_cursor_node *curr_snap = cursor->curr;
322         struct callchain_list *cnode;
323         u64 start = cursor->pos;
324         bool found = false;
325         u64 matches;
326
327         /*
328          * Lookup in the current node
329          * If we have a symbol, then compare the start to match
330          * anywhere inside a function.
331          */
332         list_for_each_entry(cnode, &root->val, list) {
333                 struct callchain_cursor_node *node;
334                 struct symbol *sym;
335
336                 node = callchain_cursor_current(cursor);
337                 if (!node)
338                         break;
339
340                 sym = node->sym;
341
342                 if (cnode->ms.sym && sym) {
343                         if (cnode->ms.sym->start != sym->start)
344                                 break;
345                 } else if (cnode->ip != node->ip)
346                         break;
347
348                 if (!found)
349                         found = true;
350
351                 callchain_cursor_advance(cursor);
352         }
353
354         /* matches not, relay on the parent */
355         if (!found) {
356                 cursor->curr = curr_snap;
357                 cursor->pos = start;
358                 return -1;
359         }
360
361         matches = cursor->pos - start;
362
363         /* we match only a part of the node. Split it and add the new chain */
364         if (matches < root->val_nr) {
365                 split_add_child(root, cursor, cnode, start, matches, period);
366                 return 0;
367         }
368
369         /* we match 100% of the path, increment the hit */
370         if (matches == root->val_nr && cursor->pos == cursor->nr) {
371                 root->hit += period;
372                 return 0;
373         }
374
375         /* We match the node and still have a part remaining */
376         append_chain_children(root, cursor, period);
377
378         return 0;
379 }
380
381 int callchain_append(struct callchain_root *root,
382                      struct callchain_cursor *cursor,
383                      u64 period)
384 {
385         if (!cursor->nr)
386                 return 0;
387
388         callchain_cursor_commit(cursor);
389
390         append_chain_children(&root->node, cursor, period);
391
392         if (cursor->nr > root->max_depth)
393                 root->max_depth = cursor->nr;
394
395         return 0;
396 }
397
398 static int
399 merge_chain_branch(struct callchain_cursor *cursor,
400                    struct callchain_node *dst, struct callchain_node *src)
401 {
402         struct callchain_cursor_node **old_last = cursor->last;
403         struct callchain_node *child, *next_child;
404         struct callchain_list *list, *next_list;
405         int old_pos = cursor->nr;
406         int err = 0;
407
408         list_for_each_entry_safe(list, next_list, &src->val, list) {
409                 callchain_cursor_append(cursor, list->ip,
410                                         list->ms.map, list->ms.sym);
411                 list_del(&list->list);
412                 free(list);
413         }
414
415         if (src->hit) {
416                 callchain_cursor_commit(cursor);
417                 append_chain_children(dst, cursor, src->hit);
418         }
419
420         chain_for_each_child_safe(child, next_child, src) {
421                 err = merge_chain_branch(cursor, dst, child);
422                 if (err)
423                         break;
424
425                 list_del(&child->siblings);
426                 free(child);
427         }
428
429         cursor->nr = old_pos;
430         cursor->last = old_last;
431
432         return err;
433 }
434
435 int callchain_merge(struct callchain_cursor *cursor,
436                     struct callchain_root *dst, struct callchain_root *src)
437 {
438         return merge_chain_branch(cursor, &dst->node, &src->node);
439 }
440
441 int callchain_cursor_append(struct callchain_cursor *cursor,
442                             u64 ip, struct map *map, struct symbol *sym)
443 {
444         struct callchain_cursor_node *node = *cursor->last;
445
446         if (!node) {
447                 node = calloc(sizeof(*node), 1);
448                 if (!node)
449                         return -ENOMEM;
450
451                 *cursor->last = node;
452         }
453
454         node->ip = ip;
455         node->map = map;
456         node->sym = sym;
457
458         cursor->nr++;
459
460         cursor->last = &node->next;
461
462         return 0;
463 }