diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 155 |
1 files changed, 64 insertions, 91 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 37512e936235..c0f69e80b2cc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include "util/symbol.h" | 23 | #include "util/symbol.h" |
24 | #include "util/color.h" | 24 | #include "util/color.h" |
25 | #include "util/thread.h" | ||
25 | #include "util/util.h" | 26 | #include "util/util.h" |
26 | #include <linux/rbtree.h> | 27 | #include <linux/rbtree.h> |
27 | #include "util/parse-options.h" | 28 | #include "util/parse-options.h" |
@@ -54,26 +55,26 @@ | |||
54 | 55 | ||
55 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 56 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
56 | 57 | ||
57 | static int system_wide = 0; | 58 | static int system_wide = 0; |
58 | 59 | ||
59 | static int default_interval = 100000; | 60 | static int default_interval = 0; |
60 | 61 | ||
61 | static int count_filter = 5; | 62 | static int count_filter = 5; |
62 | static int print_entries = 15; | 63 | static int print_entries = 15; |
63 | 64 | ||
64 | static int target_pid = -1; | 65 | static int target_pid = -1; |
65 | static int inherit = 0; | 66 | static int inherit = 0; |
66 | static int profile_cpu = -1; | 67 | static int profile_cpu = -1; |
67 | static int nr_cpus = 0; | 68 | static int nr_cpus = 0; |
68 | static unsigned int realtime_prio = 0; | 69 | static unsigned int realtime_prio = 0; |
69 | static int group = 0; | 70 | static int group = 0; |
70 | static unsigned int page_size; | 71 | static unsigned int page_size; |
71 | static unsigned int mmap_pages = 16; | 72 | static unsigned int mmap_pages = 16; |
72 | static int freq = 0; | 73 | static int freq = 1000; /* 1 KHz */ |
73 | 74 | ||
74 | static int delay_secs = 2; | 75 | static int delay_secs = 2; |
75 | static int zero; | 76 | static int zero = 0; |
76 | static int dump_symtab; | 77 | static int dump_symtab = 0; |
77 | 78 | ||
78 | /* | 79 | /* |
79 | * Source | 80 | * Source |
@@ -86,19 +87,16 @@ struct source_line { | |||
86 | struct source_line *next; | 87 | struct source_line *next; |
87 | }; | 88 | }; |
88 | 89 | ||
89 | static char *sym_filter = NULL; | 90 | static char *sym_filter = NULL; |
90 | struct sym_entry *sym_filter_entry = NULL; | 91 | struct sym_entry *sym_filter_entry = NULL; |
91 | static int sym_pcnt_filter = 5; | 92 | static int sym_pcnt_filter = 5; |
92 | static int sym_counter = 0; | 93 | static int sym_counter = 0; |
93 | static int display_weighted = -1; | 94 | static int display_weighted = -1; |
94 | 95 | ||
95 | /* | 96 | /* |
96 | * Symbols | 97 | * Symbols |
97 | */ | 98 | */ |
98 | 99 | ||
99 | static u64 min_ip; | ||
100 | static u64 max_ip = -1ll; | ||
101 | |||
102 | struct sym_entry { | 100 | struct sym_entry { |
103 | struct rb_node rb_node; | 101 | struct rb_node rb_node; |
104 | struct list_head node; | 102 | struct list_head node; |
@@ -106,6 +104,7 @@ struct sym_entry { | |||
106 | unsigned long snap_count; | 104 | unsigned long snap_count; |
107 | double weight; | 105 | double weight; |
108 | int skip; | 106 | int skip; |
107 | struct map *map; | ||
109 | struct source_line *source; | 108 | struct source_line *source; |
110 | struct source_line *lines; | 109 | struct source_line *lines; |
111 | struct source_line **lines_tail; | 110 | struct source_line **lines_tail; |
@@ -119,12 +118,11 @@ struct sym_entry { | |||
119 | static void parse_source(struct sym_entry *syme) | 118 | static void parse_source(struct sym_entry *syme) |
120 | { | 119 | { |
121 | struct symbol *sym; | 120 | struct symbol *sym; |
122 | struct module *module; | 121 | struct map *map; |
123 | struct section *section = NULL; | ||
124 | FILE *file; | 122 | FILE *file; |
125 | char command[PATH_MAX*2]; | 123 | char command[PATH_MAX*2]; |
126 | const char *path = vmlinux_name; | 124 | const char *path; |
127 | u64 start, end, len; | 125 | u64 len; |
128 | 126 | ||
129 | if (!syme) | 127 | if (!syme) |
130 | return; | 128 | return; |
@@ -135,27 +133,15 @@ static void parse_source(struct sym_entry *syme) | |||
135 | } | 133 | } |
136 | 134 | ||
137 | sym = (struct symbol *)(syme + 1); | 135 | sym = (struct symbol *)(syme + 1); |
138 | module = sym->module; | 136 | map = syme->map; |
139 | 137 | path = map->dso->long_name; | |
140 | if (module) | ||
141 | path = module->path; | ||
142 | if (!path) | ||
143 | return; | ||
144 | |||
145 | start = sym->obj_start; | ||
146 | if (!start) | ||
147 | start = sym->start; | ||
148 | 138 | ||
149 | if (module) { | ||
150 | section = module->sections->find_section(module->sections, ".text"); | ||
151 | if (section) | ||
152 | start -= section->vma; | ||
153 | } | ||
154 | |||
155 | end = start + sym->end - sym->start + 1; | ||
156 | len = sym->end - sym->start; | 139 | len = sym->end - sym->start; |
157 | 140 | ||
158 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); | 141 | sprintf(command, |
142 | "objdump --start-address=0x%016Lx " | ||
143 | "--stop-address=0x%016Lx -dS %s", | ||
144 | sym->start, sym->end, path); | ||
159 | 145 | ||
160 | file = popen(command, "r"); | 146 | file = popen(command, "r"); |
161 | if (!file) | 147 | if (!file) |
@@ -187,13 +173,11 @@ static void parse_source(struct sym_entry *syme) | |||
187 | 173 | ||
188 | if (strlen(src->line)>8 && src->line[8] == ':') { | 174 | if (strlen(src->line)>8 && src->line[8] == ':') { |
189 | src->eip = strtoull(src->line, NULL, 16); | 175 | src->eip = strtoull(src->line, NULL, 16); |
190 | if (section) | 176 | src->eip += map->start; |
191 | src->eip += section->vma; | ||
192 | } | 177 | } |
193 | if (strlen(src->line)>8 && src->line[16] == ':') { | 178 | if (strlen(src->line)>8 && src->line[16] == ':') { |
194 | src->eip = strtoull(src->line, NULL, 16); | 179 | src->eip = strtoull(src->line, NULL, 16); |
195 | if (section) | 180 | src->eip += map->start; |
196 | src->eip += section->vma; | ||
197 | } | 181 | } |
198 | } | 182 | } |
199 | pclose(file); | 183 | pclose(file); |
@@ -245,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme) | |||
245 | struct symbol *symbol = (struct symbol *)(syme + 1); | 229 | struct symbol *symbol = (struct symbol *)(syme + 1); |
246 | struct source_line *line; | 230 | struct source_line *line; |
247 | char pattern[PATH_MAX]; | 231 | char pattern[PATH_MAX]; |
248 | char *idx; | ||
249 | 232 | ||
250 | sprintf(pattern, "<%s>:", symbol->name); | 233 | sprintf(pattern, "<%s>:", symbol->name); |
251 | 234 | ||
252 | if (symbol->module) { | ||
253 | idx = strstr(pattern, "\t"); | ||
254 | if (idx) | ||
255 | *idx = 0; | ||
256 | } | ||
257 | |||
258 | pthread_mutex_lock(&syme->source_lock); | 235 | pthread_mutex_lock(&syme->source_lock); |
259 | for (line = syme->lines; line; line = line->next) { | 236 | for (line = syme->lines; line; line = line->next) { |
260 | if (strstr(line->line, pattern)) { | 237 | if (strstr(line->line, pattern)) { |
@@ -516,8 +493,8 @@ static void print_sym_table(void) | |||
516 | if (verbose) | 493 | if (verbose) |
517 | printf(" - %016llx", sym->start); | 494 | printf(" - %016llx", sym->start); |
518 | printf(" : %s", sym->name); | 495 | printf(" : %s", sym->name); |
519 | if (sym->module) | 496 | if (syme->map->dso->name[0] == '[') |
520 | printf("\t[%s]", sym->module->name); | 497 | printf(" \t%s", syme->map->dso->name); |
521 | printf("\n"); | 498 | printf("\n"); |
522 | } | 499 | } |
523 | } | 500 | } |
@@ -788,7 +765,7 @@ static const char *skip_symbols[] = { | |||
788 | NULL | 765 | NULL |
789 | }; | 766 | }; |
790 | 767 | ||
791 | static int symbol_filter(struct dso *self, struct symbol *sym) | 768 | static int symbol_filter(struct map *map, struct symbol *sym) |
792 | { | 769 | { |
793 | struct sym_entry *syme; | 770 | struct sym_entry *syme; |
794 | const char *name = sym->name; | 771 | const char *name = sym->name; |
@@ -810,7 +787,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym) | |||
810 | strstr(name, "_text_end")) | 787 | strstr(name, "_text_end")) |
811 | return 1; | 788 | return 1; |
812 | 789 | ||
813 | syme = dso__sym_priv(self, sym); | 790 | syme = dso__sym_priv(map->dso, sym); |
791 | syme->map = map; | ||
814 | pthread_mutex_init(&syme->source_lock, NULL); | 792 | pthread_mutex_init(&syme->source_lock, NULL); |
815 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) | 793 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) |
816 | sym_filter_entry = syme; | 794 | sym_filter_entry = syme; |
@@ -827,34 +805,14 @@ static int symbol_filter(struct dso *self, struct symbol *sym) | |||
827 | 805 | ||
828 | static int parse_symbols(void) | 806 | static int parse_symbols(void) |
829 | { | 807 | { |
830 | struct rb_node *node; | 808 | if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), |
831 | struct symbol *sym; | 809 | symbol_filter, verbose, 1) <= 0) |
832 | int use_modules = vmlinux_name ? 1 : 0; | ||
833 | |||
834 | kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); | ||
835 | if (kernel_dso == NULL) | ||
836 | return -1; | 810 | return -1; |
837 | 811 | ||
838 | if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0) | ||
839 | goto out_delete_dso; | ||
840 | |||
841 | node = rb_first(&kernel_dso->syms); | ||
842 | sym = rb_entry(node, struct symbol, rb_node); | ||
843 | min_ip = sym->start; | ||
844 | |||
845 | node = rb_last(&kernel_dso->syms); | ||
846 | sym = rb_entry(node, struct symbol, rb_node); | ||
847 | max_ip = sym->end; | ||
848 | |||
849 | if (dump_symtab) | 812 | if (dump_symtab) |
850 | dso__fprintf(kernel_dso, stderr); | 813 | dsos__fprintf(stderr); |
851 | 814 | ||
852 | return 0; | 815 | return 0; |
853 | |||
854 | out_delete_dso: | ||
855 | dso__delete(kernel_dso); | ||
856 | kernel_dso = NULL; | ||
857 | return -1; | ||
858 | } | 816 | } |
859 | 817 | ||
860 | /* | 818 | /* |
@@ -862,10 +820,11 @@ out_delete_dso: | |||
862 | */ | 820 | */ |
863 | static void record_ip(u64 ip, int counter) | 821 | static void record_ip(u64 ip, int counter) |
864 | { | 822 | { |
865 | struct symbol *sym = dso__find_symbol(kernel_dso, ip); | 823 | struct map *map; |
824 | struct symbol *sym = kernel_maps__find_symbol(ip, &map); | ||
866 | 825 | ||
867 | if (sym != NULL) { | 826 | if (sym != NULL) { |
868 | struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); | 827 | struct sym_entry *syme = dso__sym_priv(map->dso, sym); |
869 | 828 | ||
870 | if (!syme->skip) { | 829 | if (!syme->skip) { |
871 | syme->count[counter]++; | 830 | syme->count[counter]++; |
@@ -1016,7 +975,13 @@ static void start_counter(int i, int counter) | |||
1016 | attr = attrs + counter; | 975 | attr = attrs + counter; |
1017 | 976 | ||
1018 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 977 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
1019 | attr->freq = freq; | 978 | |
979 | if (freq) { | ||
980 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
981 | attr->freq = 1; | ||
982 | attr->sample_freq = freq; | ||
983 | } | ||
984 | |||
1020 | attr->inherit = (cpu < 0) && inherit; | 985 | attr->inherit = (cpu < 0) && inherit; |
1021 | 986 | ||
1022 | try_again: | 987 | try_again: |
@@ -1171,11 +1136,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1171 | if (argc) | 1136 | if (argc) |
1172 | usage_with_options(top_usage, options); | 1137 | usage_with_options(top_usage, options); |
1173 | 1138 | ||
1174 | if (freq) { | ||
1175 | default_interval = freq; | ||
1176 | freq = 1; | ||
1177 | } | ||
1178 | |||
1179 | /* CPU and PID are mutually exclusive */ | 1139 | /* CPU and PID are mutually exclusive */ |
1180 | if (target_pid != -1 && profile_cpu != -1) { | 1140 | if (target_pid != -1 && profile_cpu != -1) { |
1181 | printf("WARNING: PID switch overriding CPU\n"); | 1141 | printf("WARNING: PID switch overriding CPU\n"); |
@@ -1192,6 +1152,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1192 | parse_symbols(); | 1152 | parse_symbols(); |
1193 | parse_source(sym_filter_entry); | 1153 | parse_source(sym_filter_entry); |
1194 | 1154 | ||
1155 | |||
1156 | /* | ||
1157 | * User specified count overrides default frequency. | ||
1158 | */ | ||
1159 | if (default_interval) | ||
1160 | freq = 0; | ||
1161 | else if (freq) { | ||
1162 | default_interval = freq; | ||
1163 | } else { | ||
1164 | fprintf(stderr, "frequency and count are zero, aborting\n"); | ||
1165 | exit(EXIT_FAILURE); | ||
1166 | } | ||
1167 | |||
1195 | /* | 1168 | /* |
1196 | * Fill in the ones not specifically initialized via -c: | 1169 | * Fill in the ones not specifically initialized via -c: |
1197 | */ | 1170 | */ |