aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-10-26 17:23:19 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-27 08:51:54 -0400
commit5b2bb75a0d4b08cd16bc35ecd674f957fc3b0eb7 (patch)
tree78b89706226435397f5c8539bd162b81c49db2a6 /tools/perf/builtin-top.c
parent234fbbf508c58c5084292b11b242377553897459 (diff)
perf top: Support userspace symbols too
Example: Compiling the kernel with 'make -k 22 allyesconfig' [root@emilia linux-2.6-tip]# perf top -r 90 ------------------------------------------------------------------------------ PerfTop: 3669 irqs/sec kernel:59.9% [1000Hz cycles], (all, 8 CPUs) ------------------------------------------------------------------------------ samples pcnt function DSO _______ _____ ________________________________ ________________ 3062.00 6.5% clear_page_c [kernel] 2233.00 4.8% _int_malloc /lib64/libc-2.5.so 2100.00 4.5% yylex /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 2029.00 4.3% memset /lib64/libc-2.5.so 1224.00 2.6% page_fault [kernel] 1075.00 2.3% __GI_strlen /lib64/libc-2.5.so 863.00 1.8% sub_preempt_count [kernel] 822.00 1.8% __GI_memcpy /lib64/libc-2.5.so 810.00 1.7% __GI_vfprintf /lib64/libc-2.5.so 786.00 1.7% _int_free /lib64/libc-2.5.so 775.00 1.7% __GI_strcmp /lib64/libc-2.5.so 748.00 1.6% _spin_lock [kernel] 699.00 1.5% main /home/acme/git/build/allyesconfig/scripts/basic/fixdep 659.00 1.4% add_preempt_count [kernel] 649.00 1.4% yyparse /home/acme/git/build/allyesconfig/scripts/genksyms/genksyms 645.00 1.4% preempt_trace [kernel] 635.00 1.4% __GI___libc_free /lib64/libc-2.5.so 597.00 1.3% trace_preempt_on [kernel] 551.00 1.2% __GI___libc_malloc /lib64/libc-2.5.so 516.00 1.1% _spin_lock_irqsave [kernel] 481.00 1.0% copy_user_generic_string [kernel] 479.00 1.0% unmap_vmas [kernel] 429.00 0.9% _IO_file_xsputn_internal /lib64/libc-2.5.so 425.00 0.9% __GI_strncpy /lib64/libc-2.5.so 416.00 0.9% get_page_from_freelist [kernel] 414.00 0.9% malloc_consolidate /lib64/libc-2.5.so 406.00 0.9% get_parent_ip [kernel] 362.00 0.8% __rmqueue [kernel] 347.00 0.7% in_lock_functions [kernel] 316.00 0.7% __d_lookup [kernel] [root@emilia linux-2.6-tip]# More polishing is needed to print just DSO basename when not --verbose, etc. Supporting a 'comm' column requires some more reworking of 'perf top' internals as we will need to use something like the hist entries 'perf report' uses and will be done in another patch. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1256592199-9608-3-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c143
1 files changed, 101 insertions, 42 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 4a9fe228be2a..a02fc4146017 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -318,7 +318,7 @@ static void show_details(struct sym_entry *syme)
318} 318}
319 319
320/* 320/*
321 * Symbols will be added here in record_ip and will get out 321 * Symbols will be added here in event__process_sample and will get out
322 * after decayed. 322 * after decayed.
323 */ 323 */
324static LIST_HEAD(active_symbols); 324static LIST_HEAD(active_symbols);
@@ -459,18 +459,18 @@ static void print_sym_table(void)
459 } 459 }
460 460
461 if (nr_counters == 1) 461 if (nr_counters == 1)
462 printf(" samples pcnt"); 462 printf(" samples pcnt");
463 else 463 else
464 printf(" weight samples pcnt"); 464 printf(" weight samples pcnt");
465 465
466 if (verbose) 466 if (verbose)
467 printf(" RIP "); 467 printf(" RIP ");
468 printf(" kernel function\n"); 468 printf(" function DSO\n");
469 printf(" %s _______ _____", 469 printf(" %s _______ _____",
470 nr_counters == 1 ? " " : "______"); 470 nr_counters == 1 ? " " : "______");
471 if (verbose) 471 if (verbose)
472 printf(" ________________"); 472 printf(" ________________");
473 printf(" _______________\n\n"); 473 printf(" ________________________________ ________________\n\n");
474 474
475 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 475 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
476 struct symbol *sym; 476 struct symbol *sym;
@@ -486,16 +486,15 @@ static void print_sym_table(void)
486 sum_ksamples)); 486 sum_ksamples));
487 487
488 if (nr_counters == 1 || !display_weighted) 488 if (nr_counters == 1 || !display_weighted)
489 printf("%20.2f - ", syme->weight); 489 printf("%20.2f ", syme->weight);
490 else 490 else
491 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 491 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
492 492
493 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 493 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
494 if (verbose) 494 if (verbose)
495 printf(" - %016llx", sym->start); 495 printf(" %016llx", sym->start);
496 printf(" : %s", sym->name); 496 printf(" %-32s", sym->name);
497 if (syme->map->dso->name[0] == '[') 497 printf(" %s", syme->map->dso->short_name);
498 printf(" \t%s", syme->map->dso->name);
499 printf("\n"); 498 printf("\n");
500 } 499 }
501} 500}
@@ -818,41 +817,97 @@ static int parse_symbols(void)
818 return 0; 817 return 0;
819} 818}
820 819
821/* 820static 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{ 821{
822 u64 ip = self->ip.ip;
826 struct map *map; 823 struct map *map;
827 struct symbol *sym = kernel_maps__find_symbol(ip, &map); 824 struct sym_entry *syme;
828 825 struct symbol *sym;
829 if (sym != NULL) { 826
830 struct sym_entry *syme = dso__sym_priv(map->dso, sym); 827 switch (self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) {
831 828 case PERF_RECORD_MISC_USER: {
832 if (!syme->skip) { 829 struct thread *thread = threads__findnew(self->ip.pid);
833 syme->count[counter]++; 830
834 record_precise_ip(syme, counter, ip); 831 if (thread == NULL)
835 pthread_mutex_lock(&active_symbols_lock);
836 if (list_empty(&syme->node) || !syme->node.next)
837 __list_insert_active_sym(syme);
838 pthread_mutex_unlock(&active_symbols_lock);
839 return; 832 return;
833
834 map = thread__find_map(thread, ip);
835 if (map != NULL) {
836 ip = map->map_ip(map, ip);
837 sym = map->dso->find_symbol(map->dso, ip);
838 if (sym == NULL)
839 return;
840 userspace_samples++;
841 break;
840 } 842 }
841 } 843 }
844 /*
845 * If this is outside of all known maps,
846 * and is a negative address, try to look it
847 * up in the kernel dso, as it might be a
848 * vsyscall or vdso (which executes in user-mode).
849 */
850 if ((long long)ip >= 0)
851 return;
852 /* Fall thru */
853 case PERF_RECORD_MISC_KERNEL:
854 sym = kernel_maps__find_symbol(ip, &map);
855 if (sym == NULL)
856 return;
857 break;
858 default:
859 return;
860 }
861
862 syme = dso__sym_priv(map->dso, sym);
842 863
843 samples--; 864 if (!syme->skip) {
865 syme->count[counter]++;
866 record_precise_ip(syme, counter, ip);
867 pthread_mutex_lock(&active_symbols_lock);
868 if (list_empty(&syme->node) || !syme->node.next)
869 __list_insert_active_sym(syme);
870 pthread_mutex_unlock(&active_symbols_lock);
871 ++samples;
872 return;
873 }
844} 874}
845 875
846static void process_event(u64 ip, int counter, int user) 876static void event__process_mmap(event_t *self)
847{ 877{
848 samples++; 878 struct thread *thread = threads__findnew(self->mmap.pid);
879
880 if (thread != NULL) {
881 struct map *map = map__new(&self->mmap, NULL, 0,
882 sizeof(struct sym_entry),
883 symbol_filter);
884 if (map != NULL)
885 thread__insert_map(thread, map);
886 }
887}
849 888
850 if (user) { 889static void event__process_comm(event_t *self)
851 userspace_samples++; 890{
852 return; 891 struct thread *thread = threads__findnew(self->comm.pid);
892
893 if (thread != NULL)
894 thread__set_comm(thread, self->comm.comm);
895}
896
897static int event__process(event_t *event)
898{
899 switch (event->header.type) {
900 case PERF_RECORD_COMM:
901 event__process_comm(event);
902 break;
903 case PERF_RECORD_MMAP:
904 event__process_mmap(event);
905 break;
906 default:
907 break;
853 } 908 }
854 909
855 record_ip(ip, counter); 910 return 0;
856} 911}
857 912
858struct mmap_data { 913struct mmap_data {
@@ -925,13 +980,11 @@ static void mmap_read_counter(struct mmap_data *md)
925 event = &event_copy; 980 event = &event_copy;
926 } 981 }
927 982
983 if (event->header.type == PERF_RECORD_SAMPLE)
984 event__process_sample(event, md->counter);
985 else
986 event__process(event);
928 old += size; 987 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 } 988 }
936 989
937 md->prev = old; 990 md->prev = old;
@@ -973,6 +1026,7 @@ static void start_counter(int i, int counter)
973 } 1026 }
974 1027
975 attr->inherit = (cpu < 0) && inherit; 1028 attr->inherit = (cpu < 0) && inherit;
1029 attr->mmap = 1;
976 1030
977try_again: 1031try_again:
978 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1032 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1031,6 +1085,11 @@ static int __cmd_top(void)
1031 int i, counter; 1085 int i, counter;
1032 int ret; 1086 int ret;
1033 1087
1088 if (target_pid != -1)
1089 event__synthesize_thread(target_pid, event__process);
1090 else
1091 event__synthesize_threads(event__process);
1092
1034 for (i = 0; i < nr_cpus; i++) { 1093 for (i = 0; i < nr_cpus; i++) {
1035 group_fd = -1; 1094 group_fd = -1;
1036 for (counter = 0; counter < nr_counters; counter++) 1095 for (counter = 0; counter < nr_counters; counter++)