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.c121
1 files changed, 90 insertions, 31 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272..21a52e0a443 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.
@@ -17,6 +17,13 @@
17 17
18#include "callchain.h" 18#include "callchain.h"
19 19
20bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
21{
22 unsigned int chain_size = event->header.size;
23 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
24 return chain->nr * sizeof(u64) <= chain_size;
25}
26
20#define chain_for_each_child(child, parent) \ 27#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers) 28 list_for_each_entry(child, &parent->children, brothers)
22 29
@@ -160,7 +167,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
160{ 167{
161 struct callchain_node *new; 168 struct callchain_node *new;
162 169
163 new = malloc(sizeof(*new)); 170 new = zalloc(sizeof(*new));
164 if (!new) { 171 if (!new) {
165 perror("not enough memory to create child for code path tree"); 172 perror("not enough memory to create child for code path tree");
166 return NULL; 173 return NULL;
@@ -183,25 +190,36 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 190 return new;
184} 191}
185 192
193
194struct resolved_ip {
195 u64 ip;
196 struct map_symbol ms;
197};
198
199struct resolved_chain {
200 u64 nr;
201 struct resolved_ip ips[0];
202};
203
204
186/* 205/*
187 * Fill the node with callchain values 206 * Fill the node with callchain values
188 */ 207 */
189static void 208static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 209fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 210{
193 unsigned int i; 211 unsigned int i;
194 212
195 for (i = start; i < chain->nr; i++) { 213 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call; 214 struct callchain_list *call;
197 215
198 call = malloc(sizeof(*call)); 216 call = zalloc(sizeof(*call));
199 if (!call) { 217 if (!call) {
200 perror("not enough memory for the code path tree"); 218 perror("not enough memory for the code path tree");
201 return; 219 return;
202 } 220 }
203 call->ip = chain->ips[i]; 221 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 222 call->ms = chain->ips[i].ms;
205 list_add_tail(&call->list, &node->val); 223 list_add_tail(&call->list, &node->val);
206 } 224 }
207 node->val_nr = chain->nr - start; 225 node->val_nr = chain->nr - start;
@@ -210,13 +228,13 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 228}
211 229
212static void 230static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 231add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 232 int start)
215{ 233{
216 struct callchain_node *new; 234 struct callchain_node *new;
217 235
218 new = create_child(parent, false); 236 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 237 fill_node(new, chain, start);
220 238
221 new->children_hit = 0; 239 new->children_hit = 0;
222 new->hit = 1; 240 new->hit = 1;
@@ -228,9 +246,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 246 * Then create another child to host the given callchain of new branch
229 */ 247 */
230static void 248static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 249split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 250 struct callchain_list *to_split, int idx_parents, int idx_local)
233 struct symbol **syms)
234{ 251{
235 struct callchain_node *new; 252 struct callchain_node *new;
236 struct list_head *old_tail; 253 struct list_head *old_tail;
@@ -257,7 +274,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 274 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 275 if (idx_total < chain->nr) {
259 parent->hit = 0; 276 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 277 add_child(parent, chain, idx_total);
261 parent->children_hit++; 278 parent->children_hit++;
262 } else { 279 } else {
263 parent->hit = 1; 280 parent->hit = 1;
@@ -265,32 +282,33 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
265} 282}
266 283
267static int 284static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 285__append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 286 unsigned int start);
270 287
271static void 288static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 289__append_chain_children(struct callchain_node *root,
273 struct symbol **syms, unsigned int start) 290 struct resolved_chain *chain,
291 unsigned int start)
274{ 292{
275 struct callchain_node *rnode; 293 struct callchain_node *rnode;
276 294
277 /* lookup in childrens */ 295 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 296 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 297 unsigned int ret = __append_chain(rnode, chain, start);
280 298
281 if (!ret) 299 if (!ret)
282 goto inc_children_hit; 300 goto inc_children_hit;
283 } 301 }
284 /* nothing in children, add to the current node */ 302 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 303 add_child(root, chain, start);
286 304
287inc_children_hit: 305inc_children_hit:
288 root->children_hit++; 306 root->children_hit++;
289} 307}
290 308
291static int 309static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 310__append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 311 unsigned int start)
294{ 312{
295 struct callchain_list *cnode; 313 struct callchain_list *cnode;
296 unsigned int i = start; 314 unsigned int i = start;
@@ -302,13 +320,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 320 * anywhere inside a function.
303 */ 321 */
304 list_for_each_entry(cnode, &root->val, list) { 322 list_for_each_entry(cnode, &root->val, list) {
323 struct symbol *sym;
324
305 if (i == chain->nr) 325 if (i == chain->nr)
306 break; 326 break;
307 if (cnode->sym && syms[i]) { 327
308 if (cnode->sym->start != syms[i]->start) 328 sym = chain->ips[i].ms.sym;
329
330 if (cnode->ms.sym && sym) {
331 if (cnode->ms.sym->start != sym->start)
309 break; 332 break;
310 } else if (cnode->ip != chain->ips[i]) 333 } else if (cnode->ip != chain->ips[i].ip)
311 break; 334 break;
335
312 if (!found) 336 if (!found)
313 found = true; 337 found = true;
314 i++; 338 i++;
@@ -320,7 +344,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 344
321 /* we match only a part of the node. Split it and add the new chain */ 345 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 346 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 347 split_add_child(root, chain, cnode, start, i - start);
324 return 0; 348 return 0;
325 } 349 }
326 350
@@ -331,15 +355,50 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
331 } 355 }
332 356
333 /* We match the node and still have a part remaining */ 357 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 358 __append_chain_children(root, chain, i);
335 359
336 return 0; 360 return 0;
337} 361}
338 362
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 363static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
340 struct symbol **syms) 364 struct map_symbol *syms)
341{ 365{
366 int i, j = 0;
367
368 for (i = 0; i < (int)old->nr; i++) {
369 if (old->ips[i] >= PERF_CONTEXT_MAX)
370 continue;
371
372 new->ips[j].ip = old->ips[i];
373 new->ips[j].ms = syms[i];
374 j++;
375 }
376
377 new->nr = j;
378}
379
380
381int append_chain(struct callchain_node *root, struct ip_callchain *chain,
382 struct map_symbol *syms)
383{
384 struct resolved_chain *filtered;
385
342 if (!chain->nr) 386 if (!chain->nr)
343 return; 387 return 0;
344 __append_chain_children(root, chain, syms, 0); 388
389 filtered = zalloc(sizeof(*filtered) +
390 chain->nr * sizeof(struct resolved_ip));
391 if (!filtered)
392 return -ENOMEM;
393
394 filter_context(chain, filtered, syms);
395
396 if (!filtered->nr)
397 goto end;
398
399 __append_chain_children(root, filtered, 0);
400end:
401 free(filtered);
402
403 return 0;
345} 404}