aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2011-01-13 22:51:58 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-22 16:56:31 -0500
commit1b3a0e9592ebf174af934b3908a2bf6a6fa86169 (patch)
tree22de930ec03920ea7a4d602d9a582f5125595916
parentde5fa3a8a05cd60f59622e88cfeb90416760d78e (diff)
perf callchain: Feed callchains into a cursor
The callchains are fed with an array of a fixed size. As a result we iterate over each callchains three times: - 1st to resolve symbols - 2nd to filter out context boundaries - 3rd for the insertion into the tree This also involves some pairs of memory allocation/deallocation everytime we insert a callchain, for the filtered out array of addresses and for the array of symbols that comes along. Instead, feed the callchains through a linked list with persistent allocations. It brings several pros like: - Merge the 1st and 2nd iterations in one. That was possible before but in a way that would involve allocating an array slightly taller than necessary because we don't know in advance the number of context boundaries to filter out. - Much lesser allocations/deallocations. The linked list keeps persistent empty entries for the next usages and is extendable at will. - Makes it easier for multiple sources of callchains to feed a stacktrace together. This is deemed to pave the way for cfi based callchains wherein traditional frame pointer based kernel stacktraces will precede cfi based user ones, producing an overall callchain which size is hardly predictable. This requirement makes the static array obsolete and makes a linked list based iterator a much more flexible fit. Basic testing on a big perf file containing callchains (~ 176 MB) has shown a throughput gain of about 11% with perf report. Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1294977121-5700-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/builtin-report.c25
-rw-r--r--tools/perf/util/callchain.c204
-rw-r--r--tools/perf/util/callchain.h66
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/session.c22
-rw-r--r--tools/perf/util/session.h11
7 files changed, 204 insertions, 139 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c27e31f289e6..c95599a82f9e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -81,18 +81,17 @@ static int perf_session__add_hist_entry(struct perf_session *self,
81 struct addr_location *al, 81 struct addr_location *al,
82 struct sample_data *data) 82 struct sample_data *data)
83{ 83{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 84 struct symbol *parent = NULL;
86 int err = -ENOMEM; 85 int err = 0;
87 struct hist_entry *he; 86 struct hist_entry *he;
88 struct hists *hists; 87 struct hists *hists;
89 struct perf_event_attr *attr; 88 struct perf_event_attr *attr;
90 89
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 90 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
92 syms = perf_session__resolve_callchain(self, al->thread, 91 err = perf_session__resolve_callchain(self, al->thread,
93 data->callchain, &parent); 92 data->callchain, &parent);
94 if (syms == NULL) 93 if (err)
95 return -ENOMEM; 94 return err;
96 } 95 }
97 96
98 attr = perf_header__find_attr(data->id, &self->header); 97 attr = perf_header__find_attr(data->id, &self->header);
@@ -101,16 +100,17 @@ static int perf_session__add_hist_entry(struct perf_session *self,
101 else 100 else
102 hists = perf_session__hists_findnew(self, data->id, 0, 0); 101 hists = perf_session__hists_findnew(self, data->id, 0, 0);
103 if (hists == NULL) 102 if (hists == NULL)
104 goto out_free_syms; 103 return -ENOMEM;
104
105 he = __hists__add_entry(hists, al, parent, data->period); 105 he = __hists__add_entry(hists, al, parent, data->period);
106 if (he == NULL) 106 if (he == NULL)
107 goto out_free_syms; 107 return -ENOMEM;
108 err = 0; 108
109 if (symbol_conf.use_callchain) { 109 if (symbol_conf.use_callchain) {
110 err = callchain_append(he->callchain, data->callchain, syms, 110 err = callchain_append(he->callchain, &self->callchain_cursor,
111 data->period); 111 data->period);
112 if (err) 112 if (err)
113 goto out_free_syms; 113 return err;
114 } 114 }
115 /* 115 /*
116 * Only in the newt browser we are doing integrated annotation, 116 * Only in the newt browser we are doing integrated annotation,
@@ -119,8 +119,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
119 */ 119 */
120 if (use_browser > 0) 120 if (use_browser > 0)
121 err = hist_entry__inc_addr_samples(he, al->addr); 121 err = hist_entry__inc_addr_samples(he, al->addr);
122out_free_syms: 122
123 free(syms);
124 return err; 123 return err;
125} 124}
126 125
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index e12d539417b2..53a49e0cfc6c 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.
@@ -195,26 +195,21 @@ create_child(struct callchain_node *parent, bool inherit_children)
195} 195}
196 196
197 197
198struct resolved_ip {
199 u64 ip;
200 struct map_symbol ms;
201};
202
203struct resolved_chain {
204 u64 nr;
205 struct resolved_ip ips[0];
206};
207
208
209/* 198/*
210 * Fill the node with callchain values 199 * Fill the node with callchain values
211 */ 200 */
212static void 201static void
213fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) 202fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
214{ 203{
215 unsigned int i; 204 struct callchain_cursor_node *cursor_node;
205
206 node->val_nr = cursor->nr - cursor->pos;
207 if (!node->val_nr)
208 pr_warning("Warning: empty node in callchain tree\n");
216 209
217 for (i = start; i < chain->nr; i++) { 210 cursor_node = callchain_cursor_current(cursor);
211
212 while (cursor_node) {
218 struct callchain_list *call; 213 struct callchain_list *call;
219 214
220 call = zalloc(sizeof(*call)); 215 call = zalloc(sizeof(*call));
@@ -222,23 +217,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
222 perror("not enough memory for the code path tree"); 217 perror("not enough memory for the code path tree");
223 return; 218 return;
224 } 219 }
225 call->ip = chain->ips[i].ip; 220 call->ip = cursor_node->ip;
226 call->ms = chain->ips[i].ms; 221 call->ms.sym = cursor_node->sym;
222 call->ms.map = cursor_node->map;
227 list_add_tail(&call->list, &node->val); 223 list_add_tail(&call->list, &node->val);
224
225 callchain_cursor_advance(cursor);
226 cursor_node = callchain_cursor_current(cursor);
228 } 227 }
229 node->val_nr = chain->nr - start;
230 if (!node->val_nr)
231 pr_warning("Warning: empty node in callchain tree\n");
232} 228}
233 229
234static void 230static void
235add_child(struct callchain_node *parent, struct resolved_chain *chain, 231add_child(struct callchain_node *parent,
236 int start, u64 period) 232 struct callchain_cursor *cursor,
233 u64 period)
237{ 234{
238 struct callchain_node *new; 235 struct callchain_node *new;
239 236
240 new = create_child(parent, false); 237 new = create_child(parent, false);
241 fill_node(new, chain, start); 238 fill_node(new, cursor);
242 239
243 new->children_hit = 0; 240 new->children_hit = 0;
244 new->hit = period; 241 new->hit = period;
@@ -250,9 +247,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
250 * Then create another child to host the given callchain of new branch 247 * Then create another child to host the given callchain of new branch
251 */ 248 */
252static void 249static void
253split_add_child(struct callchain_node *parent, struct resolved_chain *chain, 250split_add_child(struct callchain_node *parent,
254 struct callchain_list *to_split, int idx_parents, int idx_local, 251 struct callchain_cursor *cursor,
255 u64 period) 252 struct callchain_list *to_split,
253 u64 idx_parents, u64 idx_local, u64 period)
256{ 254{
257 struct callchain_node *new; 255 struct callchain_node *new;
258 struct list_head *old_tail; 256 struct list_head *old_tail;
@@ -277,9 +275,9 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
277 parent->val_nr = idx_local; 275 parent->val_nr = idx_local;
278 276
279 /* create a new child for the new branch if any */ 277 /* create a new child for the new branch if any */
280 if (idx_total < chain->nr) { 278 if (idx_total < cursor->nr) {
281 parent->hit = 0; 279 parent->hit = 0;
282 add_child(parent, chain, idx_total, period); 280 add_child(parent, cursor, period);
283 parent->children_hit += period; 281 parent->children_hit += period;
284 } else { 282 } else {
285 parent->hit = period; 283 parent->hit = period;
@@ -287,36 +285,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
287} 285}
288 286
289static int 287static int
290append_chain(struct callchain_node *root, struct resolved_chain *chain, 288append_chain(struct callchain_node *root,
291 unsigned int start, u64 period); 289 struct callchain_cursor *cursor,
290 u64 period);
292 291
293static void 292static void
294append_chain_children(struct callchain_node *root, struct resolved_chain *chain, 293append_chain_children(struct callchain_node *root,
295 unsigned int start, u64 period) 294 struct callchain_cursor *cursor,
295 u64 period)
296{ 296{
297 struct callchain_node *rnode; 297 struct callchain_node *rnode;
298 298
299 /* lookup in childrens */ 299 /* lookup in childrens */
300 chain_for_each_child(rnode, root) { 300 chain_for_each_child(rnode, root) {
301 unsigned int ret = append_chain(rnode, chain, start, period); 301 unsigned int ret = append_chain(rnode, cursor, period);
302 302
303 if (!ret) 303 if (!ret)
304 goto inc_children_hit; 304 goto inc_children_hit;
305 } 305 }
306 /* nothing in children, add to the current node */ 306 /* nothing in children, add to the current node */
307 add_child(root, chain, start, period); 307 add_child(root, cursor, period);
308 308
309inc_children_hit: 309inc_children_hit:
310 root->children_hit += period; 310 root->children_hit += period;
311} 311}
312 312
313static int 313static int
314append_chain(struct callchain_node *root, struct resolved_chain *chain, 314append_chain(struct callchain_node *root,
315 unsigned int start, u64 period) 315 struct callchain_cursor *cursor,
316 u64 period)
316{ 317{
318 struct callchain_cursor_node *curr_snap = cursor->curr;
317 struct callchain_list *cnode; 319 struct callchain_list *cnode;
318 unsigned int i = start; 320 u64 start = cursor->pos;
319 bool found = false; 321 bool found = false;
322 u64 matches;
320 323
321 /* 324 /*
322 * Lookup in the current node 325 * Lookup in the current node
@@ -324,114 +327,95 @@ append_chain(struct callchain_node *root, struct resolved_chain *chain,
324 * anywhere inside a function. 327 * anywhere inside a function.
325 */ 328 */
326 list_for_each_entry(cnode, &root->val, list) { 329 list_for_each_entry(cnode, &root->val, list) {
330 struct callchain_cursor_node *node;
327 struct symbol *sym; 331 struct symbol *sym;
328 332
329 if (i == chain->nr) 333 node = callchain_cursor_current(cursor);
334 if (!node)
330 break; 335 break;
331 336
332 sym = chain->ips[i].ms.sym; 337 sym = node->sym;
333 338
334 if (cnode->ms.sym && sym) { 339 if (cnode->ms.sym && sym) {
335 if (cnode->ms.sym->start != sym->start) 340 if (cnode->ms.sym->start != sym->start)
336 break; 341 break;
337 } else if (cnode->ip != chain->ips[i].ip) 342 } else if (cnode->ip != node->ip)
338 break; 343 break;
339 344
340 if (!found) 345 if (!found)
341 found = true; 346 found = true;
342 i++; 347
348 callchain_cursor_advance(cursor);
343 } 349 }
344 350
345 /* matches not, relay on the parent */ 351 /* matches not, relay on the parent */
346 if (!found) 352 if (!found) {
353 cursor->curr = curr_snap;
354 cursor->pos = start;
347 return -1; 355 return -1;
356 }
357
358 matches = cursor->pos - start;
348 359
349 /* we match only a part of the node. Split it and add the new chain */ 360 /* we match only a part of the node. Split it and add the new chain */
350 if (i - start < root->val_nr) { 361 if (matches < root->val_nr) {
351 split_add_child(root, chain, cnode, start, i - start, period); 362 split_add_child(root, cursor, cnode, start, matches, period);
352 return 0; 363 return 0;
353 } 364 }
354 365
355 /* we match 100% of the path, increment the hit */ 366 /* we match 100% of the path, increment the hit */
356 if (i - start == root->val_nr && i == chain->nr) { 367 if (matches == root->val_nr && cursor->pos == cursor->nr) {
357 root->hit += period; 368 root->hit += period;
358 return 0; 369 return 0;
359 } 370 }
360 371
361 /* We match the node and still have a part remaining */ 372 /* We match the node and still have a part remaining */
362 append_chain_children(root, chain, i, period); 373 append_chain_children(root, cursor, period);
363 374
364 return 0; 375 return 0;
365} 376}
366 377
367static void filter_context(struct ip_callchain *old, struct resolved_chain *new, 378int callchain_append(struct callchain_root *root,
368 struct map_symbol *syms) 379 struct callchain_cursor *cursor,
369{ 380 u64 period)
370 int i, j = 0;
371
372 for (i = 0; i < (int)old->nr; i++) {
373 if (old->ips[i] >= PERF_CONTEXT_MAX)
374 continue;
375
376 new->ips[j].ip = old->ips[i];
377 new->ips[j].ms = syms[i];
378 j++;
379 }
380
381 new->nr = j;
382}
383
384
385int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
386 struct map_symbol *syms, u64 period)
387{ 381{
388 struct resolved_chain *filtered; 382 if (!cursor->nr)
389
390 if (!chain->nr)
391 return 0; 383 return 0;
392 384
393 filtered = zalloc(sizeof(*filtered) + 385 callchain_cursor_commit(cursor);
394 chain->nr * sizeof(struct resolved_ip));
395 if (!filtered)
396 return -ENOMEM;
397
398 filter_context(chain, filtered, syms);
399
400 if (!filtered->nr)
401 goto end;
402 386
403 append_chain_children(&root->node, filtered, 0, period); 387 append_chain_children(&root->node, cursor, period);
404 388
405 if (filtered->nr > root->max_depth) 389 if (cursor->nr > root->max_depth)
406 root->max_depth = filtered->nr; 390 root->max_depth = cursor->nr;
407end:
408 free(filtered);
409 391
410 return 0; 392 return 0;
411} 393}
412 394
413static int 395static int
414merge_chain_branch(struct callchain_node *dst, struct callchain_node *src, 396merge_chain_branch(struct callchain_cursor *cursor,
415 struct resolved_chain *chain) 397 struct callchain_node *dst, struct callchain_node *src)
416{ 398{
399 struct callchain_cursor_node **old_last = cursor->last;
417 struct callchain_node *child, *next_child; 400 struct callchain_node *child, *next_child;
418 struct callchain_list *list, *next_list; 401 struct callchain_list *list, *next_list;
419 int old_pos = chain->nr; 402 int old_pos = cursor->nr;
420 int err = 0; 403 int err = 0;
421 404
422 list_for_each_entry_safe(list, next_list, &src->val, list) { 405 list_for_each_entry_safe(list, next_list, &src->val, list) {
423 chain->ips[chain->nr].ip = list->ip; 406 callchain_cursor_append(cursor, list->ip,
424 chain->ips[chain->nr].ms = list->ms; 407 list->ms.map, list->ms.sym);
425 chain->nr++;
426 list_del(&list->list); 408 list_del(&list->list);
427 free(list); 409 free(list);
428 } 410 }
429 411
430 if (src->hit) 412 if (src->hit) {
431 append_chain_children(dst, chain, 0, src->hit); 413 callchain_cursor_commit(cursor);
414 append_chain_children(dst, cursor, src->hit);
415 }
432 416
433 chain_for_each_child_safe(child, next_child, src) { 417 chain_for_each_child_safe(child, next_child, src) {
434 err = merge_chain_branch(dst, child, chain); 418 err = merge_chain_branch(cursor, dst, child);
435 if (err) 419 if (err)
436 break; 420 break;
437 421
@@ -439,26 +423,38 @@ merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
439 free(child); 423 free(child);
440 } 424 }
441 425
442 chain->nr = old_pos; 426 cursor->nr = old_pos;
427 cursor->last = old_last;
443 428
444 return err; 429 return err;
445} 430}
446 431
447int callchain_merge(struct callchain_root *dst, struct callchain_root *src) 432int callchain_merge(struct callchain_cursor *cursor,
433 struct callchain_root *dst, struct callchain_root *src)
434{
435 return merge_chain_branch(cursor, &dst->node, &src->node);
436}
437
438int callchain_cursor_append(struct callchain_cursor *cursor,
439 u64 ip, struct map *map, struct symbol *sym)
448{ 440{
449 struct resolved_chain *chain; 441 struct callchain_cursor_node *node = *cursor->last;
450 int err;
451 442
452 chain = malloc(sizeof(*chain) + 443 if (!node) {
453 src->max_depth * sizeof(struct resolved_ip)); 444 node = calloc(sizeof(*node), 1);
454 if (!chain) 445 if (!node)
455 return -ENOMEM; 446 return -ENOMEM;
456 447
457 chain->nr = 0; 448 *cursor->last = node;
449 }
458 450
459 err = merge_chain_branch(&dst->node, &src->node, chain); 451 node->ip = ip;
452 node->map = map;
453 node->sym = sym;
460 454
461 free(chain); 455 cursor->nr++;
462 456
463 return err; 457 cursor->last = &node->next;
458
459 return 0;
464} 460}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index c15fb8c24ad2..d74a19af4a44 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -49,6 +49,27 @@ struct callchain_list {
49 struct list_head list; 49 struct list_head list;
50}; 50};
51 51
52/*
53 * A callchain cursor is a single linked list that
54 * let one feed a callchain progressively.
55 * It keeps persitent allocated entries to minimize
56 * allocations.
57 */
58struct callchain_cursor_node {
59 u64 ip;
60 struct map *map;
61 struct symbol *sym;
62 struct callchain_cursor_node *next;
63};
64
65struct callchain_cursor {
66 u64 nr;
67 struct callchain_cursor_node *first;
68 struct callchain_cursor_node **last;
69 u64 pos;
70 struct callchain_cursor_node *curr;
71};
72
52static inline void callchain_init(struct callchain_root *root) 73static inline void callchain_init(struct callchain_root *root)
53{ 74{
54 INIT_LIST_HEAD(&root->node.brothers); 75 INIT_LIST_HEAD(&root->node.brothers);
@@ -67,9 +88,48 @@ static inline u64 cumul_hits(struct callchain_node *node)
67} 88}
68 89
69int register_callchain_param(struct callchain_param *param); 90int register_callchain_param(struct callchain_param *param);
70int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 91int callchain_append(struct callchain_root *root,
71 struct map_symbol *syms, u64 period); 92 struct callchain_cursor *cursor,
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src); 93 u64 period);
94
95int callchain_merge(struct callchain_cursor *cursor,
96 struct callchain_root *dst, struct callchain_root *src);
73 97
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 98bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
99
100/*
101 * Initialize a cursor before adding entries inside, but keep
102 * the previously allocated entries as a cache.
103 */
104static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
105{
106 cursor->nr = 0;
107 cursor->last = &cursor->first;
108}
109
110int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
111 struct map *map, struct symbol *sym);
112
113/* Close a cursor writing session. Initialize for the reader */
114static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
115{
116 cursor->curr = cursor->first;
117 cursor->pos = 0;
118}
119
120/* Cursor reading iteration helpers */
121static inline struct callchain_cursor_node *
122callchain_cursor_current(struct callchain_cursor *cursor)
123{
124 if (cursor->pos == cursor->nr)
125 return NULL;
126
127 return cursor->curr;
128}
129
130static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
131{
132 cursor->curr = cursor->curr->next;
133 cursor->pos++;
134}
75#endif /* __PERF_CALLCHAIN_H */ 135#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32f4f1f2f6e4..a438a0652d23 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -211,7 +211,9 @@ void hist_entry__free(struct hist_entry *he)
211 * collapse the histogram 211 * collapse the histogram
212 */ 212 */
213 213
214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 214static bool hists__collapse_insert_entry(struct hists *self,
215 struct rb_root *root,
216 struct hist_entry *he)
215{ 217{
216 struct rb_node **p = &root->rb_node; 218 struct rb_node **p = &root->rb_node;
217 struct rb_node *parent = NULL; 219 struct rb_node *parent = NULL;
@@ -226,8 +228,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 228
227 if (!cmp) { 229 if (!cmp) {
228 iter->period += he->period; 230 iter->period += he->period;
229 if (symbol_conf.use_callchain) 231 if (symbol_conf.use_callchain) {
230 callchain_merge(iter->callchain, he->callchain); 232 callchain_cursor_reset(&self->callchain_cursor);
233 callchain_merge(&self->callchain_cursor, iter->callchain,
234 he->callchain);
235 }
231 hist_entry__free(he); 236 hist_entry__free(he);
232 return false; 237 return false;
233 } 238 }
@@ -262,7 +267,7 @@ void hists__collapse_resort(struct hists *self)
262 next = rb_next(&n->rb_node); 267 next = rb_next(&n->rb_node);
263 268
264 rb_erase(&n->rb_node, &self->entries); 269 rb_erase(&n->rb_node, &self->entries);
265 if (collapse__insert_entry(&tmp, n)) 270 if (hists__collapse_insert_entry(self, &tmp, n))
266 hists__inc_nr_entries(self, n); 271 hists__inc_nr_entries(self, n);
267 } 272 }
268 273
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ee789856a8c9..889559b86492 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -77,6 +77,8 @@ struct hists {
77 u64 event_stream; 77 u64 event_stream;
78 u32 type; 78 u32 type;
79 u16 col_len[HISTC_NR_COLS]; 79 u16 col_len[HISTC_NR_COLS];
80 /* Best would be to reuse the session callchain cursor */
81 struct callchain_cursor callchain_cursor;
80}; 82};
81 83
82struct hist_entry *__hists__add_entry(struct hists *self, 84struct hist_entry *__hists__add_entry(struct hists *self,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 105f00bfd555..b58a48a5e5a9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -242,17 +242,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
242 return 0; 242 return 0;
243} 243}
244 244
245struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 245int perf_session__resolve_callchain(struct perf_session *self,
246 struct thread *thread, 246 struct thread *thread,
247 struct ip_callchain *chain, 247 struct ip_callchain *chain,
248 struct symbol **parent) 248 struct symbol **parent)
249{ 249{
250 u8 cpumode = PERF_RECORD_MISC_USER; 250 u8 cpumode = PERF_RECORD_MISC_USER;
251 unsigned int i; 251 unsigned int i;
252 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 252 int err;
253 253
254 if (!syms) 254 callchain_cursor_reset(&self->callchain_cursor);
255 return NULL;
256 255
257 for (i = 0; i < chain->nr; i++) { 256 for (i = 0; i < chain->nr; i++) {
258 u64 ip = chain->ips[i]; 257 u64 ip = chain->ips[i];
@@ -281,12 +280,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
281 *parent = al.sym; 280 *parent = al.sym;
282 if (!symbol_conf.use_callchain) 281 if (!symbol_conf.use_callchain)
283 break; 282 break;
284 syms[i].map = al.map;
285 syms[i].sym = al.sym;
286 } 283 }
284
285 err = callchain_cursor_append(&self->callchain_cursor,
286 ip, al.map, al.sym);
287 if (err)
288 return err;
287 } 289 }
288 290
289 return syms; 291 return 0;
290} 292}
291 293
292static int process_event_synth_stub(event_t *event __used, 294static int process_event_synth_stub(event_t *event __used,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index decd83f274fd..e815468eb888 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -51,7 +51,8 @@ struct perf_session {
51 int cwdlen; 51 int cwdlen;
52 char *cwd; 52 char *cwd;
53 struct ordered_samples ordered_samples; 53 struct ordered_samples ordered_samples;
54 char filename[0]; 54 struct callchain_cursor callchain_cursor;
55 char filename[0];
55}; 56};
56 57
57struct perf_event_ops; 58struct perf_event_ops;
@@ -94,10 +95,10 @@ int __perf_session__process_events(struct perf_session *self,
94int perf_session__process_events(struct perf_session *self, 95int perf_session__process_events(struct perf_session *self,
95 struct perf_event_ops *event_ops); 96 struct perf_event_ops *event_ops);
96 97
97struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 98int perf_session__resolve_callchain(struct perf_session *self,
98 struct thread *thread, 99 struct thread *thread,
99 struct ip_callchain *chain, 100 struct ip_callchain *chain,
100 struct symbol **parent); 101 struct symbol **parent);
101 102
102bool perf_session__has_traces(struct perf_session *self, const char *msg); 103bool perf_session__has_traces(struct perf_session *self, const char *msg);
103 104