1 /* 2 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com> 3 * 4 * Handle the callchains from the stream in an ad-hoc radix tree and then 5 * sort them in an rbtree. 6 * 7 * Using a radix for code path provides a fast retrieval and factorizes 8 * memory use. Also that lets us use the paths in a hierarchical graph view. 9 * 10 */ 11 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <stdbool.h> 15 #include <errno.h> 16 #include <math.h> 17 18 #include "asm/bug.h" 19 20 #include "hist.h" 21 #include "util.h" 22 #include "sort.h" 23 #include "machine.h" 24 #include "callchain.h" 25 26 __thread struct callchain_cursor callchain_cursor; 27 28 int parse_callchain_record_opt(const char *arg, struct callchain_param *param) 29 { 30 return parse_callchain_record(arg, param); 31 } 32 33 static int parse_callchain_mode(const char *value) 34 { 35 if (!strncmp(value, "graph", strlen(value))) { 36 callchain_param.mode = CHAIN_GRAPH_ABS; 37 return 0; 38 } 39 if (!strncmp(value, "flat", strlen(value))) { 40 callchain_param.mode = CHAIN_FLAT; 41 return 0; 42 } 43 if (!strncmp(value, "fractal", strlen(value))) { 44 callchain_param.mode = CHAIN_GRAPH_REL; 45 return 0; 46 } 47 return -1; 48 } 49 50 static int parse_callchain_order(const char *value) 51 { 52 if (!strncmp(value, "caller", strlen(value))) { 53 callchain_param.order = ORDER_CALLER; 54 return 0; 55 } 56 if (!strncmp(value, "callee", strlen(value))) { 57 callchain_param.order = ORDER_CALLEE; 58 return 0; 59 } 60 return -1; 61 } 62 63 static int parse_callchain_sort_key(const char *value) 64 { 65 if (!strncmp(value, "function", strlen(value))) { 66 callchain_param.key = CCKEY_FUNCTION; 67 return 0; 68 } 69 if (!strncmp(value, "address", strlen(value))) { 70 callchain_param.key = CCKEY_ADDRESS; 71 return 0; 72 } 73 if (!strncmp(value, "branch", strlen(value))) { 74 callchain_param.branch_callstack = 1; 75 return 0; 76 } 77 return -1; 78 } 79 80 int 81 parse_callchain_report_opt(const char *arg) 82 { 83 char *tok; 84 char *endptr; 85 bool minpcnt_set = false; 86 87 symbol_conf.use_callchain = true; 88 89 if (!arg) 90 return 0; 91 92 while ((tok = strtok((char *)arg, ",")) != NULL) { 93 if (!strncmp(tok, "none", strlen(tok))) { 94 callchain_param.mode = CHAIN_NONE; 95 symbol_conf.use_callchain = false; 96 return 0; 97 } 98 99 if (!parse_callchain_mode(tok) || 100 !parse_callchain_order(tok) || 101 !parse_callchain_sort_key(tok)) { 102 /* parsing ok - move on to the next */ 103 } else if (!minpcnt_set) { 104 /* try to get the min percent */ 105 callchain_param.min_percent = strtod(tok, &endptr); 106 if (tok == endptr) 107 return -1; 108 minpcnt_set = true; 109 } else { 110 /* try print limit at last */ 111 callchain_param.print_limit = strtoul(tok, &endptr, 0); 112 if (tok == endptr) 113 return -1; 114 } 115 116 arg = NULL; 117 } 118 119 if (callchain_register_param(&callchain_param) < 0) { 120 pr_err("Can't register callchain params\n"); 121 return -1; 122 } 123 return 0; 124 } 125 126 int perf_callchain_config(const char *var, const char *value) 127 { 128 char *endptr; 129 130 if (prefixcmp(var, "call-graph.")) 131 return 0; 132 var += sizeof("call-graph.") - 1; 133 134 if (!strcmp(var, "record-mode")) 135 return parse_callchain_record_opt(value, &callchain_param); 136 #ifdef HAVE_DWARF_UNWIND_SUPPORT 137 if (!strcmp(var, "dump-size")) { 138 unsigned long size = 0; 139 int ret; 140 141 ret = get_stack_size(value, &size); 142 callchain_param.dump_size = size; 143 144 return ret; 145 } 146 #endif 147 if (!strcmp(var, "print-type")) 148 return parse_callchain_mode(value); 149 if (!strcmp(var, "order")) 150 return parse_callchain_order(value); 151 if (!strcmp(var, "sort-key")) 152 return parse_callchain_sort_key(value); 153 if (!strcmp(var, "threshold")) { 154 callchain_param.min_percent = strtod(value, &endptr); 155 if (value == endptr) 156 return -1; 157 } 158 if (!strcmp(var, "print-limit")) { 159 callchain_param.print_limit = strtod(value, &endptr); 160 if (value == endptr) 161 return -1; 162 } 163 164 return 0; 165 } 166 167 static void 168 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 169 enum chain_mode mode) 170 { 171 struct rb_node **p = &root->rb_node; 172 struct rb_node *parent = NULL; 173 struct callchain_node *rnode; 174 u64 chain_cumul = callchain_cumul_hits(chain); 175 176 while (*p) { 177 u64 rnode_cumul; 178 179 parent = *p; 180 rnode = rb_entry(parent, struct callchain_node, rb_node); 181 rnode_cumul = callchain_cumul_hits(rnode); 182 183 switch (mode) { 184 case CHAIN_FLAT: 185 if (rnode->hit < chain->hit) 186 p = &(*p)->rb_left; 187 else 188 p = &(*p)->rb_right; 189 break; 190 case CHAIN_GRAPH_ABS: /* Falldown */ 191 case CHAIN_GRAPH_REL: 192 if (rnode_cumul < chain_cumul) 193 p = &(*p)->rb_left; 194 else 195 p = &(*p)->rb_right; 196 break; 197 case CHAIN_NONE: 198 default: 199 break; 200 } 201 } 202 203 rb_link_node(&chain->rb_node, parent, p); 204 rb_insert_color(&chain->rb_node, root); 205 } 206 207 static void 208 __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 209 u64 min_hit) 210 { 211 struct rb_node *n; 212 struct callchain_node *child; 213 214 n = rb_first(&node->rb_root_in); 215 while (n) { 216 child = rb_entry(n, struct callchain_node, rb_node_in); 217 n = rb_next(n); 218 219 __sort_chain_flat(rb_root, child, min_hit); 220 } 221 222 if (node->hit && node->hit >= min_hit) 223 rb_insert_callchain(rb_root, node, CHAIN_FLAT); 224 } 225 226 /* 227 * Once we get every callchains from the stream, we can now 228 * sort them by hit 229 */ 230 static void 231 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root, 232 u64 min_hit, struct callchain_param *param __maybe_unused) 233 { 234 __sort_chain_flat(rb_root, &root->node, min_hit); 235 } 236 237 static void __sort_chain_graph_abs(struct callchain_node *node, 238 u64 min_hit) 239 { 240 struct rb_node *n; 241 struct callchain_node *child; 242 243 node->rb_root = RB_ROOT; 244 n = rb_first(&node->rb_root_in); 245 246 while (n) { 247 child = rb_entry(n, struct callchain_node, rb_node_in); 248 n = rb_next(n); 249 250 __sort_chain_graph_abs(child, min_hit); 251 if (callchain_cumul_hits(child) >= min_hit) 252 rb_insert_callchain(&node->rb_root, child, 253 CHAIN_GRAPH_ABS); 254 } 255 } 256 257 static void 258 sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root, 259 u64 min_hit, struct callchain_param *param __maybe_unused) 260 { 261 __sort_chain_graph_abs(&chain_root->node, min_hit); 262 rb_root->rb_node = chain_root->node.rb_root.rb_node; 263 } 264 265 static void __sort_chain_graph_rel(struct callchain_node *node, 266 double min_percent) 267 { 268 struct rb_node *n; 269 struct callchain_node *child; 270 u64 min_hit; 271 272 node->rb_root = RB_ROOT; 273 min_hit = ceil(node->children_hit * min_percent); 274 275 n = rb_first(&node->rb_root_in); 276 while (n) { 277 child = rb_entry(n, struct callchain_node, rb_node_in); 278 n = rb_next(n); 279 280 __sort_chain_graph_rel(child, min_percent); 281 if (callchain_cumul_hits(child) >= min_hit) 282 rb_insert_callchain(&node->rb_root, child, 283 CHAIN_GRAPH_REL); 284 } 285 } 286 287 static void 288 sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root, 289 u64 min_hit __maybe_unused, struct callchain_param *param) 290 { 291 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0); 292 rb_root->rb_node = chain_root->node.rb_root.rb_node; 293 } 294 295 int callchain_register_param(struct callchain_param *param) 296 { 297 switch (param->mode) { 298 case CHAIN_GRAPH_ABS: 299 param->sort = sort_chain_graph_abs; 300 break; 301 case CHAIN_GRAPH_REL: 302 param->sort = sort_chain_graph_rel; 303 break; 304 case CHAIN_FLAT: 305 param->sort = sort_chain_flat; 306 break; 307 case CHAIN_NONE: 308 default: 309 return -1; 310 } 311 return 0; 312 } 313 314 /* 315 * Create a child for a parent. If inherit_children, then the new child 316 * will become the new parent of it's parent children 317 */ 318 static struct callchain_node * 319 create_child(struct callchain_node *parent, bool inherit_children) 320 { 321 struct callchain_node *new; 322 323 new = zalloc(sizeof(*new)); 324 if (!new) { 325 perror("not enough memory to create child for code path tree"); 326 return NULL; 327 } 328 new->parent = parent; 329 INIT_LIST_HEAD(&new->val); 330 331 if (inherit_children) { 332 struct rb_node *n; 333 struct callchain_node *child; 334 335 new->rb_root_in = parent->rb_root_in; 336 parent->rb_root_in = RB_ROOT; 337 338 n = rb_first(&new->rb_root_in); 339 while (n) { 340 child = rb_entry(n, struct callchain_node, rb_node_in); 341 child->parent = new; 342 n = rb_next(n); 343 } 344 345 /* make it the first child */ 346 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node); 347 rb_insert_color(&new->rb_node_in, &parent->rb_root_in); 348 } 349 350 return new; 351 } 352 353 354 /* 355 * Fill the node with callchain values 356 */ 357 static void 358 fill_node(struct callchain_node *node, struct callchain_cursor *cursor) 359 { 360 struct callchain_cursor_node *cursor_node; 361 362 node->val_nr = cursor->nr - cursor->pos; 363 if (!node->val_nr) 364 pr_warning("Warning: empty node in callchain tree\n"); 365 366 cursor_node = callchain_cursor_current(cursor); 367 368 while (cursor_node) { 369 struct callchain_list *call; 370 371 call = zalloc(sizeof(*call)); 372 if (!call) { 373 perror("not enough memory for the code path tree"); 374 return; 375 } 376 call->ip = cursor_node->ip; 377 call->ms.sym = cursor_node->sym; 378 call->ms.map = cursor_node->map; 379 list_add_tail(&call->list, &node->val); 380 381 callchain_cursor_advance(cursor); 382 cursor_node = callchain_cursor_current(cursor); 383 } 384 } 385 386 static struct callchain_node * 387 add_child(struct callchain_node *parent, 388 struct callchain_cursor *cursor, 389 u64 period) 390 { 391 struct callchain_node *new; 392 393 new = create_child(parent, false); 394 fill_node(new, cursor); 395 396 new->children_hit = 0; 397 new->hit = period; 398 return new; 399 } 400 401 static s64 match_chain(struct callchain_cursor_node *node, 402 struct callchain_list *cnode) 403 { 404 struct symbol *sym = node->sym; 405 406 if (cnode->ms.sym && sym && 407 callchain_param.key == CCKEY_FUNCTION) 408 return cnode->ms.sym->start - sym->start; 409 else 410 return cnode->ip - node->ip; 411 } 412 413 /* 414 * Split the parent in two parts (a new child is created) and 415 * give a part of its callchain to the created child. 416 * Then create another child to host the given callchain of new branch 417 */ 418 static void 419 split_add_child(struct callchain_node *parent, 420 struct callchain_cursor *cursor, 421 struct callchain_list *to_split, 422 u64 idx_parents, u64 idx_local, u64 period) 423 { 424 struct callchain_node *new; 425 struct list_head *old_tail; 426 unsigned int idx_total = idx_parents + idx_local; 427 428 /* split */ 429 new = create_child(parent, true); 430 431 /* split the callchain and move a part to the new child */ 432 old_tail = parent->val.prev; 433 list_del_range(&to_split->list, old_tail); 434 new->val.next = &to_split->list; 435 new->val.prev = old_tail; 436 to_split->list.prev = &new->val; 437 old_tail->next = &new->val; 438 439 /* split the hits */ 440 new->hit = parent->hit; 441 new->children_hit = parent->children_hit; 442 parent->children_hit = callchain_cumul_hits(new); 443 new->val_nr = parent->val_nr - idx_local; 444 parent->val_nr = idx_local; 445 446 /* create a new child for the new branch if any */ 447 if (idx_total < cursor->nr) { 448 struct callchain_node *first; 449 struct callchain_list *cnode; 450 struct callchain_cursor_node *node; 451 struct rb_node *p, **pp; 452 453 parent->hit = 0; 454 parent->children_hit += period; 455 456 node = callchain_cursor_current(cursor); 457 new = add_child(parent, cursor, period); 458 459 /* 460 * This is second child since we moved parent's children 461 * to new (first) child above. 462 */ 463 p = parent->rb_root_in.rb_node; 464 first = rb_entry(p, struct callchain_node, rb_node_in); 465 cnode = list_first_entry(&first->val, struct callchain_list, 466 list); 467 468 if (match_chain(node, cnode) < 0) 469 pp = &p->rb_left; 470 else 471 pp = &p->rb_right; 472 473 rb_link_node(&new->rb_node_in, p, pp); 474 rb_insert_color(&new->rb_node_in, &parent->rb_root_in); 475 } else { 476 parent->hit = period; 477 } 478 } 479 480 static int 481 append_chain(struct callchain_node *root, 482 struct callchain_cursor *cursor, 483 u64 period); 484 485 static void 486 append_chain_children(struct callchain_node *root, 487 struct callchain_cursor *cursor, 488 u64 period) 489 { 490 struct callchain_node *rnode; 491 struct callchain_cursor_node *node; 492 struct rb_node **p = &root->rb_root_in.rb_node; 493 struct rb_node *parent = NULL; 494 495 node = callchain_cursor_current(cursor); 496 if (!node) 497 return; 498 499 /* lookup in childrens */ 500 while (*p) { 501 s64 ret; 502 503 parent = *p; 504 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 505 506 /* If at least first entry matches, rely to children */ 507 ret = append_chain(rnode, cursor, period); 508 if (ret == 0) 509 goto inc_children_hit; 510 511 if (ret < 0) 512 p = &parent->rb_left; 513 else 514 p = &parent->rb_right; 515 } 516 /* nothing in children, add to the current node */ 517 rnode = add_child(root, cursor, period); 518 rb_link_node(&rnode->rb_node_in, parent, p); 519 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in); 520 521 inc_children_hit: 522 root->children_hit += period; 523 } 524 525 static int 526 append_chain(struct callchain_node *root, 527 struct callchain_cursor *cursor, 528 u64 period) 529 { 530 struct callchain_list *cnode; 531 u64 start = cursor->pos; 532 bool found = false; 533 u64 matches; 534 int cmp = 0; 535 536 /* 537 * Lookup in the current node 538 * If we have a symbol, then compare the start to match 539 * anywhere inside a function, unless function 540 * mode is disabled. 541 */ 542 list_for_each_entry(cnode, &root->val, list) { 543 struct callchain_cursor_node *node; 544 545 node = callchain_cursor_current(cursor); 546 if (!node) 547 break; 548 549 cmp = match_chain(node, cnode); 550 if (cmp) 551 break; 552 553 found = true; 554 555 callchain_cursor_advance(cursor); 556 } 557 558 /* matches not, relay no the parent */ 559 if (!found) { 560 WARN_ONCE(!cmp, "Chain comparison error\n"); 561 return cmp; 562 } 563 564 matches = cursor->pos - start; 565 566 /* we match only a part of the node. Split it and add the new chain */ 567 if (matches < root->val_nr) { 568 split_add_child(root, cursor, cnode, start, matches, period); 569 return 0; 570 } 571 572 /* we match 100% of the path, increment the hit */ 573 if (matches == root->val_nr && cursor->pos == cursor->nr) { 574 root->hit += period; 575 return 0; 576 } 577 578 /* We match the node and still have a part remaining */ 579 append_chain_children(root, cursor, period); 580 581 return 0; 582 } 583 584 int callchain_append(struct callchain_root *root, 585 struct callchain_cursor *cursor, 586 u64 period) 587 { 588 if (!cursor->nr) 589 return 0; 590 591 callchain_cursor_commit(cursor); 592 593 append_chain_children(&root->node, cursor, period); 594 595 if (cursor->nr > root->max_depth) 596 root->max_depth = cursor->nr; 597 598 return 0; 599 } 600 601 static int 602 merge_chain_branch(struct callchain_cursor *cursor, 603 struct callchain_node *dst, struct callchain_node *src) 604 { 605 struct callchain_cursor_node **old_last = cursor->last; 606 struct callchain_node *child; 607 struct callchain_list *list, *next_list; 608 struct rb_node *n; 609 int old_pos = cursor->nr; 610 int err = 0; 611 612 list_for_each_entry_safe(list, next_list, &src->val, list) { 613 callchain_cursor_append(cursor, list->ip, 614 list->ms.map, list->ms.sym); 615 list_del(&list->list); 616 free(list); 617 } 618 619 if (src->hit) { 620 callchain_cursor_commit(cursor); 621 append_chain_children(dst, cursor, src->hit); 622 } 623 624 n = rb_first(&src->rb_root_in); 625 while (n) { 626 child = container_of(n, struct callchain_node, rb_node_in); 627 n = rb_next(n); 628 rb_erase(&child->rb_node_in, &src->rb_root_in); 629 630 err = merge_chain_branch(cursor, dst, child); 631 if (err) 632 break; 633 634 free(child); 635 } 636 637 cursor->nr = old_pos; 638 cursor->last = old_last; 639 640 return err; 641 } 642 643 int callchain_merge(struct callchain_cursor *cursor, 644 struct callchain_root *dst, struct callchain_root *src) 645 { 646 return merge_chain_branch(cursor, &dst->node, &src->node); 647 } 648 649 int callchain_cursor_append(struct callchain_cursor *cursor, 650 u64 ip, struct map *map, struct symbol *sym) 651 { 652 struct callchain_cursor_node *node = *cursor->last; 653 654 if (!node) { 655 node = calloc(1, sizeof(*node)); 656 if (!node) 657 return -ENOMEM; 658 659 *cursor->last = node; 660 } 661 662 node->ip = ip; 663 node->map = map; 664 node->sym = sym; 665 666 cursor->nr++; 667 668 cursor->last = &node->next; 669 670 return 0; 671 } 672 673 int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, 674 struct perf_evsel *evsel, struct addr_location *al, 675 int max_stack) 676 { 677 if (sample->callchain == NULL) 678 return 0; 679 680 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || 681 sort__has_parent) { 682 return thread__resolve_callchain(al->thread, evsel, sample, 683 parent, al, max_stack); 684 } 685 return 0; 686 } 687 688 int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) 689 { 690 if (!symbol_conf.use_callchain || sample->callchain == NULL) 691 return 0; 692 return callchain_append(he->callchain, &callchain_cursor, sample->period); 693 } 694 695 int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, 696 bool hide_unresolved) 697 { 698 al->map = node->map; 699 al->sym = node->sym; 700 if (node->map) 701 al->addr = node->map->map_ip(node->map, node->ip); 702 else 703 al->addr = node->ip; 704 705 if (al->sym == NULL) { 706 if (hide_unresolved) 707 return 0; 708 if (al->map == NULL) 709 goto out; 710 } 711 712 if (al->map->groups == &al->machine->kmaps) { 713 if (machine__is_host(al->machine)) { 714 al->cpumode = PERF_RECORD_MISC_KERNEL; 715 al->level = 'k'; 716 } else { 717 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL; 718 al->level = 'g'; 719 } 720 } else { 721 if (machine__is_host(al->machine)) { 722 al->cpumode = PERF_RECORD_MISC_USER; 723 al->level = '.'; 724 } else if (perf_guest) { 725 al->cpumode = PERF_RECORD_MISC_GUEST_USER; 726 al->level = 'u'; 727 } else { 728 al->cpumode = PERF_RECORD_MISC_HYPERVISOR; 729 al->level = 'H'; 730 } 731 } 732 733 out: 734 return 1; 735 } 736 737 char *callchain_list__sym_name(struct callchain_list *cl, 738 char *bf, size_t bfsize, bool show_dso) 739 { 740 int printed; 741 742 if (cl->ms.sym) { 743 if (callchain_param.key == CCKEY_ADDRESS && 744 cl->ms.map && !cl->srcline) 745 cl->srcline = get_srcline(cl->ms.map->dso, 746 map__rip_2objdump(cl->ms.map, 747 cl->ip), 748 cl->ms.sym, false); 749 if (cl->srcline) 750 printed = scnprintf(bf, bfsize, "%s %s", 751 cl->ms.sym->name, cl->srcline); 752 else 753 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); 754 } else 755 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); 756 757 if (show_dso) 758 scnprintf(bf + printed, bfsize - printed, " %s", 759 cl->ms.map ? 760 cl->ms.map->dso->short_name : 761 "unknown"); 762 763 return bf; 764 } 765 766 static void free_callchain_node(struct callchain_node *node) 767 { 768 struct callchain_list *list, *tmp; 769 struct callchain_node *child; 770 struct rb_node *n; 771 772 list_for_each_entry_safe(list, tmp, &node->val, list) { 773 list_del(&list->list); 774 free(list); 775 } 776 777 n = rb_first(&node->rb_root_in); 778 while (n) { 779 child = container_of(n, struct callchain_node, rb_node_in); 780 n = rb_next(n); 781 rb_erase(&child->rb_node_in, &node->rb_root_in); 782 783 free_callchain_node(child); 784 free(child); 785 } 786 } 787 788 void free_callchain(struct callchain_root *root) 789 { 790 if (!symbol_conf.use_callchain) 791 return; 792 793 free_callchain_node(&root->node); 794 } 795