aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c230
1 files changed, 182 insertions, 48 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 4a9fe228be2a..89b7f68a1799 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -60,7 +60,7 @@ static int system_wide = 0;
60static int default_interval = 0; 60static int default_interval = 0;
61 61
62static int count_filter = 5; 62static int count_filter = 5;
63static int print_entries = 15; 63static int print_entries;
64 64
65static int target_pid = -1; 65static int target_pid = -1;
66static int inherit = 0; 66static int inherit = 0;
@@ -76,6 +76,9 @@ static int delay_secs = 2;
76static int zero = 0; 76static int zero = 0;
77static int dump_symtab = 0; 77static int dump_symtab = 0;
78 78
79static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false;
81
79/* 82/*
80 * Source 83 * Source
81 */ 84 */
@@ -104,6 +107,7 @@ struct sym_entry {
104 unsigned long snap_count; 107 unsigned long snap_count;
105 double weight; 108 double weight;
106 int skip; 109 int skip;
110 u8 origin;
107 struct map *map; 111 struct map *map;
108 struct source_line *source; 112 struct source_line *source;
109 struct source_line *lines; 113 struct source_line *lines;
@@ -115,6 +119,36 @@ struct sym_entry {
115 * Source functions 119 * Source functions
116 */ 120 */
117 121
122/* most GUI terminals set LINES (although some don't export it) */
123static int term_rows(void)
124{
125 char *lines_string = getenv("LINES");
126 int n_lines;
127
128 if (lines_string && (n_lines = atoi(lines_string)) > 0)
129 return n_lines;
130#ifdef TIOCGWINSZ
131 else {
132 struct winsize ws;
133 if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_row)
134 return ws.ws_row;
135 }
136#endif
137 return 25;
138}
139
140static void update_print_entries(void)
141{
142 print_entries = term_rows();
143 if (print_entries > 9)
144 print_entries -= 9;
145}
146
147static void sig_winch_handler(int sig __used)
148{
149 update_print_entries();
150}
151
118static void parse_source(struct sym_entry *syme) 152static void parse_source(struct sym_entry *syme)
119{ 153{
120 struct symbol *sym; 154 struct symbol *sym;
@@ -318,7 +352,7 @@ static void show_details(struct sym_entry *syme)
318} 352}
319 353
320/* 354/*
321 * Symbols will be added here in record_ip and will get out 355 * Symbols will be added here in event__process_sample and will get out
322 * after decayed. 356 * after decayed.
323 */ 357 */
324static LIST_HEAD(active_symbols); 358static LIST_HEAD(active_symbols);
@@ -400,6 +434,13 @@ static void print_sym_table(void)
400 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 434 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
401 syme->snap_count = syme->count[snap]; 435 syme->snap_count = syme->count[snap];
402 if (syme->snap_count != 0) { 436 if (syme->snap_count != 0) {
437 if ((hide_user_symbols &&
438 syme->origin == PERF_RECORD_MISC_USER) ||
439 (hide_kernel_symbols &&
440 syme->origin == PERF_RECORD_MISC_KERNEL)) {
441 list_remove_active_sym(syme);
442 continue;
443 }
403 syme->weight = sym_weight(syme); 444 syme->weight = sym_weight(syme);
404 rb_insert_active_sym(&tmp, syme); 445 rb_insert_active_sym(&tmp, syme);
405 sum_ksamples += syme->snap_count; 446 sum_ksamples += syme->snap_count;
@@ -459,18 +500,18 @@ static void print_sym_table(void)
459 } 500 }
460 501
461 if (nr_counters == 1) 502 if (nr_counters == 1)
462 printf(" samples pcnt"); 503 printf(" samples pcnt");
463 else 504 else
464 printf(" weight samples pcnt"); 505 printf(" weight samples pcnt");
465 506
466 if (verbose) 507 if (verbose)
467 printf(" RIP "); 508 printf(" RIP ");
468 printf(" kernel function\n"); 509 printf(" function DSO\n");
469 printf(" %s _______ _____", 510 printf(" %s _______ _____",
470 nr_counters == 1 ? " " : "______"); 511 nr_counters == 1 ? " " : "______");
471 if (verbose) 512 if (verbose)
472 printf(" ________________"); 513 printf(" ________________");
473 printf(" _______________\n\n"); 514 printf(" ________________________________ ________________\n\n");
474 515
475 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 516 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
476 struct symbol *sym; 517 struct symbol *sym;
@@ -486,16 +527,15 @@ static void print_sym_table(void)
486 sum_ksamples)); 527 sum_ksamples));
487 528
488 if (nr_counters == 1 || !display_weighted) 529 if (nr_counters == 1 || !display_weighted)
489 printf("%20.2f - ", syme->weight); 530 printf("%20.2f ", syme->weight);
490 else 531 else
491 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 532 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
492 533
493 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 534 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
494 if (verbose) 535 if (verbose)
495 printf(" - %016llx", sym->start); 536 printf(" %016llx", sym->start);
496 printf(" : %s", sym->name); 537 printf(" %-32s", sym->name);
497 if (syme->map->dso->name[0] == '[') 538 printf(" %s", syme->map->dso->short_name);
498 printf(" \t%s", syme->map->dso->name);
499 printf("\n"); 539 printf("\n");
500 } 540 }
501} 541}
@@ -608,6 +648,12 @@ static void print_mapped_keys(void)
608 if (nr_counters > 1) 648 if (nr_counters > 1)
609 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 649 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
610 650
651 fprintf(stdout,
652 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
653 hide_kernel_symbols ? "yes" : "no");
654 fprintf(stdout,
655 "\t[U] hide user symbols. \t(%s)\n",
656 hide_user_symbols ? "yes" : "no");
611 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 657 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
612 fprintf(stdout, "\t[qQ] quit.\n"); 658 fprintf(stdout, "\t[qQ] quit.\n");
613} 659}
@@ -621,6 +667,8 @@ static int key_mapped(int c)
621 case 'z': 667 case 'z':
622 case 'q': 668 case 'q':
623 case 'Q': 669 case 'Q':
670 case 'K':
671 case 'U':
624 return 1; 672 return 1;
625 case 'E': 673 case 'E':
626 case 'w': 674 case 'w':
@@ -669,6 +717,11 @@ static void handle_keypress(int c)
669 break; 717 break;
670 case 'e': 718 case 'e':
671 prompt_integer(&print_entries, "Enter display entries (lines)"); 719 prompt_integer(&print_entries, "Enter display entries (lines)");
720 if (print_entries == 0) {
721 update_print_entries();
722 signal(SIGWINCH, sig_winch_handler);
723 } else
724 signal(SIGWINCH, SIG_DFL);
672 break; 725 break;
673 case 'E': 726 case 'E':
674 if (nr_counters > 1) { 727 if (nr_counters > 1) {
@@ -693,6 +746,9 @@ static void handle_keypress(int c)
693 case 'F': 746 case 'F':
694 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 747 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
695 break; 748 break;
749 case 'K':
750 hide_kernel_symbols = !hide_kernel_symbols;
751 break;
696 case 'q': 752 case 'q':
697 case 'Q': 753 case 'Q':
698 printf("exiting.\n"); 754 printf("exiting.\n");
@@ -712,6 +768,9 @@ static void handle_keypress(int c)
712 pthread_mutex_unlock(&syme->source_lock); 768 pthread_mutex_unlock(&syme->source_lock);
713 } 769 }
714 break; 770 break;
771 case 'U':
772 hide_user_symbols = !hide_user_symbols;
773 break;
715 case 'w': 774 case 'w':
716 display_weighted = ~display_weighted; 775 display_weighted = ~display_weighted;
717 break; 776 break;
@@ -790,7 +849,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
790 strstr(name, "_text_end")) 849 strstr(name, "_text_end"))
791 return 1; 850 return 1;
792 851
793 syme = dso__sym_priv(map->dso, sym); 852 syme = symbol__priv(sym);
794 syme->map = map; 853 syme->map = map;
795 pthread_mutex_init(&syme->source_lock, NULL); 854 pthread_mutex_init(&syme->source_lock, NULL);
796 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 855 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
@@ -808,8 +867,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
808 867
809static int parse_symbols(void) 868static int parse_symbols(void)
810{ 869{
811 if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), 870 if (dsos__load_kernel(vmlinux_name, symbol_filter, 1) <= 0)
812 symbol_filter, 1) <= 0)
813 return -1; 871 return -1;
814 872
815 if (dump_symtab) 873 if (dump_symtab)
@@ -818,41 +876,104 @@ static int parse_symbols(void)
818 return 0; 876 return 0;
819} 877}
820 878
821/* 879static void event__process_sample(const event_t *self, int counter)
822 * Binary search in the histogram table and record the hit:
823 */
824static void record_ip(u64 ip, int counter)
825{ 880{
881 u64 ip = self->ip.ip;
826 struct map *map; 882 struct map *map;
827 struct symbol *sym = kernel_maps__find_symbol(ip, &map); 883 struct sym_entry *syme;
828 884 struct symbol *sym;
829 if (sym != NULL) { 885 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
830 struct sym_entry *syme = dso__sym_priv(map->dso, sym); 886
831 887 switch (origin) {
832 if (!syme->skip) { 888 case PERF_RECORD_MISC_USER: {
833 syme->count[counter]++; 889 struct thread *thread;
834 record_precise_ip(syme, counter, ip); 890
835 pthread_mutex_lock(&active_symbols_lock); 891 if (hide_user_symbols)
836 if (list_empty(&syme->node) || !syme->node.next) 892 return;
837 __list_insert_active_sym(syme); 893
838 pthread_mutex_unlock(&active_symbols_lock); 894 thread = threads__findnew(self->ip.pid);
895 if (thread == NULL)
839 return; 896 return;
897
898 map = thread__find_map(thread, ip);
899 if (map != NULL) {
900 ip = map->map_ip(map, ip);
901 sym = map__find_symbol(map, ip, symbol_filter);
902 if (sym == NULL)
903 return;
904 userspace_samples++;
905 break;
840 } 906 }
841 } 907 }
908 /*
909 * If this is outside of all known maps,
910 * and is a negative address, try to look it
911 * up in the kernel dso, as it might be a
912 * vsyscall or vdso (which executes in user-mode).
913 */
914 if ((long long)ip >= 0)
915 return;
916 /* Fall thru */
917 case PERF_RECORD_MISC_KERNEL:
918 if (hide_kernel_symbols)
919 return;
920
921 sym = kernel_maps__find_symbol(ip, &map);
922 if (sym == NULL)
923 return;
924 break;
925 default:
926 return;
927 }
842 928
843 samples--; 929 syme = symbol__priv(sym);
930
931 if (!syme->skip) {
932 syme->count[counter]++;
933 syme->origin = origin;
934 record_precise_ip(syme, counter, ip);
935 pthread_mutex_lock(&active_symbols_lock);
936 if (list_empty(&syme->node) || !syme->node.next)
937 __list_insert_active_sym(syme);
938 pthread_mutex_unlock(&active_symbols_lock);
939 ++samples;
940 return;
941 }
844} 942}
845 943
846static void process_event(u64 ip, int counter, int user) 944static void event__process_mmap(event_t *self)
847{ 945{
848 samples++; 946 struct thread *thread = threads__findnew(self->mmap.pid);
849 947
850 if (user) { 948 if (thread != NULL) {
851 userspace_samples++; 949 struct map *map = map__new(&self->mmap, NULL, 0);
852 return; 950 if (map != NULL)
951 thread__insert_map(thread, map);
853 } 952 }
953}
854 954
855 record_ip(ip, counter); 955static void event__process_comm(event_t *self)
956{
957 struct thread *thread = threads__findnew(self->comm.pid);
958
959 if (thread != NULL)
960 thread__set_comm(thread, self->comm.comm);
961}
962
963static int event__process(event_t *event)
964{
965 switch (event->header.type) {
966 case PERF_RECORD_COMM:
967 event__process_comm(event);
968 break;
969 case PERF_RECORD_MMAP:
970 event__process_mmap(event);
971 break;
972 default:
973 break;
974 }
975
976 return 0;
856} 977}
857 978
858struct mmap_data { 979struct mmap_data {
@@ -925,13 +1046,11 @@ static void mmap_read_counter(struct mmap_data *md)
925 event = &event_copy; 1046 event = &event_copy;
926 } 1047 }
927 1048
1049 if (event->header.type == PERF_RECORD_SAMPLE)
1050 event__process_sample(event, md->counter);
1051 else
1052 event__process(event);
928 old += size; 1053 old += size;
929
930 if (event->header.type == PERF_RECORD_SAMPLE) {
931 int user =
932 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
933 process_event(event->ip.ip, md->counter, user);
934 }
935 } 1054 }
936 1055
937 md->prev = old; 1056 md->prev = old;
@@ -973,6 +1092,7 @@ static void start_counter(int i, int counter)
973 } 1092 }
974 1093
975 attr->inherit = (cpu < 0) && inherit; 1094 attr->inherit = (cpu < 0) && inherit;
1095 attr->mmap = 1;
976 1096
977try_again: 1097try_again:
978 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1098 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -980,7 +1100,7 @@ try_again:
980 if (fd[i][counter] < 0) { 1100 if (fd[i][counter] < 0) {
981 int err = errno; 1101 int err = errno;
982 1102
983 if (err == EPERM) 1103 if (err == EPERM || err == EACCES)
984 die("No permission - are you root?\n"); 1104 die("No permission - are you root?\n");
985 /* 1105 /*
986 * If it's cycles then fall back to hrtimer 1106 * If it's cycles then fall back to hrtimer
@@ -1031,6 +1151,11 @@ static int __cmd_top(void)
1031 int i, counter; 1151 int i, counter;
1032 int ret; 1152 int ret;
1033 1153
1154 if (target_pid != -1)
1155 event__synthesize_thread(target_pid, event__process);
1156 else
1157 event__synthesize_threads(event__process);
1158
1034 for (i = 0; i < nr_cpus; i++) { 1159 for (i = 0; i < nr_cpus; i++) {
1035 group_fd = -1; 1160 group_fd = -1;
1036 for (counter = 0; counter < nr_counters; counter++) 1161 for (counter = 0; counter < nr_counters; counter++)
@@ -1087,6 +1212,8 @@ static const struct option options[] = {
1087 OPT_INTEGER('C', "CPU", &profile_cpu, 1212 OPT_INTEGER('C', "CPU", &profile_cpu,
1088 "CPU to profile on"), 1213 "CPU to profile on"),
1089 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1214 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1215 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1216 "hide kernel symbols"),
1090 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1217 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1091 "number of mmap data pages"), 1218 "number of mmap data pages"),
1092 OPT_INTEGER('r', "realtime", &realtime_prio, 1219 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1109,6 +1236,8 @@ static const struct option options[] = {
1109 "profile at this frequency"), 1236 "profile at this frequency"),
1110 OPT_INTEGER('E', "entries", &print_entries, 1237 OPT_INTEGER('E', "entries", &print_entries,
1111 "display this many functions"), 1238 "display this many functions"),
1239 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1240 "hide user symbols"),
1112 OPT_BOOLEAN('v', "verbose", &verbose, 1241 OPT_BOOLEAN('v', "verbose", &verbose,
1113 "be more verbose (show counter open errors, etc)"), 1242 "be more verbose (show counter open errors, etc)"),
1114 OPT_END() 1243 OPT_END()
@@ -1118,7 +1247,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118{ 1247{
1119 int counter; 1248 int counter;
1120 1249
1121 symbol__init(); 1250 symbol__init(sizeof(struct sym_entry));
1122 1251
1123 page_size = sysconf(_SC_PAGE_SIZE); 1252 page_size = sysconf(_SC_PAGE_SIZE);
1124 1253
@@ -1172,5 +1301,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1172 if (target_pid != -1 || profile_cpu != -1) 1301 if (target_pid != -1 || profile_cpu != -1)
1173 nr_cpus = 1; 1302 nr_cpus = 1;
1174 1303
1304 if (print_entries == 0) {
1305 update_print_entries();
1306 signal(SIGWINCH, sig_winch_handler);
1307 }
1308
1175 return __cmd_top(); 1309 return __cmd_top();
1176} 1310}