diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 237 |
1 files changed, 131 insertions, 106 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dd625808c2a5..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': |
@@ -977,12 +986,13 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
977 | } | 986 | } |
978 | 987 | ||
979 | static void event__process_sample(const event_t *self, | 988 | static void event__process_sample(const event_t *self, |
980 | struct perf_session *session, int counter) | 989 | struct sample_data *sample, |
990 | struct perf_session *session, | ||
991 | struct perf_evsel *evsel) | ||
981 | { | 992 | { |
982 | u64 ip = self->ip.ip; | 993 | u64 ip = self->ip.ip; |
983 | struct sym_entry *syme; | 994 | struct sym_entry *syme; |
984 | struct addr_location al; | 995 | struct addr_location al; |
985 | struct sample_data data; | ||
986 | struct machine *machine; | 996 | struct machine *machine; |
987 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 997 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
988 | 998 | ||
@@ -1025,7 +1035,7 @@ static void event__process_sample(const event_t *self, | |||
1025 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) | 1035 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) |
1026 | exact_samples++; | 1036 | exact_samples++; |
1027 | 1037 | ||
1028 | if (event__preprocess_sample(self, session, &al, &data, | 1038 | if (event__preprocess_sample(self, session, &al, sample, |
1029 | symbol_filter) < 0 || | 1039 | symbol_filter) < 0 || |
1030 | al.filtered) | 1040 | al.filtered) |
1031 | return; | 1041 | return; |
@@ -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,11 +1122,15 @@ 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; |
1133 | struct sample_data sample; | ||
1108 | int diff; | 1134 | int diff; |
1109 | 1135 | ||
1110 | /* | 1136 | /* |
@@ -1152,10 +1178,11 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1152 | event = &event_copy; | 1178 | event = &event_copy; |
1153 | } | 1179 | } |
1154 | 1180 | ||
1181 | event__parse_sample(event, self, &sample); | ||
1155 | if (event->header.type == PERF_RECORD_SAMPLE) | 1182 | if (event->header.type == PERF_RECORD_SAMPLE) |
1156 | event__process_sample(event, self, md->counter); | 1183 | event__process_sample(event, &sample, self, evsel); |
1157 | else | 1184 | else |
1158 | event__process(event, self); | 1185 | event__process(event, &sample, self); |
1159 | old += size; | 1186 | old += size; |
1160 | } | 1187 | } |
1161 | 1188 | ||
@@ -1163,36 +1190,39 @@ static void perf_session__mmap_read_counter(struct perf_session *self, | |||
1163 | } | 1190 | } |
1164 | 1191 | ||
1165 | static struct pollfd *event_array; | 1192 | static struct pollfd *event_array; |
1166 | static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | ||
1167 | 1193 | ||
1168 | static void perf_session__mmap_read(struct perf_session *self) | 1194 | static void perf_session__mmap_read(struct perf_session *self) |
1169 | { | 1195 | { |
1170 | int i, counter, thread_index; | 1196 | struct perf_evsel *counter; |
1197 | int i, thread_index; | ||
1171 | 1198 | ||
1172 | for (i = 0; i < nr_cpus; i++) { | 1199 | for (i = 0; i < cpus->nr; i++) { |
1173 | for (counter = 0; counter < nr_counters; counter++) | 1200 | list_for_each_entry(counter, &evsel_list, node) { |
1174 | for (thread_index = 0; | 1201 | for (thread_index = 0; |
1175 | thread_index < thread_num; | 1202 | thread_index < threads->nr; |
1176 | thread_index++) { | 1203 | thread_index++) { |
1177 | perf_session__mmap_read_counter(self, | 1204 | perf_session__mmap_read_counter(self, |
1178 | &mmap_array[i][counter][thread_index]); | 1205 | counter, i, thread_index); |
1179 | } | 1206 | } |
1207 | } | ||
1180 | } | 1208 | } |
1181 | } | 1209 | } |
1182 | 1210 | ||
1183 | int nr_poll; | 1211 | int nr_poll; |
1184 | int group_fd; | 1212 | int group_fd; |
1185 | 1213 | ||
1186 | static void start_counter(int i, int counter) | 1214 | static void start_counter(int i, struct perf_evsel *evsel) |
1187 | { | 1215 | { |
1216 | struct xyarray *mmap_array = evsel->priv; | ||
1217 | struct mmap_data *mm; | ||
1188 | struct perf_event_attr *attr; | 1218 | struct perf_event_attr *attr; |
1189 | int cpu = -1; | 1219 | int cpu = -1; |
1190 | int thread_index; | 1220 | int thread_index; |
1191 | 1221 | ||
1192 | if (target_tid == -1) | 1222 | if (target_tid == -1) |
1193 | cpu = cpumap[i]; | 1223 | cpu = cpus->map[i]; |
1194 | 1224 | ||
1195 | attr = attrs + counter; | 1225 | attr = &evsel->attr; |
1196 | 1226 | ||
1197 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 1227 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
1198 | 1228 | ||
@@ -1205,16 +1235,18 @@ static void start_counter(int i, int counter) | |||
1205 | attr->inherit = (cpu < 0) && inherit; | 1235 | attr->inherit = (cpu < 0) && inherit; |
1206 | attr->mmap = 1; | 1236 | attr->mmap = 1; |
1207 | 1237 | ||
1208 | for (thread_index = 0; thread_index < thread_num; thread_index++) { | 1238 | for (thread_index = 0; thread_index < threads->nr; thread_index++) { |
1209 | try_again: | 1239 | try_again: |
1210 | fd[i][counter][thread_index] = sys_perf_event_open(attr, | 1240 | FD(evsel, i, thread_index) = sys_perf_event_open(attr, |
1211 | all_tids[thread_index], cpu, group_fd, 0); | 1241 | threads->map[thread_index], cpu, group_fd, 0); |
1212 | 1242 | ||
1213 | if (fd[i][counter][thread_index] < 0) { | 1243 | if (FD(evsel, i, thread_index) < 0) { |
1214 | int err = errno; | 1244 | int err = errno; |
1215 | 1245 | ||
1216 | if (err == EPERM || err == EACCES) | 1246 | if (err == EPERM || err == EACCES) |
1217 | die("No permission - are you root?\n"); | 1247 | die("Permission error - are you root?\n" |
1248 | "\t Consider tweaking" | ||
1249 | " /proc/sys/kernel/perf_event_paranoid.\n"); | ||
1218 | /* | 1250 | /* |
1219 | * If it's cycles then fall back to hrtimer | 1251 | * If it's cycles then fall back to hrtimer |
1220 | * based cpu-clock-tick sw counter, which | 1252 | * based cpu-clock-tick sw counter, which |
@@ -1231,30 +1263,30 @@ try_again: | |||
1231 | goto try_again; | 1263 | goto try_again; |
1232 | } | 1264 | } |
1233 | printf("\n"); | 1265 | printf("\n"); |
1234 | error("perfcounter syscall returned with %d (%s)\n", | 1266 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", |
1235 | fd[i][counter][thread_index], strerror(err)); | 1267 | FD(evsel, i, thread_index), strerror(err)); |
1236 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1268 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
1237 | exit(-1); | 1269 | exit(-1); |
1238 | } | 1270 | } |
1239 | assert(fd[i][counter][thread_index] >= 0); | 1271 | assert(FD(evsel, i, thread_index) >= 0); |
1240 | fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); | 1272 | fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); |
1241 | 1273 | ||
1242 | /* | 1274 | /* |
1243 | * First counter acts as the group leader: | 1275 | * First counter acts as the group leader: |
1244 | */ | 1276 | */ |
1245 | if (group && group_fd == -1) | 1277 | if (group && group_fd == -1) |
1246 | group_fd = fd[i][counter][thread_index]; | 1278 | group_fd = FD(evsel, i, thread_index); |
1247 | 1279 | ||
1248 | event_array[nr_poll].fd = fd[i][counter][thread_index]; | 1280 | event_array[nr_poll].fd = FD(evsel, i, thread_index); |
1249 | event_array[nr_poll].events = POLLIN; | 1281 | event_array[nr_poll].events = POLLIN; |
1250 | nr_poll++; | 1282 | nr_poll++; |
1251 | 1283 | ||
1252 | mmap_array[i][counter][thread_index].counter = counter; | 1284 | mm = xyarray__entry(mmap_array, i, thread_index); |
1253 | mmap_array[i][counter][thread_index].prev = 0; | 1285 | mm->prev = 0; |
1254 | mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; | 1286 | mm->mask = mmap_pages*page_size - 1; |
1255 | mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, | 1287 | mm->base = mmap(NULL, (mmap_pages+1)*page_size, |
1256 | PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); | 1288 | PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); |
1257 | if (mmap_array[i][counter][thread_index].base == MAP_FAILED) | 1289 | if (mm->base == MAP_FAILED) |
1258 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 1290 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
1259 | } | 1291 | } |
1260 | } | 1292 | } |
@@ -1262,13 +1294,13 @@ try_again: | |||
1262 | static int __cmd_top(void) | 1294 | static int __cmd_top(void) |
1263 | { | 1295 | { |
1264 | pthread_t thread; | 1296 | pthread_t thread; |
1265 | int i, counter; | 1297 | struct perf_evsel *counter; |
1266 | int ret; | 1298 | int i, ret; |
1267 | /* | 1299 | /* |
1268 | * 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 |
1269 | * 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. |
1270 | */ | 1302 | */ |
1271 | struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false); | 1303 | struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); |
1272 | if (session == NULL) | 1304 | if (session == NULL) |
1273 | return -ENOMEM; | 1305 | return -ENOMEM; |
1274 | 1306 | ||
@@ -1277,9 +1309,9 @@ static int __cmd_top(void) | |||
1277 | else | 1309 | else |
1278 | event__synthesize_threads(event__process, session); | 1310 | event__synthesize_threads(event__process, session); |
1279 | 1311 | ||
1280 | for (i = 0; i < nr_cpus; i++) { | 1312 | for (i = 0; i < cpus->nr; i++) { |
1281 | group_fd = -1; | 1313 | group_fd = -1; |
1282 | for (counter = 0; counter < nr_counters; counter++) | 1314 | list_for_each_entry(counter, &evsel_list, node) |
1283 | start_counter(i, counter); | 1315 | start_counter(i, counter); |
1284 | } | 1316 | } |
1285 | 1317 | ||
@@ -1368,8 +1400,8 @@ static const struct option options[] = { | |||
1368 | 1400 | ||
1369 | 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) |
1370 | { | 1402 | { |
1371 | int counter; | 1403 | struct perf_evsel *pos; |
1372 | int i,j; | 1404 | int status = -ENOMEM; |
1373 | 1405 | ||
1374 | page_size = sysconf(_SC_PAGE_SIZE); | 1406 | page_size = sysconf(_SC_PAGE_SIZE); |
1375 | 1407 | ||
@@ -1377,34 +1409,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1377 | if (argc) | 1409 | if (argc) |
1378 | usage_with_options(top_usage, options); | 1410 | usage_with_options(top_usage, options); |
1379 | 1411 | ||
1380 | if (target_pid != -1) { | 1412 | if (target_pid != -1) |
1381 | target_tid = target_pid; | 1413 | target_tid = target_pid; |
1382 | thread_num = find_all_tid(target_pid, &all_tids); | ||
1383 | if (thread_num <= 0) { | ||
1384 | fprintf(stderr, "Can't find all threads of pid %d\n", | ||
1385 | target_pid); | ||
1386 | usage_with_options(top_usage, options); | ||
1387 | } | ||
1388 | } else { | ||
1389 | all_tids=malloc(sizeof(pid_t)); | ||
1390 | if (!all_tids) | ||
1391 | return -ENOMEM; | ||
1392 | 1414 | ||
1393 | all_tids[0] = target_tid; | 1415 | threads = thread_map__new(target_pid, target_tid); |
1394 | thread_num = 1; | 1416 | if (threads == NULL) { |
1417 | pr_err("Problems finding threads of monitor\n"); | ||
1418 | usage_with_options(top_usage, options); | ||
1395 | } | 1419 | } |
1396 | 1420 | ||
1397 | for (i = 0; i < MAX_NR_CPUS; i++) { | 1421 | event_array = malloc((sizeof(struct pollfd) * |
1398 | for (j = 0; j < MAX_COUNTERS; j++) { | 1422 | MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); |
1399 | fd[i][j] = malloc(sizeof(int)*thread_num); | ||
1400 | mmap_array[i][j] = zalloc( | ||
1401 | sizeof(struct mmap_data)*thread_num); | ||
1402 | if (!fd[i][j] || !mmap_array[i][j]) | ||
1403 | return -ENOMEM; | ||
1404 | } | ||
1405 | } | ||
1406 | event_array = malloc( | ||
1407 | sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); | ||
1408 | if (!event_array) | 1423 | if (!event_array) |
1409 | return -ENOMEM; | 1424 | return -ENOMEM; |
1410 | 1425 | ||
@@ -1415,15 +1430,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1415 | cpu_list = NULL; | 1430 | cpu_list = NULL; |
1416 | } | 1431 | } |
1417 | 1432 | ||
1418 | if (!nr_counters) | 1433 | if (!nr_counters && perf_evsel_list__create_default() < 0) { |
1419 | nr_counters = 1; | 1434 | pr_err("Not enough memory for event selector list\n"); |
1420 | 1435 | return -ENOMEM; | |
1421 | symbol_conf.priv_size = (sizeof(struct sym_entry) + | 1436 | } |
1422 | (nr_counters + 1) * sizeof(unsigned long)); | ||
1423 | |||
1424 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | ||
1425 | if (symbol__init() < 0) | ||
1426 | return -1; | ||
1427 | 1437 | ||
1428 | if (delay_secs < 1) | 1438 | if (delay_secs < 1) |
1429 | delay_secs = 1; | 1439 | delay_secs = 1; |
@@ -1440,23 +1450,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1440 | exit(EXIT_FAILURE); | 1450 | exit(EXIT_FAILURE); |
1441 | } | 1451 | } |
1442 | 1452 | ||
1443 | /* | 1453 | if (target_tid != -1) |
1444 | * Fill in the ones not specifically initialized via -c: | 1454 | cpus = cpu_map__dummy_new(); |
1445 | */ | 1455 | else |
1446 | for (counter = 0; counter < nr_counters; counter++) { | 1456 | cpus = cpu_map__new(cpu_list); |
1447 | 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) | ||
1448 | continue; | 1469 | continue; |
1449 | 1470 | ||
1450 | attrs[counter].sample_period = default_interval; | 1471 | pos->attr.sample_period = default_interval; |
1451 | } | 1472 | } |
1452 | 1473 | ||
1453 | if (target_tid != -1) | 1474 | symbol_conf.priv_size = (sizeof(struct sym_entry) + |
1454 | nr_cpus = 1; | 1475 | (nr_counters + 1) * sizeof(unsigned long)); |
1455 | else | ||
1456 | nr_cpus = read_cpu_map(cpu_list); | ||
1457 | 1476 | ||
1458 | if (nr_cpus < 1) | 1477 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1459 | usage_with_options(top_usage, options); | 1478 | if (symbol__init() < 0) |
1479 | return -1; | ||
1460 | 1480 | ||
1461 | get_term_dimensions(&winsize); | 1481 | get_term_dimensions(&winsize); |
1462 | if (print_entries == 0) { | 1482 | if (print_entries == 0) { |
@@ -1464,5 +1484,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1464 | signal(SIGWINCH, sig_winch_handler); | 1484 | signal(SIGWINCH, sig_winch_handler); |
1465 | } | 1485 | } |
1466 | 1486 | ||
1467 | 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; | ||
1468 | } | 1493 | } |