diff options
-rw-r--r-- | tools/perf/builtin-report.c | 6 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 109 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 4 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 5 |
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 | |||
187 | struct resolved_ip { | ||
188 | u64 ip; | ||
189 | struct symbol *sym; | ||
190 | }; | ||
191 | |||
192 | struct 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 | */ |
189 | static void | 201 | static void |
190 | fill_node(struct callchain_node *node, struct ip_callchain *chain, | 202 | fill_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 | ||
212 | static void | 223 | static void |
213 | add_child(struct callchain_node *parent, struct ip_callchain *chain, | 224 | add_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 | */ |
230 | static void | 241 | static void |
231 | split_add_child(struct callchain_node *parent, struct ip_callchain *chain, | 242 | split_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 | ||
267 | static int | 277 | static 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 | ||
271 | static void | 281 | static 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 | ||
287 | inc_children_hit: | 298 | inc_children_hit: |
288 | root->children_hit++; | 299 | root->children_hit++; |
289 | } | 300 | } |
290 | 301 | ||
291 | static int | 302 | static 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 | ||
339 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, | 356 | static void |
357 | filter_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 | |||
375 | int 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); | ||
394 | end: | ||
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 | ||
58 | int register_callchain_param(struct callchain_param *param); | 58 | int register_callchain_param(struct callchain_param *param); |
59 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, | 59 | int 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 | ||