aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/callchain.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/callchain.c')
-rw-r--r--tools/perf/util/callchain.c233
1 files changed, 144 insertions, 89 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index f231f43424d2..9f7106a8d9a4 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3 * 3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then 4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree. 5 * sort them in an rbtree.
@@ -18,7 +18,8 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event) 21bool ip_callchain__valid(struct ip_callchain *chain,
22 const union perf_event *event)
22{ 23{
23 unsigned int chain_size = event->header.size; 24 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 25 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
@@ -26,7 +27,10 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
26} 27}
27 28
28#define chain_for_each_child(child, parent) \ 29#define chain_for_each_child(child, parent) \
29 list_for_each_entry(child, &parent->children, brothers) 30 list_for_each_entry(child, &parent->children, siblings)
31
32#define chain_for_each_child_safe(child, next, parent) \
33 list_for_each_entry_safe(child, next, &parent->children, siblings)
30 34
31static void 35static void
32rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 36rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
@@ -35,14 +39,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
35 struct rb_node **p = &root->rb_node; 39 struct rb_node **p = &root->rb_node;
36 struct rb_node *parent = NULL; 40 struct rb_node *parent = NULL;
37 struct callchain_node *rnode; 41 struct callchain_node *rnode;
38 u64 chain_cumul = cumul_hits(chain); 42 u64 chain_cumul = callchain_cumul_hits(chain);
39 43
40 while (*p) { 44 while (*p) {
41 u64 rnode_cumul; 45 u64 rnode_cumul;
42 46
43 parent = *p; 47 parent = *p;
44 rnode = rb_entry(parent, struct callchain_node, rb_node); 48 rnode = rb_entry(parent, struct callchain_node, rb_node);
45 rnode_cumul = cumul_hits(rnode); 49 rnode_cumul = callchain_cumul_hits(rnode);
46 50
47 switch (mode) { 51 switch (mode) {
48 case CHAIN_FLAT: 52 case CHAIN_FLAT:
@@ -86,10 +90,10 @@ __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
86 * sort them by hit 90 * sort them by hit
87 */ 91 */
88static void 92static void
89sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 93sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
90 u64 min_hit, struct callchain_param *param __used) 94 u64 min_hit, struct callchain_param *param __used)
91{ 95{
92 __sort_chain_flat(rb_root, node, min_hit); 96 __sort_chain_flat(rb_root, &root->node, min_hit);
93} 97}
94 98
95static void __sort_chain_graph_abs(struct callchain_node *node, 99static void __sort_chain_graph_abs(struct callchain_node *node,
@@ -101,18 +105,18 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
101 105
102 chain_for_each_child(child, node) { 106 chain_for_each_child(child, node) {
103 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
104 if (cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
105 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
106 CHAIN_GRAPH_ABS); 110 CHAIN_GRAPH_ABS);
107 } 111 }
108} 112}
109 113
110static void 114static void
111sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root, 115sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
112 u64 min_hit, struct callchain_param *param __used) 116 u64 min_hit, struct callchain_param *param __used)
113{ 117{
114 __sort_chain_graph_abs(chain_root, min_hit); 118 __sort_chain_graph_abs(&chain_root->node, min_hit);
115 rb_root->rb_node = chain_root->rb_root.rb_node; 119 rb_root->rb_node = chain_root->node.rb_root.rb_node;
116} 120}
117 121
118static void __sort_chain_graph_rel(struct callchain_node *node, 122static void __sort_chain_graph_rel(struct callchain_node *node,
@@ -126,21 +130,21 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
126 130
127 chain_for_each_child(child, node) { 131 chain_for_each_child(child, node) {
128 __sort_chain_graph_rel(child, min_percent); 132 __sort_chain_graph_rel(child, min_percent);
129 if (cumul_hits(child) >= min_hit) 133 if (callchain_cumul_hits(child) >= min_hit)
130 rb_insert_callchain(&node->rb_root, child, 134 rb_insert_callchain(&node->rb_root, child,
131 CHAIN_GRAPH_REL); 135 CHAIN_GRAPH_REL);
132 } 136 }
133} 137}
134 138
135static void 139static void
136sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, 140sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
137 u64 min_hit __used, struct callchain_param *param) 141 u64 min_hit __used, struct callchain_param *param)
138{ 142{
139 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0); 143 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
140 rb_root->rb_node = chain_root->rb_root.rb_node; 144 rb_root->rb_node = chain_root->node.rb_root.rb_node;
141} 145}
142 146
143int register_callchain_param(struct callchain_param *param) 147int callchain_register_param(struct callchain_param *param)
144{ 148{
145 switch (param->mode) { 149 switch (param->mode) {
146 case CHAIN_GRAPH_ABS: 150 case CHAIN_GRAPH_ABS:
@@ -186,32 +190,27 @@ create_child(struct callchain_node *parent, bool inherit_children)
186 chain_for_each_child(next, new) 190 chain_for_each_child(next, new)
187 next->parent = new; 191 next->parent = new;
188 } 192 }
189 list_add_tail(&new->brothers, &parent->children); 193 list_add_tail(&new->siblings, &parent->children);
190 194
191 return new; 195 return new;
192} 196}
193 197
194 198
195struct resolved_ip {
196 u64 ip;
197 struct map_symbol ms;
198};
199
200struct resolved_chain {
201 u64 nr;
202 struct resolved_ip ips[0];
203};
204
205
206/* 199/*
207 * Fill the node with callchain values 200 * Fill the node with callchain values
208 */ 201 */
209static void 202static void
210fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) 203fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
211{ 204{
212 unsigned int i; 205 struct callchain_cursor_node *cursor_node;
213 206
214 for (i = start; i < chain->nr; i++) { 207 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) {
215 struct callchain_list *call; 214 struct callchain_list *call;
216 215
217 call = zalloc(sizeof(*call)); 216 call = zalloc(sizeof(*call));
@@ -219,23 +218,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
219 perror("not enough memory for the code path tree"); 218 perror("not enough memory for the code path tree");
220 return; 219 return;
221 } 220 }
222 call->ip = chain->ips[i].ip; 221 call->ip = cursor_node->ip;
223 call->ms = chain->ips[i].ms; 222 call->ms.sym = cursor_node->sym;
223 call->ms.map = cursor_node->map;
224 list_add_tail(&call->list, &node->val); 224 list_add_tail(&call->list, &node->val);
225
226 callchain_cursor_advance(cursor);
227 cursor_node = callchain_cursor_current(cursor);
225 } 228 }
226 node->val_nr = chain->nr - start;
227 if (!node->val_nr)
228 pr_warning("Warning: empty node in callchain tree\n");
229} 229}
230 230
231static void 231static void
232add_child(struct callchain_node *parent, struct resolved_chain *chain, 232add_child(struct callchain_node *parent,
233 int start, u64 period) 233 struct callchain_cursor *cursor,
234 u64 period)
234{ 235{
235 struct callchain_node *new; 236 struct callchain_node *new;
236 237
237 new = create_child(parent, false); 238 new = create_child(parent, false);
238 fill_node(new, chain, start); 239 fill_node(new, cursor);
239 240
240 new->children_hit = 0; 241 new->children_hit = 0;
241 new->hit = period; 242 new->hit = period;
@@ -247,9 +248,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
247 * Then create another child to host the given callchain of new branch 248 * Then create another child to host the given callchain of new branch
248 */ 249 */
249static void 250static void
250split_add_child(struct callchain_node *parent, struct resolved_chain *chain, 251split_add_child(struct callchain_node *parent,
251 struct callchain_list *to_split, int idx_parents, int idx_local, 252 struct callchain_cursor *cursor,
252 u64 period) 253 struct callchain_list *to_split,
254 u64 idx_parents, u64 idx_local, u64 period)
253{ 255{
254 struct callchain_node *new; 256 struct callchain_node *new;
255 struct list_head *old_tail; 257 struct list_head *old_tail;
@@ -269,14 +271,14 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
269 /* split the hits */ 271 /* split the hits */
270 new->hit = parent->hit; 272 new->hit = parent->hit;
271 new->children_hit = parent->children_hit; 273 new->children_hit = parent->children_hit;
272 parent->children_hit = cumul_hits(new); 274 parent->children_hit = callchain_cumul_hits(new);
273 new->val_nr = parent->val_nr - idx_local; 275 new->val_nr = parent->val_nr - idx_local;
274 parent->val_nr = idx_local; 276 parent->val_nr = idx_local;
275 277
276 /* create a new child for the new branch if any */ 278 /* create a new child for the new branch if any */
277 if (idx_total < chain->nr) { 279 if (idx_total < cursor->nr) {
278 parent->hit = 0; 280 parent->hit = 0;
279 add_child(parent, chain, idx_total, period); 281 add_child(parent, cursor, period);
280 parent->children_hit += period; 282 parent->children_hit += period;
281 } else { 283 } else {
282 parent->hit = period; 284 parent->hit = period;
@@ -284,37 +286,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
284} 286}
285 287
286static int 288static int
287__append_chain(struct callchain_node *root, struct resolved_chain *chain, 289append_chain(struct callchain_node *root,
288 unsigned int start, u64 period); 290 struct callchain_cursor *cursor,
291 u64 period);
289 292
290static void 293static void
291__append_chain_children(struct callchain_node *root, 294append_chain_children(struct callchain_node *root,
292 struct resolved_chain *chain, 295 struct callchain_cursor *cursor,
293 unsigned int start, u64 period) 296 u64 period)
294{ 297{
295 struct callchain_node *rnode; 298 struct callchain_node *rnode;
296 299
297 /* lookup in childrens */ 300 /* lookup in childrens */
298 chain_for_each_child(rnode, root) { 301 chain_for_each_child(rnode, root) {
299 unsigned int ret = __append_chain(rnode, chain, start, period); 302 unsigned int ret = append_chain(rnode, cursor, period);
300 303
301 if (!ret) 304 if (!ret)
302 goto inc_children_hit; 305 goto inc_children_hit;
303 } 306 }
304 /* nothing in children, add to the current node */ 307 /* nothing in children, add to the current node */
305 add_child(root, chain, start, period); 308 add_child(root, cursor, period);
306 309
307inc_children_hit: 310inc_children_hit:
308 root->children_hit += period; 311 root->children_hit += period;
309} 312}
310 313
311static int 314static int
312__append_chain(struct callchain_node *root, struct resolved_chain *chain, 315append_chain(struct callchain_node *root,
313 unsigned int start, u64 period) 316 struct callchain_cursor *cursor,
317 u64 period)
314{ 318{
319 struct callchain_cursor_node *curr_snap = cursor->curr;
315 struct callchain_list *cnode; 320 struct callchain_list *cnode;
316 unsigned int i = start; 321 u64 start = cursor->pos;
317 bool found = false; 322 bool found = false;
323 u64 matches;
318 324
319 /* 325 /*
320 * Lookup in the current node 326 * Lookup in the current node
@@ -322,85 +328,134 @@ __append_chain(struct callchain_node *root, struct resolved_chain *chain,
322 * anywhere inside a function. 328 * anywhere inside a function.
323 */ 329 */
324 list_for_each_entry(cnode, &root->val, list) { 330 list_for_each_entry(cnode, &root->val, list) {
331 struct callchain_cursor_node *node;
325 struct symbol *sym; 332 struct symbol *sym;
326 333
327 if (i == chain->nr) 334 node = callchain_cursor_current(cursor);
335 if (!node)
328 break; 336 break;
329 337
330 sym = chain->ips[i].ms.sym; 338 sym = node->sym;
331 339
332 if (cnode->ms.sym && sym) { 340 if (cnode->ms.sym && sym) {
333 if (cnode->ms.sym->start != sym->start) 341 if (cnode->ms.sym->start != sym->start)
334 break; 342 break;
335 } else if (cnode->ip != chain->ips[i].ip) 343 } else if (cnode->ip != node->ip)
336 break; 344 break;
337 345
338 if (!found) 346 if (!found)
339 found = true; 347 found = true;
340 i++; 348
349 callchain_cursor_advance(cursor);
341 } 350 }
342 351
343 /* matches not, relay on the parent */ 352 /* matches not, relay on the parent */
344 if (!found) 353 if (!found) {
354 cursor->curr = curr_snap;
355 cursor->pos = start;
345 return -1; 356 return -1;
357 }
358
359 matches = cursor->pos - start;
346 360
347 /* we match only a part of the node. Split it and add the new chain */ 361 /* we match only a part of the node. Split it and add the new chain */
348 if (i - start < root->val_nr) { 362 if (matches < root->val_nr) {
349 split_add_child(root, chain, cnode, start, i - start, period); 363 split_add_child(root, cursor, cnode, start, matches, period);
350 return 0; 364 return 0;
351 } 365 }
352 366
353 /* we match 100% of the path, increment the hit */ 367 /* we match 100% of the path, increment the hit */
354 if (i - start == root->val_nr && i == chain->nr) { 368 if (matches == root->val_nr && cursor->pos == cursor->nr) {
355 root->hit += period; 369 root->hit += period;
356 return 0; 370 return 0;
357 } 371 }
358 372
359 /* We match the node and still have a part remaining */ 373 /* We match the node and still have a part remaining */
360 __append_chain_children(root, chain, i, period); 374 append_chain_children(root, cursor, period);
361 375
362 return 0; 376 return 0;
363} 377}
364 378
365static void filter_context(struct ip_callchain *old, struct resolved_chain *new, 379int callchain_append(struct callchain_root *root,
366 struct map_symbol *syms) 380 struct callchain_cursor *cursor,
381 u64 period)
367{ 382{
368 int i, j = 0; 383 if (!cursor->nr)
384 return 0;
385
386 callchain_cursor_commit(cursor);
387
388 append_chain_children(&root->node, cursor, period);
369 389
370 for (i = 0; i < (int)old->nr; i++) { 390 if (cursor->nr > root->max_depth)
371 if (old->ips[i] >= PERF_CONTEXT_MAX) 391 root->max_depth = cursor->nr;
372 continue;
373 392
374 new->ips[j].ip = old->ips[i]; 393 return 0;
375 new->ips[j].ms = syms[i]; 394}
376 j++; 395
396static int
397merge_chain_branch(struct callchain_cursor *cursor,
398 struct callchain_node *dst, struct callchain_node *src)
399{
400 struct callchain_cursor_node **old_last = cursor->last;
401 struct callchain_node *child, *next_child;
402 struct callchain_list *list, *next_list;
403 int old_pos = cursor->nr;
404 int err = 0;
405
406 list_for_each_entry_safe(list, next_list, &src->val, list) {
407 callchain_cursor_append(cursor, list->ip,
408 list->ms.map, list->ms.sym);
409 list_del(&list->list);
410 free(list);
411 }
412
413 if (src->hit) {
414 callchain_cursor_commit(cursor);
415 append_chain_children(dst, cursor, src->hit);
416 }
417
418 chain_for_each_child_safe(child, next_child, src) {
419 err = merge_chain_branch(cursor, dst, child);
420 if (err)
421 break;
422
423 list_del(&child->siblings);
424 free(child);
377 } 425 }
378 426
379 new->nr = j; 427 cursor->nr = old_pos;
428 cursor->last = old_last;
429
430 return err;
380} 431}
381 432
433int callchain_merge(struct callchain_cursor *cursor,
434 struct callchain_root *dst, struct callchain_root *src)
435{
436 return merge_chain_branch(cursor, &dst->node, &src->node);
437}
382 438
383int append_chain(struct callchain_node *root, struct ip_callchain *chain, 439int callchain_cursor_append(struct callchain_cursor *cursor,
384 struct map_symbol *syms, u64 period) 440 u64 ip, struct map *map, struct symbol *sym)
385{ 441{
386 struct resolved_chain *filtered; 442 struct callchain_cursor_node *node = *cursor->last;
387 443
388 if (!chain->nr) 444 if (!node) {
389 return 0; 445 node = calloc(sizeof(*node), 1);
446 if (!node)
447 return -ENOMEM;
390 448
391 filtered = zalloc(sizeof(*filtered) + 449 *cursor->last = node;
392 chain->nr * sizeof(struct resolved_ip)); 450 }
393 if (!filtered)
394 return -ENOMEM;
395 451
396 filter_context(chain, filtered, syms); 452 node->ip = ip;
453 node->map = map;
454 node->sym = sym;
397 455
398 if (!filtered->nr) 456 cursor->nr++;
399 goto end;
400 457
401 __append_chain_children(root, filtered, 0, period); 458 cursor->last = &node->next;
402end:
403 free(filtered);
404 459
405 return 0; 460 return 0;
406} 461}