Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31-rc9 1505 lines 29 kB view raw
1/* 2 * builtin-annotate.c 3 * 4 * Builtin annotate command: Analyze the perf.data input file, 5 * look up and read DSOs and symbol information and display 6 * a histogram of results, along various sorting keys. 7 */ 8#include "builtin.h" 9 10#include "util/util.h" 11 12#include "util/color.h" 13#include <linux/list.h> 14#include "util/cache.h" 15#include <linux/rbtree.h> 16#include "util/symbol.h" 17#include "util/string.h" 18 19#include "perf.h" 20 21#include "util/parse-options.h" 22#include "util/parse-events.h" 23 24#define SHOW_KERNEL 1 25#define SHOW_USER 2 26#define SHOW_HV 4 27 28static char const *input_name = "perf.data"; 29static char *vmlinux = "vmlinux"; 30 31static char default_sort_order[] = "comm,symbol"; 32static char *sort_order = default_sort_order; 33 34static int force; 35static int input; 36static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 37 38static int dump_trace = 0; 39#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) 40 41static int verbose; 42 43static int modules; 44 45static int full_paths; 46 47static int print_line; 48 49static unsigned long page_size; 50static unsigned long mmap_window = 32; 51 52struct ip_event { 53 struct perf_event_header header; 54 u64 ip; 55 u32 pid, tid; 56}; 57 58struct mmap_event { 59 struct perf_event_header header; 60 u32 pid, tid; 61 u64 start; 62 u64 len; 63 u64 pgoff; 64 char filename[PATH_MAX]; 65}; 66 67struct comm_event { 68 struct perf_event_header header; 69 u32 pid, tid; 70 char comm[16]; 71}; 72 73struct fork_event { 74 struct perf_event_header header; 75 u32 pid, ppid; 76}; 77 78typedef union event_union { 79 struct perf_event_header header; 80 struct ip_event ip; 81 struct mmap_event mmap; 82 struct comm_event comm; 83 struct fork_event fork; 84} event_t; 85 86 87struct sym_ext { 88 struct rb_node node; 89 double percent; 90 char *path; 91}; 92 93static LIST_HEAD(dsos); 94static struct dso *kernel_dso; 95static struct dso *vdso; 96 97 98static void dsos__add(struct dso *dso) 99{ 100 list_add_tail(&dso->node, &dsos); 101} 102 103static struct dso *dsos__find(const char *name) 104{ 105 struct dso *pos; 106 107 list_for_each_entry(pos, &dsos, node) 108 if (strcmp(pos->name, name) == 0) 109 return pos; 110 return NULL; 111} 112 113static struct dso *dsos__findnew(const char *name) 114{ 115 struct dso *dso = dsos__find(name); 116 int nr; 117 118 if (dso) 119 return dso; 120 121 dso = dso__new(name, 0); 122 if (!dso) 123 goto out_delete_dso; 124 125 nr = dso__load(dso, NULL, verbose); 126 if (nr < 0) { 127 if (verbose) 128 fprintf(stderr, "Failed to open: %s\n", name); 129 goto out_delete_dso; 130 } 131 if (!nr && verbose) { 132 fprintf(stderr, 133 "No symbols found in: %s, maybe install a debug package?\n", 134 name); 135 } 136 137 dsos__add(dso); 138 139 return dso; 140 141out_delete_dso: 142 dso__delete(dso); 143 return NULL; 144} 145 146static void dsos__fprintf(FILE *fp) 147{ 148 struct dso *pos; 149 150 list_for_each_entry(pos, &dsos, node) 151 dso__fprintf(pos, fp); 152} 153 154static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 155{ 156 return dso__find_symbol(dso, ip); 157} 158 159static int load_kernel(void) 160{ 161 int err; 162 163 kernel_dso = dso__new("[kernel]", 0); 164 if (!kernel_dso) 165 return -1; 166 167 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); 168 if (err <= 0) { 169 dso__delete(kernel_dso); 170 kernel_dso = NULL; 171 } else 172 dsos__add(kernel_dso); 173 174 vdso = dso__new("[vdso]", 0); 175 if (!vdso) 176 return -1; 177 178 vdso->find_symbol = vdso__find_symbol; 179 180 dsos__add(vdso); 181 182 return err; 183} 184 185struct map { 186 struct list_head node; 187 u64 start; 188 u64 end; 189 u64 pgoff; 190 u64 (*map_ip)(struct map *, u64); 191 struct dso *dso; 192}; 193 194static u64 map__map_ip(struct map *map, u64 ip) 195{ 196 return ip - map->start + map->pgoff; 197} 198 199static u64 vdso__map_ip(struct map *map __used, u64 ip) 200{ 201 return ip; 202} 203 204static struct map *map__new(struct mmap_event *event) 205{ 206 struct map *self = malloc(sizeof(*self)); 207 208 if (self != NULL) { 209 const char *filename = event->filename; 210 211 self->start = event->start; 212 self->end = event->start + event->len; 213 self->pgoff = event->pgoff; 214 215 self->dso = dsos__findnew(filename); 216 if (self->dso == NULL) 217 goto out_delete; 218 219 if (self->dso == vdso) 220 self->map_ip = vdso__map_ip; 221 else 222 self->map_ip = map__map_ip; 223 } 224 return self; 225out_delete: 226 free(self); 227 return NULL; 228} 229 230static struct map *map__clone(struct map *self) 231{ 232 struct map *map = malloc(sizeof(*self)); 233 234 if (!map) 235 return NULL; 236 237 memcpy(map, self, sizeof(*self)); 238 239 return map; 240} 241 242static int map__overlap(struct map *l, struct map *r) 243{ 244 if (l->start > r->start) { 245 struct map *t = l; 246 l = r; 247 r = t; 248 } 249 250 if (l->end > r->start) 251 return 1; 252 253 return 0; 254} 255 256static size_t map__fprintf(struct map *self, FILE *fp) 257{ 258 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 259 self->start, self->end, self->pgoff, self->dso->name); 260} 261 262 263struct thread { 264 struct rb_node rb_node; 265 struct list_head maps; 266 pid_t pid; 267 char *comm; 268}; 269 270static struct thread *thread__new(pid_t pid) 271{ 272 struct thread *self = malloc(sizeof(*self)); 273 274 if (self != NULL) { 275 self->pid = pid; 276 self->comm = malloc(32); 277 if (self->comm) 278 snprintf(self->comm, 32, ":%d", self->pid); 279 INIT_LIST_HEAD(&self->maps); 280 } 281 282 return self; 283} 284 285static int thread__set_comm(struct thread *self, const char *comm) 286{ 287 if (self->comm) 288 free(self->comm); 289 self->comm = strdup(comm); 290 return self->comm ? 0 : -ENOMEM; 291} 292 293static size_t thread__fprintf(struct thread *self, FILE *fp) 294{ 295 struct map *pos; 296 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 297 298 list_for_each_entry(pos, &self->maps, node) 299 ret += map__fprintf(pos, fp); 300 301 return ret; 302} 303 304 305static struct rb_root threads; 306static struct thread *last_match; 307 308static struct thread *threads__findnew(pid_t pid) 309{ 310 struct rb_node **p = &threads.rb_node; 311 struct rb_node *parent = NULL; 312 struct thread *th; 313 314 /* 315 * Font-end cache - PID lookups come in blocks, 316 * so most of the time we dont have to look up 317 * the full rbtree: 318 */ 319 if (last_match && last_match->pid == pid) 320 return last_match; 321 322 while (*p != NULL) { 323 parent = *p; 324 th = rb_entry(parent, struct thread, rb_node); 325 326 if (th->pid == pid) { 327 last_match = th; 328 return th; 329 } 330 331 if (pid < th->pid) 332 p = &(*p)->rb_left; 333 else 334 p = &(*p)->rb_right; 335 } 336 337 th = thread__new(pid); 338 if (th != NULL) { 339 rb_link_node(&th->rb_node, parent, p); 340 rb_insert_color(&th->rb_node, &threads); 341 last_match = th; 342 } 343 344 return th; 345} 346 347static void thread__insert_map(struct thread *self, struct map *map) 348{ 349 struct map *pos, *tmp; 350 351 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 352 if (map__overlap(pos, map)) { 353 list_del_init(&pos->node); 354 /* XXX leaks dsos */ 355 free(pos); 356 } 357 } 358 359 list_add_tail(&map->node, &self->maps); 360} 361 362static int thread__fork(struct thread *self, struct thread *parent) 363{ 364 struct map *map; 365 366 if (self->comm) 367 free(self->comm); 368 self->comm = strdup(parent->comm); 369 if (!self->comm) 370 return -ENOMEM; 371 372 list_for_each_entry(map, &parent->maps, node) { 373 struct map *new = map__clone(map); 374 if (!new) 375 return -ENOMEM; 376 thread__insert_map(self, new); 377 } 378 379 return 0; 380} 381 382static struct map *thread__find_map(struct thread *self, u64 ip) 383{ 384 struct map *pos; 385 386 if (self == NULL) 387 return NULL; 388 389 list_for_each_entry(pos, &self->maps, node) 390 if (ip >= pos->start && ip <= pos->end) 391 return pos; 392 393 return NULL; 394} 395 396static size_t threads__fprintf(FILE *fp) 397{ 398 size_t ret = 0; 399 struct rb_node *nd; 400 401 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 402 struct thread *pos = rb_entry(nd, struct thread, rb_node); 403 404 ret += thread__fprintf(pos, fp); 405 } 406 407 return ret; 408} 409 410/* 411 * histogram, sorted on item, collects counts 412 */ 413 414static struct rb_root hist; 415 416struct hist_entry { 417 struct rb_node rb_node; 418 419 struct thread *thread; 420 struct map *map; 421 struct dso *dso; 422 struct symbol *sym; 423 u64 ip; 424 char level; 425 426 uint32_t count; 427}; 428 429/* 430 * configurable sorting bits 431 */ 432 433struct sort_entry { 434 struct list_head list; 435 436 char *header; 437 438 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 439 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 440 size_t (*print)(FILE *fp, struct hist_entry *); 441}; 442 443/* --sort pid */ 444 445static int64_t 446sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 447{ 448 return right->thread->pid - left->thread->pid; 449} 450 451static size_t 452sort__thread_print(FILE *fp, struct hist_entry *self) 453{ 454 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 455} 456 457static struct sort_entry sort_thread = { 458 .header = " Command: Pid", 459 .cmp = sort__thread_cmp, 460 .print = sort__thread_print, 461}; 462 463/* --sort comm */ 464 465static int64_t 466sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 467{ 468 return right->thread->pid - left->thread->pid; 469} 470 471static int64_t 472sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 473{ 474 char *comm_l = left->thread->comm; 475 char *comm_r = right->thread->comm; 476 477 if (!comm_l || !comm_r) { 478 if (!comm_l && !comm_r) 479 return 0; 480 else if (!comm_l) 481 return -1; 482 else 483 return 1; 484 } 485 486 return strcmp(comm_l, comm_r); 487} 488 489static size_t 490sort__comm_print(FILE *fp, struct hist_entry *self) 491{ 492 return fprintf(fp, "%16s", self->thread->comm); 493} 494 495static struct sort_entry sort_comm = { 496 .header = " Command", 497 .cmp = sort__comm_cmp, 498 .collapse = sort__comm_collapse, 499 .print = sort__comm_print, 500}; 501 502/* --sort dso */ 503 504static int64_t 505sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 506{ 507 struct dso *dso_l = left->dso; 508 struct dso *dso_r = right->dso; 509 510 if (!dso_l || !dso_r) { 511 if (!dso_l && !dso_r) 512 return 0; 513 else if (!dso_l) 514 return -1; 515 else 516 return 1; 517 } 518 519 return strcmp(dso_l->name, dso_r->name); 520} 521 522static size_t 523sort__dso_print(FILE *fp, struct hist_entry *self) 524{ 525 if (self->dso) 526 return fprintf(fp, "%-25s", self->dso->name); 527 528 return fprintf(fp, "%016llx ", (u64)self->ip); 529} 530 531static struct sort_entry sort_dso = { 532 .header = "Shared Object ", 533 .cmp = sort__dso_cmp, 534 .print = sort__dso_print, 535}; 536 537/* --sort symbol */ 538 539static int64_t 540sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 541{ 542 u64 ip_l, ip_r; 543 544 if (left->sym == right->sym) 545 return 0; 546 547 ip_l = left->sym ? left->sym->start : left->ip; 548 ip_r = right->sym ? right->sym->start : right->ip; 549 550 return (int64_t)(ip_r - ip_l); 551} 552 553static size_t 554sort__sym_print(FILE *fp, struct hist_entry *self) 555{ 556 size_t ret = 0; 557 558 if (verbose) 559 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 560 561 if (self->sym) { 562 ret += fprintf(fp, "[%c] %s", 563 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 564 } else { 565 ret += fprintf(fp, "%#016llx", (u64)self->ip); 566 } 567 568 return ret; 569} 570 571static struct sort_entry sort_sym = { 572 .header = "Symbol", 573 .cmp = sort__sym_cmp, 574 .print = sort__sym_print, 575}; 576 577static int sort__need_collapse = 0; 578 579struct sort_dimension { 580 char *name; 581 struct sort_entry *entry; 582 int taken; 583}; 584 585static struct sort_dimension sort_dimensions[] = { 586 { .name = "pid", .entry = &sort_thread, }, 587 { .name = "comm", .entry = &sort_comm, }, 588 { .name = "dso", .entry = &sort_dso, }, 589 { .name = "symbol", .entry = &sort_sym, }, 590}; 591 592static LIST_HEAD(hist_entry__sort_list); 593 594static int sort_dimension__add(char *tok) 595{ 596 unsigned int i; 597 598 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 599 struct sort_dimension *sd = &sort_dimensions[i]; 600 601 if (sd->taken) 602 continue; 603 604 if (strncasecmp(tok, sd->name, strlen(tok))) 605 continue; 606 607 if (sd->entry->collapse) 608 sort__need_collapse = 1; 609 610 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 611 sd->taken = 1; 612 613 return 0; 614 } 615 616 return -ESRCH; 617} 618 619static int64_t 620hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 621{ 622 struct sort_entry *se; 623 int64_t cmp = 0; 624 625 list_for_each_entry(se, &hist_entry__sort_list, list) { 626 cmp = se->cmp(left, right); 627 if (cmp) 628 break; 629 } 630 631 return cmp; 632} 633 634static int64_t 635hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 636{ 637 struct sort_entry *se; 638 int64_t cmp = 0; 639 640 list_for_each_entry(se, &hist_entry__sort_list, list) { 641 int64_t (*f)(struct hist_entry *, struct hist_entry *); 642 643 f = se->collapse ?: se->cmp; 644 645 cmp = f(left, right); 646 if (cmp) 647 break; 648 } 649 650 return cmp; 651} 652 653/* 654 * collect histogram counts 655 */ 656static void hist_hit(struct hist_entry *he, u64 ip) 657{ 658 unsigned int sym_size, offset; 659 struct symbol *sym = he->sym; 660 661 he->count++; 662 663 if (!sym || !sym->hist) 664 return; 665 666 sym_size = sym->end - sym->start; 667 offset = ip - sym->start; 668 669 if (offset >= sym_size) 670 return; 671 672 sym->hist_sum++; 673 sym->hist[offset]++; 674 675 if (verbose >= 3) 676 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 677 (void *)(unsigned long)he->sym->start, 678 he->sym->name, 679 (void *)(unsigned long)ip, ip - he->sym->start, 680 sym->hist[offset]); 681} 682 683static int 684hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 685 struct symbol *sym, u64 ip, char level) 686{ 687 struct rb_node **p = &hist.rb_node; 688 struct rb_node *parent = NULL; 689 struct hist_entry *he; 690 struct hist_entry entry = { 691 .thread = thread, 692 .map = map, 693 .dso = dso, 694 .sym = sym, 695 .ip = ip, 696 .level = level, 697 .count = 1, 698 }; 699 int cmp; 700 701 while (*p != NULL) { 702 parent = *p; 703 he = rb_entry(parent, struct hist_entry, rb_node); 704 705 cmp = hist_entry__cmp(&entry, he); 706 707 if (!cmp) { 708 hist_hit(he, ip); 709 710 return 0; 711 } 712 713 if (cmp < 0) 714 p = &(*p)->rb_left; 715 else 716 p = &(*p)->rb_right; 717 } 718 719 he = malloc(sizeof(*he)); 720 if (!he) 721 return -ENOMEM; 722 *he = entry; 723 rb_link_node(&he->rb_node, parent, p); 724 rb_insert_color(&he->rb_node, &hist); 725 726 return 0; 727} 728 729static void hist_entry__free(struct hist_entry *he) 730{ 731 free(he); 732} 733 734/* 735 * collapse the histogram 736 */ 737 738static struct rb_root collapse_hists; 739 740static void collapse__insert_entry(struct hist_entry *he) 741{ 742 struct rb_node **p = &collapse_hists.rb_node; 743 struct rb_node *parent = NULL; 744 struct hist_entry *iter; 745 int64_t cmp; 746 747 while (*p != NULL) { 748 parent = *p; 749 iter = rb_entry(parent, struct hist_entry, rb_node); 750 751 cmp = hist_entry__collapse(iter, he); 752 753 if (!cmp) { 754 iter->count += he->count; 755 hist_entry__free(he); 756 return; 757 } 758 759 if (cmp < 0) 760 p = &(*p)->rb_left; 761 else 762 p = &(*p)->rb_right; 763 } 764 765 rb_link_node(&he->rb_node, parent, p); 766 rb_insert_color(&he->rb_node, &collapse_hists); 767} 768 769static void collapse__resort(void) 770{ 771 struct rb_node *next; 772 struct hist_entry *n; 773 774 if (!sort__need_collapse) 775 return; 776 777 next = rb_first(&hist); 778 while (next) { 779 n = rb_entry(next, struct hist_entry, rb_node); 780 next = rb_next(&n->rb_node); 781 782 rb_erase(&n->rb_node, &hist); 783 collapse__insert_entry(n); 784 } 785} 786 787/* 788 * reverse the map, sort on count. 789 */ 790 791static struct rb_root output_hists; 792 793static void output__insert_entry(struct hist_entry *he) 794{ 795 struct rb_node **p = &output_hists.rb_node; 796 struct rb_node *parent = NULL; 797 struct hist_entry *iter; 798 799 while (*p != NULL) { 800 parent = *p; 801 iter = rb_entry(parent, struct hist_entry, rb_node); 802 803 if (he->count > iter->count) 804 p = &(*p)->rb_left; 805 else 806 p = &(*p)->rb_right; 807 } 808 809 rb_link_node(&he->rb_node, parent, p); 810 rb_insert_color(&he->rb_node, &output_hists); 811} 812 813static void output__resort(void) 814{ 815 struct rb_node *next; 816 struct hist_entry *n; 817 struct rb_root *tree = &hist; 818 819 if (sort__need_collapse) 820 tree = &collapse_hists; 821 822 next = rb_first(tree); 823 824 while (next) { 825 n = rb_entry(next, struct hist_entry, rb_node); 826 next = rb_next(&n->rb_node); 827 828 rb_erase(&n->rb_node, tree); 829 output__insert_entry(n); 830 } 831} 832 833static void register_idle_thread(void) 834{ 835 struct thread *thread = threads__findnew(0); 836 837 if (thread == NULL || 838 thread__set_comm(thread, "[idle]")) { 839 fprintf(stderr, "problem inserting idle task.\n"); 840 exit(-1); 841 } 842} 843 844static unsigned long total = 0, 845 total_mmap = 0, 846 total_comm = 0, 847 total_fork = 0, 848 total_unknown = 0; 849 850static int 851process_sample_event(event_t *event, unsigned long offset, unsigned long head) 852{ 853 char level; 854 int show = 0; 855 struct dso *dso = NULL; 856 struct thread *thread = threads__findnew(event->ip.pid); 857 u64 ip = event->ip.ip; 858 struct map *map = NULL; 859 860 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 861 (void *)(offset + head), 862 (void *)(long)(event->header.size), 863 event->header.misc, 864 event->ip.pid, 865 (void *)(long)ip); 866 867 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 868 869 if (thread == NULL) { 870 fprintf(stderr, "problem processing %d event, skipping it.\n", 871 event->header.type); 872 return -1; 873 } 874 875 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 876 show = SHOW_KERNEL; 877 level = 'k'; 878 879 dso = kernel_dso; 880 881 dprintf(" ...... dso: %s\n", dso->name); 882 883 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 884 885 show = SHOW_USER; 886 level = '.'; 887 888 map = thread__find_map(thread, ip); 889 if (map != NULL) { 890 ip = map->map_ip(map, ip); 891 dso = map->dso; 892 } else { 893 /* 894 * If this is outside of all known maps, 895 * and is a negative address, try to look it 896 * up in the kernel dso, as it might be a 897 * vsyscall (which executes in user-mode): 898 */ 899 if ((long long)ip < 0) 900 dso = kernel_dso; 901 } 902 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 903 904 } else { 905 show = SHOW_HV; 906 level = 'H'; 907 dprintf(" ...... dso: [hypervisor]\n"); 908 } 909 910 if (show & show_mask) { 911 struct symbol *sym = NULL; 912 913 if (dso) 914 sym = dso->find_symbol(dso, ip); 915 916 if (hist_entry__add(thread, map, dso, sym, ip, level)) { 917 fprintf(stderr, 918 "problem incrementing symbol count, skipping event\n"); 919 return -1; 920 } 921 } 922 total++; 923 924 return 0; 925} 926 927static int 928process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 929{ 930 struct thread *thread = threads__findnew(event->mmap.pid); 931 struct map *map = map__new(&event->mmap); 932 933 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 934 (void *)(offset + head), 935 (void *)(long)(event->header.size), 936 event->mmap.pid, 937 (void *)(long)event->mmap.start, 938 (void *)(long)event->mmap.len, 939 (void *)(long)event->mmap.pgoff, 940 event->mmap.filename); 941 942 if (thread == NULL || map == NULL) { 943 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); 944 return 0; 945 } 946 947 thread__insert_map(thread, map); 948 total_mmap++; 949 950 return 0; 951} 952 953static int 954process_comm_event(event_t *event, unsigned long offset, unsigned long head) 955{ 956 struct thread *thread = threads__findnew(event->comm.pid); 957 958 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", 959 (void *)(offset + head), 960 (void *)(long)(event->header.size), 961 event->comm.comm, event->comm.pid); 962 963 if (thread == NULL || 964 thread__set_comm(thread, event->comm.comm)) { 965 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); 966 return -1; 967 } 968 total_comm++; 969 970 return 0; 971} 972 973static int 974process_fork_event(event_t *event, unsigned long offset, unsigned long head) 975{ 976 struct thread *thread = threads__findnew(event->fork.pid); 977 struct thread *parent = threads__findnew(event->fork.ppid); 978 979 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 980 (void *)(offset + head), 981 (void *)(long)(event->header.size), 982 event->fork.pid, event->fork.ppid); 983 984 /* 985 * A thread clone will have the same PID for both 986 * parent and child. 987 */ 988 if (thread == parent) 989 return 0; 990 991 if (!thread || !parent || thread__fork(thread, parent)) { 992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 993 return -1; 994 } 995 total_fork++; 996 997 return 0; 998} 999 1000static int 1001process_event(event_t *event, unsigned long offset, unsigned long head) 1002{ 1003 switch (event->header.type) { 1004 case PERF_EVENT_SAMPLE: 1005 return process_sample_event(event, offset, head); 1006 1007 case PERF_EVENT_MMAP: 1008 return process_mmap_event(event, offset, head); 1009 1010 case PERF_EVENT_COMM: 1011 return process_comm_event(event, offset, head); 1012 1013 case PERF_EVENT_FORK: 1014 return process_fork_event(event, offset, head); 1015 /* 1016 * We dont process them right now but they are fine: 1017 */ 1018 1019 case PERF_EVENT_THROTTLE: 1020 case PERF_EVENT_UNTHROTTLE: 1021 return 0; 1022 1023 default: 1024 return -1; 1025 } 1026 1027 return 0; 1028} 1029 1030static int 1031parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 1032{ 1033 char *line = NULL, *tmp, *tmp2; 1034 static const char *prev_line; 1035 static const char *prev_color; 1036 unsigned int offset; 1037 size_t line_len; 1038 s64 line_ip; 1039 int ret; 1040 char *c; 1041 1042 if (getline(&line, &line_len, file) < 0) 1043 return -1; 1044 if (!line) 1045 return -1; 1046 1047 c = strchr(line, '\n'); 1048 if (c) 1049 *c = 0; 1050 1051 line_ip = -1; 1052 offset = 0; 1053 ret = -2; 1054 1055 /* 1056 * Strip leading spaces: 1057 */ 1058 tmp = line; 1059 while (*tmp) { 1060 if (*tmp != ' ') 1061 break; 1062 tmp++; 1063 } 1064 1065 if (*tmp) { 1066 /* 1067 * Parse hexa addresses followed by ':' 1068 */ 1069 line_ip = strtoull(tmp, &tmp2, 16); 1070 if (*tmp2 != ':') 1071 line_ip = -1; 1072 } 1073 1074 if (line_ip != -1) { 1075 const char *path = NULL; 1076 unsigned int hits = 0; 1077 double percent = 0.0; 1078 char *color; 1079 struct sym_ext *sym_ext = sym->priv; 1080 1081 offset = line_ip - start; 1082 if (offset < len) 1083 hits = sym->hist[offset]; 1084 1085 if (offset < len && sym_ext) { 1086 path = sym_ext[offset].path; 1087 percent = sym_ext[offset].percent; 1088 } else if (sym->hist_sum) 1089 percent = 100.0 * hits / sym->hist_sum; 1090 1091 color = get_percent_color(percent); 1092 1093 /* 1094 * Also color the filename and line if needed, with 1095 * the same color than the percentage. Don't print it 1096 * twice for close colored ip with the same filename:line 1097 */ 1098 if (path) { 1099 if (!prev_line || strcmp(prev_line, path) 1100 || color != prev_color) { 1101 color_fprintf(stdout, color, " %s", path); 1102 prev_line = path; 1103 prev_color = color; 1104 } 1105 } 1106 1107 color_fprintf(stdout, color, " %7.2f", percent); 1108 printf(" : "); 1109 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 1110 } else { 1111 if (!*line) 1112 printf(" :\n"); 1113 else 1114 printf(" : %s\n", line); 1115 } 1116 1117 return 0; 1118} 1119 1120static struct rb_root root_sym_ext; 1121 1122static void insert_source_line(struct sym_ext *sym_ext) 1123{ 1124 struct sym_ext *iter; 1125 struct rb_node **p = &root_sym_ext.rb_node; 1126 struct rb_node *parent = NULL; 1127 1128 while (*p != NULL) { 1129 parent = *p; 1130 iter = rb_entry(parent, struct sym_ext, node); 1131 1132 if (sym_ext->percent > iter->percent) 1133 p = &(*p)->rb_left; 1134 else 1135 p = &(*p)->rb_right; 1136 } 1137 1138 rb_link_node(&sym_ext->node, parent, p); 1139 rb_insert_color(&sym_ext->node, &root_sym_ext); 1140} 1141 1142static void free_source_line(struct symbol *sym, int len) 1143{ 1144 struct sym_ext *sym_ext = sym->priv; 1145 int i; 1146 1147 if (!sym_ext) 1148 return; 1149 1150 for (i = 0; i < len; i++) 1151 free(sym_ext[i].path); 1152 free(sym_ext); 1153 1154 sym->priv = NULL; 1155 root_sym_ext = RB_ROOT; 1156} 1157 1158/* Get the filename:line for the colored entries */ 1159static void 1160get_source_line(struct symbol *sym, u64 start, int len, char *filename) 1161{ 1162 int i; 1163 char cmd[PATH_MAX * 2]; 1164 struct sym_ext *sym_ext; 1165 1166 if (!sym->hist_sum) 1167 return; 1168 1169 sym->priv = calloc(len, sizeof(struct sym_ext)); 1170 if (!sym->priv) 1171 return; 1172 1173 sym_ext = sym->priv; 1174 1175 for (i = 0; i < len; i++) { 1176 char *path = NULL; 1177 size_t line_len; 1178 u64 offset; 1179 FILE *fp; 1180 1181 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 1182 if (sym_ext[i].percent <= 0.5) 1183 continue; 1184 1185 offset = start + i; 1186 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 1187 fp = popen(cmd, "r"); 1188 if (!fp) 1189 continue; 1190 1191 if (getline(&path, &line_len, fp) < 0 || !line_len) 1192 goto next; 1193 1194 sym_ext[i].path = malloc(sizeof(char) * line_len + 1); 1195 if (!sym_ext[i].path) 1196 goto next; 1197 1198 strcpy(sym_ext[i].path, path); 1199 insert_source_line(&sym_ext[i]); 1200 1201 next: 1202 pclose(fp); 1203 } 1204} 1205 1206static void print_summary(char *filename) 1207{ 1208 struct sym_ext *sym_ext; 1209 struct rb_node *node; 1210 1211 printf("\nSorted summary for file %s\n", filename); 1212 printf("----------------------------------------------\n\n"); 1213 1214 if (RB_EMPTY_ROOT(&root_sym_ext)) { 1215 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 1216 return; 1217 } 1218 1219 node = rb_first(&root_sym_ext); 1220 while (node) { 1221 double percent; 1222 char *color; 1223 char *path; 1224 1225 sym_ext = rb_entry(node, struct sym_ext, node); 1226 percent = sym_ext->percent; 1227 color = get_percent_color(percent); 1228 path = sym_ext->path; 1229 1230 color_fprintf(stdout, color, " %7.2f %s", percent, path); 1231 node = rb_next(node); 1232 } 1233} 1234 1235static void annotate_sym(struct dso *dso, struct symbol *sym) 1236{ 1237 char *filename = dso->name, *d_filename; 1238 u64 start, end, len; 1239 char command[PATH_MAX*2]; 1240 FILE *file; 1241 1242 if (!filename) 1243 return; 1244 if (sym->module) 1245 filename = sym->module->path; 1246 else if (dso == kernel_dso) 1247 filename = vmlinux; 1248 1249 start = sym->obj_start; 1250 if (!start) 1251 start = sym->start; 1252 if (full_paths) 1253 d_filename = filename; 1254 else 1255 d_filename = basename(filename); 1256 1257 end = start + sym->end - sym->start + 1; 1258 len = sym->end - sym->start; 1259 1260 if (print_line) { 1261 get_source_line(sym, start, len, filename); 1262 print_summary(filename); 1263 } 1264 1265 printf("\n\n------------------------------------------------\n"); 1266 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 1267 printf("------------------------------------------------\n"); 1268 1269 if (verbose >= 2) 1270 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 1271 1272 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 1273 (u64)start, (u64)end, filename, filename); 1274 1275 if (verbose >= 3) 1276 printf("doing: %s\n", command); 1277 1278 file = popen(command, "r"); 1279 if (!file) 1280 return; 1281 1282 while (!feof(file)) { 1283 if (parse_line(file, sym, start, len) < 0) 1284 break; 1285 } 1286 1287 pclose(file); 1288 if (print_line) 1289 free_source_line(sym, len); 1290} 1291 1292static void find_annotations(void) 1293{ 1294 struct rb_node *nd; 1295 struct dso *dso; 1296 int count = 0; 1297 1298 list_for_each_entry(dso, &dsos, node) { 1299 1300 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) { 1301 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 1302 1303 if (sym->hist) { 1304 annotate_sym(dso, sym); 1305 count++; 1306 } 1307 } 1308 } 1309 1310 if (!count) 1311 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter); 1312} 1313 1314static int __cmd_annotate(void) 1315{ 1316 int ret, rc = EXIT_FAILURE; 1317 unsigned long offset = 0; 1318 unsigned long head = 0; 1319 struct stat stat; 1320 event_t *event; 1321 uint32_t size; 1322 char *buf; 1323 1324 register_idle_thread(); 1325 1326 input = open(input_name, O_RDONLY); 1327 if (input < 0) { 1328 perror("failed to open file"); 1329 exit(-1); 1330 } 1331 1332 ret = fstat(input, &stat); 1333 if (ret < 0) { 1334 perror("failed to stat file"); 1335 exit(-1); 1336 } 1337 1338 if (!force && (stat.st_uid != geteuid())) { 1339 fprintf(stderr, "file: %s not owned by current user\n", input_name); 1340 exit(-1); 1341 } 1342 1343 if (!stat.st_size) { 1344 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1345 exit(0); 1346 } 1347 1348 if (load_kernel() < 0) { 1349 perror("failed to load kernel symbols"); 1350 return EXIT_FAILURE; 1351 } 1352 1353remap: 1354 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 1355 MAP_SHARED, input, offset); 1356 if (buf == MAP_FAILED) { 1357 perror("failed to mmap file"); 1358 exit(-1); 1359 } 1360 1361more: 1362 event = (event_t *)(buf + head); 1363 1364 size = event->header.size; 1365 if (!size) 1366 size = 8; 1367 1368 if (head + event->header.size >= page_size * mmap_window) { 1369 unsigned long shift = page_size * (head / page_size); 1370 int ret; 1371 1372 ret = munmap(buf, page_size * mmap_window); 1373 assert(ret == 0); 1374 1375 offset += shift; 1376 head -= shift; 1377 goto remap; 1378 } 1379 1380 size = event->header.size; 1381 1382 dprintf("%p [%p]: event: %d\n", 1383 (void *)(offset + head), 1384 (void *)(long)event->header.size, 1385 event->header.type); 1386 1387 if (!size || process_event(event, offset, head) < 0) { 1388 1389 dprintf("%p [%p]: skipping unknown header type: %d\n", 1390 (void *)(offset + head), 1391 (void *)(long)(event->header.size), 1392 event->header.type); 1393 1394 total_unknown++; 1395 1396 /* 1397 * assume we lost track of the stream, check alignment, and 1398 * increment a single u64 in the hope to catch on again 'soon'. 1399 */ 1400 1401 if (unlikely(head & 7)) 1402 head &= ~7ULL; 1403 1404 size = 8; 1405 } 1406 1407 head += size; 1408 1409 if (offset + head < (unsigned long)stat.st_size) 1410 goto more; 1411 1412 rc = EXIT_SUCCESS; 1413 close(input); 1414 1415 dprintf(" IP events: %10ld\n", total); 1416 dprintf(" mmap events: %10ld\n", total_mmap); 1417 dprintf(" comm events: %10ld\n", total_comm); 1418 dprintf(" fork events: %10ld\n", total_fork); 1419 dprintf(" unknown events: %10ld\n", total_unknown); 1420 1421 if (dump_trace) 1422 return 0; 1423 1424 if (verbose >= 3) 1425 threads__fprintf(stdout); 1426 1427 if (verbose >= 2) 1428 dsos__fprintf(stdout); 1429 1430 collapse__resort(); 1431 output__resort(); 1432 1433 find_annotations(); 1434 1435 return rc; 1436} 1437 1438static const char * const annotate_usage[] = { 1439 "perf annotate [<options>] <command>", 1440 NULL 1441}; 1442 1443static const struct option options[] = { 1444 OPT_STRING('i', "input", &input_name, "file", 1445 "input file name"), 1446 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 1447 "symbol to annotate"), 1448 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 1449 OPT_BOOLEAN('v', "verbose", &verbose, 1450 "be more verbose (show symbol address, etc)"), 1451 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1452 "dump raw trace in ASCII"), 1453 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1454 OPT_BOOLEAN('m', "modules", &modules, 1455 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1456 OPT_BOOLEAN('l', "print-line", &print_line, 1457 "print matching source lines (may be slow)"), 1458 OPT_BOOLEAN('P', "full-paths", &full_paths, 1459 "Don't shorten the displayed pathnames"), 1460 OPT_END() 1461}; 1462 1463static void setup_sorting(void) 1464{ 1465 char *tmp, *tok, *str = strdup(sort_order); 1466 1467 for (tok = strtok_r(str, ", ", &tmp); 1468 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1469 if (sort_dimension__add(tok) < 0) { 1470 error("Unknown --sort key: `%s'", tok); 1471 usage_with_options(annotate_usage, options); 1472 } 1473 } 1474 1475 free(str); 1476} 1477 1478int cmd_annotate(int argc, const char **argv, const char *prefix __used) 1479{ 1480 symbol__init(); 1481 1482 page_size = getpagesize(); 1483 1484 argc = parse_options(argc, argv, options, annotate_usage, 0); 1485 1486 setup_sorting(); 1487 1488 if (argc) { 1489 /* 1490 * Special case: if there's an argument left then assume tha 1491 * it's a symbol filter: 1492 */ 1493 if (argc > 1) 1494 usage_with_options(annotate_usage, options); 1495 1496 sym_hist_filter = argv[0]; 1497 } 1498 1499 if (!sym_hist_filter) 1500 usage_with_options(annotate_usage, options); 1501 1502 setup_pager(); 1503 1504 return __cmd_annotate(); 1505}