aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/util/callchain.c109
-rw-r--r--tools/perf/util/callchain.h4
-rw-r--r--tools/perf/util/hist.c5
4 files changed, 88 insertions, 36 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 1f9f8695f055..d609afbd1a35 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -83,6 +83,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
83{ 83{
84 struct symbol **syms = NULL, *parent = NULL; 84 struct symbol **syms = NULL, *parent = NULL;
85 bool hit; 85 bool hit;
86 int err;
86 struct hist_entry *he; 87 struct hist_entry *he;
87 struct event_stat_id *stats; 88 struct event_stat_id *stats;
88 struct perf_event_attr *attr; 89 struct perf_event_attr *attr;
@@ -109,8 +110,11 @@ static int perf_session__add_hist_entry(struct perf_session *self,
109 if (symbol_conf.use_callchain) { 110 if (symbol_conf.use_callchain) {
110 if (!hit) 111 if (!hit)
111 callchain_init(&he->callchain); 112 callchain_init(&he->callchain);
112 append_chain(&he->callchain, data->callchain, syms); 113 err = append_chain(&he->callchain, data->callchain, syms);
113 free(syms); 114 free(syms);
115
116 if (err)
117 return err;
114 } 118 }
115 119
116 return 0; 120 return 0;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272a..883844eb4b0a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2010, 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.
@@ -183,12 +183,23 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 183 return new;
184} 184}
185 185
186
187struct resolved_ip {
188 u64 ip;
189 struct symbol *sym;
190};
191
192struct resolved_chain {
193 u64 nr;
194 struct resolved_ip ips[0];
195};
196
197
186/* 198/*
187 * Fill the node with callchain values 199 * Fill the node with callchain values
188 */ 200 */
189static void 201static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 202fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 203{
193 unsigned int i; 204 unsigned int i;
194 205
@@ -200,8 +211,8 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
200 perror("not enough memory for the code path tree"); 211 perror("not enough memory for the code path tree");
201 return; 212 return;
202 } 213 }
203 call->ip = chain->ips[i]; 214 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 215 call->sym = chain->ips[i].sym;
205 list_add_tail(&call->list, &node->val); 216 list_add_tail(&call->list, &node->val);
206 } 217 }
207 node->val_nr = chain->nr - start; 218 node->val_nr = chain->nr - start;
@@ -210,13 +221,13 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 221}
211 222
212static void 223static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 224add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 225 int start)
215{ 226{
216 struct callchain_node *new; 227 struct callchain_node *new;
217 228
218 new = create_child(parent, false); 229 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 230 fill_node(new, chain, start);
220 231
221 new->children_hit = 0; 232 new->children_hit = 0;
222 new->hit = 1; 233 new->hit = 1;
@@ -228,9 +239,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 239 * Then create another child to host the given callchain of new branch
229 */ 240 */
230static void 241static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 242split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 243 struct callchain_list *to_split, int idx_parents, int idx_local)
233 struct symbol **syms)
234{ 244{
235 struct callchain_node *new; 245 struct callchain_node *new;
236 struct list_head *old_tail; 246 struct list_head *old_tail;
@@ -257,7 +267,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 267 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 268 if (idx_total < chain->nr) {
259 parent->hit = 0; 269 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 270 add_child(parent, chain, idx_total);
261 parent->children_hit++; 271 parent->children_hit++;
262 } else { 272 } else {
263 parent->hit = 1; 273 parent->hit = 1;
@@ -265,32 +275,33 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
265} 275}
266 276
267static int 277static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 278__append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 279 unsigned int start);
270 280
271static void 281static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 282__append_chain_children(struct callchain_node *root,
273 struct symbol **syms, unsigned int start) 283 struct resolved_chain *chain,
284 unsigned int start)
274{ 285{
275 struct callchain_node *rnode; 286 struct callchain_node *rnode;
276 287
277 /* lookup in childrens */ 288 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 289 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 290 unsigned int ret = __append_chain(rnode, chain, start);
280 291
281 if (!ret) 292 if (!ret)
282 goto inc_children_hit; 293 goto inc_children_hit;
283 } 294 }
284 /* nothing in children, add to the current node */ 295 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 296 add_child(root, chain, start);
286 297
287inc_children_hit: 298inc_children_hit:
288 root->children_hit++; 299 root->children_hit++;
289} 300}
290 301
291static int 302static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 303__append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 304 unsigned int start)
294{ 305{
295 struct callchain_list *cnode; 306 struct callchain_list *cnode;
296 unsigned int i = start; 307 unsigned int i = start;
@@ -302,13 +313,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 313 * anywhere inside a function.
303 */ 314 */
304 list_for_each_entry(cnode, &root->val, list) { 315 list_for_each_entry(cnode, &root->val, list) {
316 struct symbol *sym;
317
305 if (i == chain->nr) 318 if (i == chain->nr)
306 break; 319 break;
307 if (cnode->sym && syms[i]) { 320
308 if (cnode->sym->start != syms[i]->start) 321 sym = chain->ips[i].sym;
322
323 if (cnode->sym && sym) {
324 if (cnode->sym->start != sym->start)
309 break; 325 break;
310 } else if (cnode->ip != chain->ips[i]) 326 } else if (cnode->ip != chain->ips[i].ip)
311 break; 327 break;
328
312 if (!found) 329 if (!found)
313 found = true; 330 found = true;
314 i++; 331 i++;
@@ -320,7 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 337
321 /* we match only a part of the node. Split it and add the new chain */ 338 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 339 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 340 split_add_child(root, chain, cnode, start, i - start);
324 return 0; 341 return 0;
325 } 342 }
326 343
@@ -331,15 +348,51 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
331 } 348 }
332 349
333 /* We match the node and still have a part remaining */ 350 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 351 __append_chain_children(root, chain, i);
335 352
336 return 0; 353 return 0;
337} 354}
338 355
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 356static void
357filter_context(struct ip_callchain *old, struct resolved_chain *new,
358 struct symbol **syms)
359{
360 int i, j = 0;
361
362 for (i = 0; i < (int)old->nr; i++) {
363 if (old->ips[i] >= PERF_CONTEXT_MAX)
364 continue;
365
366 new->ips[j].ip = old->ips[i];
367 new->ips[j].sym = syms[i];
368 j++;
369 }
370
371 new->nr = j;
372}
373
374
375int append_chain(struct callchain_node *root, struct ip_callchain *chain,
340 struct symbol **syms) 376 struct symbol **syms)
341{ 377{
378 struct resolved_chain *filtered;
379
342 if (!chain->nr) 380 if (!chain->nr)
343 return; 381 return 0;
344 __append_chain_children(root, chain, syms, 0); 382
383 filtered = malloc(sizeof(*filtered) +
384 chain->nr * sizeof(struct resolved_ip));
385 if (!filtered)
386 return -ENOMEM;
387
388 filter_context(chain, filtered, syms);
389
390 if (!filtered->nr)
391 goto end;
392
393 __append_chain_children(root, filtered, 0);
394end:
395 free(filtered);
396
397 return 0;
345} 398}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index ad4626de4c2b..bbd76da27f22 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -56,6 +56,6 @@ static inline u64 cumul_hits(struct callchain_node *node)
56} 56}
57 57
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59int append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif /* __PERF_CALLCHAIN_H */ 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index c37da8b88573..5843a9c572ad 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -328,8 +328,6 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
328 left_margin); 328 left_margin);
329 i = 0; 329 i = 0;
330 list_for_each_entry(chain, &child->val, list) { 330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth, 331 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++, 332 new_depth_mask, i++,
335 new_total, 333 new_total,
@@ -368,9 +366,6 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
368 int ret = 0; 366 int ret = 0;
369 367
370 list_for_each_entry(chain, &self->val, list) { 368 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM) 369 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue; 370 continue;
376 371