diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 221 |
1 files changed, 121 insertions, 100 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ae15f046c405..1e67ab9c7ebc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "perf.h" | 21 | #include "perf.h" |
22 | 22 | ||
23 | #include "util/color.h" | 23 | #include "util/color.h" |
24 | #include "util/evsel.h" | ||
24 | #include "util/session.h" | 25 | #include "util/session.h" |
25 | #include "util/symbol.h" | 26 | #include "util/symbol.h" |
26 | #include "util/thread.h" | 27 | #include "util/thread.h" |
@@ -29,6 +30,7 @@ | |||
29 | #include "util/parse-options.h" | 30 | #include "util/parse-options.h" |
30 | #include "util/parse-events.h" | 31 | #include "util/parse-events.h" |
31 | #include "util/cpumap.h" | 32 | #include "util/cpumap.h" |
33 | #include "util/xyarray.h" | ||
32 | 34 | ||
33 | #include "util/debug.h" | 35 | #include "util/debug.h" |
34 | 36 | ||
@@ -55,7 +57,7 @@ | |||
55 | #include <linux/unistd.h> | 57 | #include <linux/unistd.h> |
56 | #include <linux/types.h> | 58 | #include <linux/types.h> |
57 | 59 | ||
58 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | 60 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
59 | 61 | ||
60 | static bool system_wide = false; | 62 | static bool system_wide = false; |
61 | 63 | ||
@@ -66,10 +68,9 @@ static int print_entries; | |||
66 | 68 | ||
67 | static int target_pid = -1; | 69 | static int target_pid = -1; |
68 | static int target_tid = -1; | 70 | static int target_tid = -1; |
69 | static pid_t *all_tids = NULL; | 71 | static struct thread_map *threads; |
70 | static int thread_num = 0; | ||
71 | static bool inherit = false; | 72 | static bool inherit = false; |
72 | static int nr_cpus = 0; | 73 | static struct cpu_map *cpus; |
73 | static int realtime_prio = 0; | 74 | static int realtime_prio = 0; |
74 | static bool group = false; | 75 | static bool group = false; |
75 | static unsigned int page_size; | 76 | static unsigned int page_size; |
@@ -100,6 +101,7 @@ struct sym_entry *sym_filter_entry = NULL; | |||
100 | struct sym_entry *sym_filter_entry_sched = NULL; | 101 | struct sym_entry *sym_filter_entry_sched = NULL; |
101 | static int sym_pcnt_filter = 5; | 102 | static int sym_pcnt_filter = 5; |
102 | static int sym_counter = 0; | 103 | static int sym_counter = 0; |
104 | static struct perf_evsel *sym_evsel = NULL; | ||
103 | static int display_weighted = -1; | 105 | static int display_weighted = -1; |
104 | static const char *cpu_list; | 106 | static const char *cpu_list; |
105 | 107 | ||
@@ -353,7 +355,7 @@ static void show_details(struct sym_entry *syme) | |||
353 | return; | 355 | return; |
354 | 356 | ||
355 | symbol = sym_entry__symbol(syme); | 357 | symbol = sym_entry__symbol(syme); |
356 | printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); | 358 | printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); |
357 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | 359 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); |
358 | 360 | ||
359 | pthread_mutex_lock(&syme->src->lock); | 361 | pthread_mutex_lock(&syme->src->lock); |
@@ -460,7 +462,8 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | |||
460 | static void print_sym_table(void) | 462 | static void print_sym_table(void) |
461 | { | 463 | { |
462 | int printed = 0, j; | 464 | int printed = 0, j; |
463 | int counter, snap = !display_weighted ? sym_counter : 0; | 465 | struct perf_evsel *counter; |
466 | int snap = !display_weighted ? sym_counter : 0; | ||
464 | float samples_per_sec = samples/delay_secs; | 467 | float samples_per_sec = samples/delay_secs; |
465 | float ksamples_per_sec = kernel_samples/delay_secs; | 468 | float ksamples_per_sec = kernel_samples/delay_secs; |
466 | float us_samples_per_sec = (us_samples)/delay_secs; | 469 | float us_samples_per_sec = (us_samples)/delay_secs; |
@@ -532,7 +535,9 @@ static void print_sym_table(void) | |||
532 | } | 535 | } |
533 | 536 | ||
534 | if (nr_counters == 1 || !display_weighted) { | 537 | if (nr_counters == 1 || !display_weighted) { |
535 | printf("%Ld", (u64)attrs[0].sample_period); | 538 | struct perf_evsel *first; |
539 | first = list_entry(evsel_list.next, struct perf_evsel, node); | ||
540 | printf("%Ld", first->attr.sample_period); | ||
536 | if (freq) | 541 | if (freq) |
537 | printf("Hz "); | 542 | printf("Hz "); |
538 | else | 543 | else |
@@ -540,9 +545,9 @@ static void print_sym_table(void) | |||
540 | } | 545 | } |
541 | 546 | ||
542 | if (!display_weighted) | 547 | if (!display_weighted) |
543 | printf("%s", event_name(sym_counter)); | 548 | printf("%s", event_name(sym_evsel)); |
544 | else for (counter = 0; counter < nr_counters; counter++) { | 549 | else list_for_each_entry(counter, &evsel_list, node) { |
545 | if (counter) | 550 | if (counter->idx) |
546 | printf("/"); | 551 | printf("/"); |
547 | 552 | ||
548 | printf("%s", event_name(counter)); | 553 | printf("%s", event_name(counter)); |
@@ -558,12 +563,12 @@ static void print_sym_table(void) | |||
558 | printf(" (all"); | 563 | printf(" (all"); |
559 | 564 | ||
560 | if (cpu_list) | 565 | if (cpu_list) |
561 | printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list); | 566 | printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list); |
562 | else { | 567 | else { |
563 | if (target_tid != -1) | 568 | if (target_tid != -1) |
564 | printf(")\n"); | 569 | printf(")\n"); |
565 | else | 570 | else |
566 | printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : ""); | 571 | printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : ""); |
567 | } | 572 | } |
568 | 573 | ||
569 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 574 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
@@ -739,7 +744,7 @@ static void print_mapped_keys(void) | |||
739 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); | 744 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); |
740 | 745 | ||
741 | if (nr_counters > 1) | 746 | if (nr_counters > 1) |
742 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); | 747 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); |
743 | 748 | ||
744 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); | 749 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); |
745 | 750 | ||
@@ -826,19 +831,23 @@ static void handle_keypress(struct perf_session *session, int c) | |||
826 | break; | 831 | break; |
827 | case 'E': | 832 | case 'E': |
828 | if (nr_counters > 1) { | 833 | if (nr_counters > 1) { |
829 | int i; | ||
830 | |||
831 | fprintf(stderr, "\nAvailable events:"); | 834 | fprintf(stderr, "\nAvailable events:"); |
832 | for (i = 0; i < nr_counters; i++) | 835 | |
833 | fprintf(stderr, "\n\t%d %s", i, event_name(i)); | 836 | list_for_each_entry(sym_evsel, &evsel_list, node) |
837 | fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); | ||
834 | 838 | ||
835 | prompt_integer(&sym_counter, "Enter details event counter"); | 839 | prompt_integer(&sym_counter, "Enter details event counter"); |
836 | 840 | ||
837 | if (sym_counter >= nr_counters) { | 841 | if (sym_counter >= nr_counters) { |
838 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); | 842 | sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); |
839 | sym_counter = 0; | 843 | sym_counter = 0; |
844 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); | ||
840 | sleep(1); | 845 | sleep(1); |
846 | break; | ||
841 | } | 847 | } |
848 | list_for_each_entry(sym_evsel, &evsel_list, node) | ||
849 | if (sym_evsel->idx == sym_counter) | ||
850 | break; | ||
842 | } else sym_counter = 0; | 851 | } else sym_counter = 0; |
843 | break; | 852 | break; |
844 | case 'f': | 853 | case 'f': |
@@ -978,7 +987,8 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
978 | 987 | ||
979 | static void event__process_sample(const event_t *self, | 988 | static void event__process_sample(const event_t *self, |
980 | struct sample_data *sample, | 989 | struct sample_data *sample, |
981 | struct perf_session *session, int counter) | 990 | struct perf_session *session, |
991 | struct perf_evsel *evsel) | ||
982 | { | 992 | { |
983 | u64 ip = self->ip.ip; | 993 | u64 ip = self->ip.ip; |
984 | struct sym_entry *syme; | 994 | struct sym_entry *syme; |
@@ -1071,9 +1081,9 @@ static void event__process_sample(const event_t *self, | |||
1071 | 1081 | ||
1072 | syme = symbol__priv(al.sym); | 1082 | syme = symbol__priv(al.sym); |
1073 | if (!syme->skip) { | 1083 | if (!syme->skip) { |
1074 | syme->count[counter]++; | 1084 | syme->count[evsel->idx]++; |
1075 | syme->origin = origin; | 1085 | syme->origin = origin; |
1076 | record_precise_ip(syme, counter, ip); | 1086 | record_precise_ip(syme, evsel->idx, ip); |
1077 | pthread_mutex_lock(&active_symbols_lock); | 1087 | pthread_mutex_lock(&active_symbols_lock); |
1078 | if (list_empty(&syme->node) || !syme->node.next) | 1088 | if (list_empty(&syme->node) || !syme->node.next) |
1079 | __list_insert_active_sym(syme); | 1089 | __list_insert_active_sym(syme); |
@@ -1082,12 +1092,24 @@ static void event__process_sample(const event_t *self, | |||
1082 | } | 1092 | } |
1083 | 1093 | ||
1084 | struct mmap_data { | 1094 | struct mmap_data { |
1085 | int counter; | ||
1086 | void *base; | 1095 | void *base; |
1087 | int mask; | 1096 | int mask; |
1088 | unsigned int prev; | 1097 | unsigned int prev; |
1089 | }; | 1098 | }; |
1090 | 1099 | ||
1100 | static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, | ||
1101 | int ncpus, int nthreads) | ||
1102 | { | ||
1103 | evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); | ||
1104 | return evsel->priv != NULL ? 0 : -ENOMEM; | ||
1105 | } | ||
1106 | |||
1107 | static void perf_evsel__free_mmap(struct perf_evsel *evsel) | ||
1108 | { | ||
1109 | xyarray__delete(evsel->priv); | ||
1110 | evsel->priv = NULL; | ||
1111 | } | ||
1112 | |||
1091 | static unsigned int mmap_read_head(struct mmap_data *md) | 1113 | static unsigned int mmap_read_head(struct mmap_data *md) |
1092 | { | 1114 | { |
1093 | struct perf_event_mmap_page *pc = md->base; | 1115 | struct perf_event_mmap_page *pc = md->base; |
@@ -1100,8 +1122,11 @@ static unsigned int mmap_read_head(struct mmap_data *md) | |||
1100 | } | 1122 | } |
1101 | 1123 | ||
1102 | static void perf_session__mmap_read_counter(struct perf_session *self, | 1124 | static void perf_session__mmap_read_counter(struct perf_session *self, |
1103 | struct mmap_data *md) | 1125 | struct perf_evsel *evsel, |
1126 | int cpu, int thread_idx) | ||
1104 | { | 1127 | { |
1128 | struct xyarray *mmap_array = evsel->priv; | ||
1129 | struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); | ||
1105 | unsigned int head = mmap_read_head(md); | 1130 | unsigned int head = mmap_read_head(md); |
1106 | unsigned int old = md->prev; | 1131 | unsigned int old = md->prev; |
1107 | unsigned char *data = md->base + page_size; | 1132 | unsigned char *data = md->base + page_size; |
@@ -1155,7 +1180,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1155 | 1180 | ||
1156 | event__parse_sample(event, self, &sample); | 1181 | event__parse_sample(event, self, &sample); |
1157 | if (event->header.type == PERF_RECORD_SAMPLE) | 1182 | if (event->header.type == PERF_RECORD_SAMPLE) |
1158 | event__process_sample(event, &sample, self, md->counter); | 1183 | event__process_sample(event, &sample, self, evsel); |
1159 | else | 1184 | else |
1160 | event__process(event, &sample, self); | 1185 | event__process(event, &sample, self); |
1161 | old += size; | 1186 | old += size; |
@@ -1165,36 +1190,39 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1165 | } | 1190 | } |
1166 | 1191 | ||
1167 | static struct pollfd *event_array; | 1192 | static struct pollfd *event_array; |
1168 | static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | ||
1169 | 1193 | ||
1170 | static void perf_session__mmap_read(struct perf_session *self) | 1194 | static void perf_session__mmap_read(struct perf_session *self) |
1171 | { | 1195 | { |
1172 | int i, counter, thread_index; | 1196 | struct perf_evsel *counter; |
1197 | int i, thread_index; | ||
1173 | 1198 | ||
1174 | for (i = 0; i < nr_cpus; i++) { | 1199 | for (i = 0; i < cpus->nr; i++) { |
1175 | for (counter = 0; counter < nr_counters; counter++) | 1200 | list_for_each_entry(counter, &evsel_list, node) { |
1176 | for (thread_index = 0; | 1201 | for (thread_index = 0; |
1177 | thread_index < thread_num; | 1202 | thread_index < threads->nr; |
1178 | thread_index++) { | 1203 | thread_index++) { |
1179 | perf_session__mmap_read_counter(self, | 1204 | perf_session__mmap_read_counter(self, |
1180 | &mmap_array[i][counter][thread_index]); | 1205 | counter, i, thread_index); |
1181 | } | 1206 | } |
1207 | } | ||
1182 | } | 1208 | } |
1183 | } | 1209 | } |
1184 | 1210 | ||
1185 | int nr_poll; | 1211 | int nr_poll; |
1186 | int group_fd; | 1212 | int group_fd; |
1187 | 1213 | ||
1188 | static void start_counter(int i, int counter) | 1214 | static void start_counter(int i, struct perf_evsel *evsel) |
1189 | { | 1215 | { |
1216 | struct xyarray *mmap_array = evsel->priv; | ||
1217 | struct mmap_data *mm; | ||
1190 | struct perf_event_attr *attr; | 1218 | struct perf_event_attr *attr; |
1191 | int cpu = -1; | 1219 | int cpu = -1; |
1192 | int thread_index; | 1220 | int thread_index; |
1193 | 1221 | ||
1194 | if (target_tid == -1) | 1222 | if (target_tid == -1) |
1195 | cpu = cpumap[i]; | 1223 | cpu = cpus->map[i]; |
1196 | 1224 | ||
1197 | attr = attrs + counter; | 1225 | attr = &evsel->attr; |
1198 | 1226 | ||
1199 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 1227 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
1200 | 1228 | ||
@@ -1207,12 +1235,12 @@ static void start_counter(int i, int counter) | |||
1207 | attr->inherit = (cpu < 0) && inherit; | 1235 | attr->inherit = (cpu < 0) && inherit; |
1208 | attr->mmap = 1; | 1236 | attr->mmap = 1; |
1209 | 1237 | ||
1210 | for (thread_index = 0; thread_index < thread_num; thread_index++) { | 1238 | for (thread_index = 0; thread_index < threads->nr; thread_index++) { |
1211 | try_again: | 1239 | try_again: |
1212 | fd[i][counter][thread_index] = sys_perf_event_open(attr, | 1240 | FD(evsel, i, thread_index) = sys_perf_event_open(attr, |
1213 | all_tids[thread_index], cpu, group_fd, 0); | 1241 | threads->map[thread_index], cpu, group_fd, 0); |
1214 | 1242 | ||
1215 | if (fd[i][counter][thread_index] < 0) { | 1243 | if (FD(evsel, i, thread_index) < 0) { |
1216 | int err = errno; | 1244 | int err = errno; |
1217 | 1245 | ||
1218 | if (err == EPERM || err == EACCES) | 1246 | if (err == EPERM || err == EACCES) |
@@ -1236,29 +1264,29 @@ try_again: | |||
1236 | } | 1264 | } |
1237 | printf("\n"); | 1265 | printf("\n"); |
1238 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", | 1266 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", |
1239 | fd[i][counter][thread_index], strerror(err)); | 1267 | FD(evsel, i, thread_index), strerror(err)); |
1240 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1268 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
1241 | exit(-1); | 1269 | exit(-1); |
1242 | } | 1270 | } |
1243 | assert(fd[i][counter][thread_index] >= 0); | 1271 | assert(FD(evsel, i, thread_index) >= 0); |
1244 | fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); | 1272 | fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); |
1245 | 1273 | ||
1246 | /* | 1274 | /* |
1247 | * First counter acts as the group leader: | 1275 | * First counter acts as the group leader: |
1248 | */ | 1276 | */ |
1249 | if (group && group_fd == -1) | 1277 | if (group && group_fd == -1) |
1250 | group_fd = fd[i][counter][thread_index]; | 1278 | group_fd = FD(evsel, i, thread_index); |
1251 | 1279 | ||
1252 | event_array[nr_poll].fd = fd[i][counter][thread_index]; | 1280 | event_array[nr_poll].fd = FD(evsel, i, thread_index); |
1253 | event_array[nr_poll].events = POLLIN; | 1281 | event_array[nr_poll].events = POLLIN; |
1254 | nr_poll++; | 1282 | nr_poll++; |
1255 | 1283 | ||
1256 | mmap_array[i][counter][thread_index].counter = counter; | 1284 | mm = xyarray__entry(mmap_array, i, thread_index); |
1257 | mmap_array[i][counter][thread_index].prev = 0; | 1285 | mm->prev = 0; |
1258 | mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; | 1286 | mm->mask = mmap_pages*page_size - 1; |
1259 | mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, | 1287 | mm->base = mmap(NULL, (mmap_pages+1)*page_size, |
1260 | PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); | 1288 | PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); |
1261 | if (mmap_array[i][counter][thread_index].base == MAP_FAILED) | 1289 | if (mm->base == MAP_FAILED) |
1262 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 1290 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
1263 | } | 1291 | } |
1264 | } | 1292 | } |
@@ -1266,8 +1294,8 @@ try_again: | |||
1266 | static int __cmd_top(void) | 1294 | static int __cmd_top(void) |
1267 | { | 1295 | { |
1268 | pthread_t thread; | 1296 | pthread_t thread; |
1269 | int i, counter; | 1297 | struct perf_evsel *counter; |
1270 | int ret; | 1298 | int i, ret; |
1271 | /* | 1299 | /* |
1272 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 1300 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this |
1273 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | 1301 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. |
@@ -1281,9 +1309,9 @@ static int __cmd_top(void) | |||
1281 | else | 1309 | else |
1282 | event__synthesize_threads(event__process, session); | 1310 | event__synthesize_threads(event__process, session); |
1283 | 1311 | ||
1284 | for (i = 0; i < nr_cpus; i++) { | 1312 | for (i = 0; i < cpus->nr; i++) { |
1285 | group_fd = -1; | 1313 | group_fd = -1; |
1286 | for (counter = 0; counter < nr_counters; counter++) | 1314 | list_for_each_entry(counter, &evsel_list, node) |
1287 | start_counter(i, counter); | 1315 | start_counter(i, counter); |
1288 | } | 1316 | } |
1289 | 1317 | ||
@@ -1372,8 +1400,8 @@ static const struct option options[] = { | |||
1372 | 1400 | ||
1373 | int cmd_top(int argc, const char **argv, const char *prefix __used) | 1401 | int cmd_top(int argc, const char **argv, const char *prefix __used) |
1374 | { | 1402 | { |
1375 | int counter; | 1403 | struct perf_evsel *pos; |
1376 | int i,j; | 1404 | int status = -ENOMEM; |
1377 | 1405 | ||
1378 | page_size = sysconf(_SC_PAGE_SIZE); | 1406 | page_size = sysconf(_SC_PAGE_SIZE); |
1379 | 1407 | ||
@@ -1381,34 +1409,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1381 | if (argc) | 1409 | if (argc) |
1382 | usage_with_options(top_usage, options); | 1410 | usage_with_options(top_usage, options); |
1383 | 1411 | ||
1384 | if (target_pid != -1) { | 1412 | if (target_pid != -1) |
1385 | target_tid = target_pid; | 1413 | target_tid = target_pid; |
1386 | thread_num = find_all_tid(target_pid, &all_tids); | ||
1387 | if (thread_num <= 0) { | ||
1388 | fprintf(stderr, "Can't find all threads of pid %d\n", | ||
1389 | target_pid); | ||
1390 | usage_with_options(top_usage, options); | ||
1391 | } | ||
1392 | } else { | ||
1393 | all_tids=malloc(sizeof(pid_t)); | ||
1394 | if (!all_tids) | ||
1395 | return -ENOMEM; | ||
1396 | 1414 | ||
1397 | all_tids[0] = target_tid; | 1415 | threads = thread_map__new(target_pid, target_tid); |
1398 | thread_num = 1; | 1416 | if (threads == NULL) { |
1417 | pr_err("Problems finding threads of monitor\n"); | ||
1418 | usage_with_options(top_usage, options); | ||
1399 | } | 1419 | } |
1400 | 1420 | ||
1401 | for (i = 0; i < MAX_NR_CPUS; i++) { | 1421 | event_array = malloc((sizeof(struct pollfd) * |
1402 | for (j = 0; j < MAX_COUNTERS; j++) { | 1422 | MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); |
1403 | fd[i][j] = malloc(sizeof(int)*thread_num); | ||
1404 | mmap_array[i][j] = zalloc( | ||
1405 | sizeof(struct mmap_data)*thread_num); | ||
1406 | if (!fd[i][j] || !mmap_array[i][j]) | ||
1407 | return -ENOMEM; | ||
1408 | } | ||
1409 | } | ||
1410 | event_array = malloc( | ||
1411 | sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); | ||
1412 | if (!event_array) | 1423 | if (!event_array) |
1413 | return -ENOMEM; | 1424 | return -ENOMEM; |
1414 | 1425 | ||
@@ -1419,15 +1430,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1419 | cpu_list = NULL; | 1430 | cpu_list = NULL; |
1420 | } | 1431 | } |
1421 | 1432 | ||
1422 | if (!nr_counters) | 1433 | if (!nr_counters && perf_evsel_list__create_default() < 0) { |
1423 | nr_counters = 1; | 1434 | pr_err("Not enough memory for event selector list\n"); |
1424 | 1435 | return -ENOMEM; | |
1425 | symbol_conf.priv_size = (sizeof(struct sym_entry) + | 1436 | } |
1426 | (nr_counters + 1) * sizeof(unsigned long)); | ||
1427 | |||
1428 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | ||
1429 | if (symbol__init() < 0) | ||
1430 | return -1; | ||
1431 | 1437 | ||
1432 | if (delay_secs < 1) | 1438 | if (delay_secs < 1) |
1433 | delay_secs = 1; | 1439 | delay_secs = 1; |
@@ -1444,23 +1450,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1444 | exit(EXIT_FAILURE); | 1450 | exit(EXIT_FAILURE); |
1445 | } | 1451 | } |
1446 | 1452 | ||
1447 | /* | 1453 | if (target_tid != -1) |
1448 | * Fill in the ones not specifically initialized via -c: | 1454 | cpus = cpu_map__dummy_new(); |
1449 | */ | 1455 | else |
1450 | for (counter = 0; counter < nr_counters; counter++) { | 1456 | cpus = cpu_map__new(cpu_list); |
1451 | if (attrs[counter].sample_period) | 1457 | |
1458 | if (cpus == NULL) | ||
1459 | usage_with_options(top_usage, options); | ||
1460 | |||
1461 | list_for_each_entry(pos, &evsel_list, node) { | ||
1462 | if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || | ||
1463 | perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) | ||
1464 | goto out_free_fd; | ||
1465 | /* | ||
1466 | * Fill in the ones not specifically initialized via -c: | ||
1467 | */ | ||
1468 | if (pos->attr.sample_period) | ||
1452 | continue; | 1469 | continue; |
1453 | 1470 | ||
1454 | attrs[counter].sample_period = default_interval; | 1471 | pos->attr.sample_period = default_interval; |
1455 | } | 1472 | } |
1456 | 1473 | ||
1457 | if (target_tid != -1) | 1474 | symbol_conf.priv_size = (sizeof(struct sym_entry) + |
1458 | nr_cpus = 1; | 1475 | (nr_counters + 1) * sizeof(unsigned long)); |
1459 | else | ||
1460 | nr_cpus = read_cpu_map(cpu_list); | ||
1461 | 1476 | ||
1462 | if (nr_cpus < 1) | 1477 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1463 | usage_with_options(top_usage, options); | 1478 | if (symbol__init() < 0) |
1479 | return -1; | ||
1464 | 1480 | ||
1465 | get_term_dimensions(&winsize); | 1481 | get_term_dimensions(&winsize); |
1466 | if (print_entries == 0) { | 1482 | if (print_entries == 0) { |
@@ -1468,5 +1484,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1468 | signal(SIGWINCH, sig_winch_handler); | 1484 | signal(SIGWINCH, sig_winch_handler); |
1469 | } | 1485 | } |
1470 | 1486 | ||
1471 | return __cmd_top(); | 1487 | status = __cmd_top(); |
1488 | out_free_fd: | ||
1489 | list_for_each_entry(pos, &evsel_list, node) | ||
1490 | perf_evsel__free_mmap(pos); | ||
1491 | |||
1492 | return status; | ||
1472 | } | 1493 | } |