diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 283 |
1 files changed, 85 insertions, 198 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b6998e055767..ce2e50c891c7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -21,10 +21,12 @@ | |||
21 | #include "perf.h" | 21 | #include "perf.h" |
22 | 22 | ||
23 | #include "util/color.h" | 23 | #include "util/color.h" |
24 | #include "util/evlist.h" | ||
24 | #include "util/evsel.h" | 25 | #include "util/evsel.h" |
25 | #include "util/session.h" | 26 | #include "util/session.h" |
26 | #include "util/symbol.h" | 27 | #include "util/symbol.h" |
27 | #include "util/thread.h" | 28 | #include "util/thread.h" |
29 | #include "util/thread_map.h" | ||
28 | #include "util/util.h" | 30 | #include "util/util.h" |
29 | #include <linux/rbtree.h> | 31 | #include <linux/rbtree.h> |
30 | #include "util/parse-options.h" | 32 | #include "util/parse-options.h" |
@@ -60,6 +62,8 @@ | |||
60 | 62 | ||
61 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 63 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
62 | 64 | ||
65 | struct perf_evlist *evsel_list; | ||
66 | |||
63 | static bool system_wide = false; | 67 | static bool system_wide = false; |
64 | 68 | ||
65 | static int default_interval = 0; | 69 | static int default_interval = 0; |
@@ -75,7 +79,7 @@ static struct cpu_map *cpus; | |||
75 | static int realtime_prio = 0; | 79 | static int realtime_prio = 0; |
76 | static bool group = false; | 80 | static bool group = false; |
77 | static unsigned int page_size; | 81 | static unsigned int page_size; |
78 | static unsigned int mmap_pages = 16; | 82 | static unsigned int mmap_pages = 128; |
79 | static int freq = 1000; /* 1 KHz */ | 83 | static int freq = 1000; /* 1 KHz */ |
80 | 84 | ||
81 | static int delay_secs = 2; | 85 | static int delay_secs = 2; |
@@ -267,7 +271,7 @@ static void __zero_source_counters(struct sym_entry *syme) | |||
267 | 271 | ||
268 | line = syme->src->lines; | 272 | line = syme->src->lines; |
269 | while (line) { | 273 | while (line) { |
270 | for (i = 0; i < nr_counters; i++) | 274 | for (i = 0; i < evsel_list->nr_entries; i++) |
271 | line->count[i] = 0; | 275 | line->count[i] = 0; |
272 | line = line->next; | 276 | line = line->next; |
273 | } | 277 | } |
@@ -414,7 +418,7 @@ static double sym_weight(const struct sym_entry *sym) | |||
414 | if (!display_weighted) | 418 | if (!display_weighted) |
415 | return weight; | 419 | return weight; |
416 | 420 | ||
417 | for (counter = 1; counter < nr_counters-1; counter++) | 421 | for (counter = 1; counter < evsel_list->nr_entries - 1; counter++) |
418 | weight *= sym->count[counter]; | 422 | weight *= sym->count[counter]; |
419 | 423 | ||
420 | weight /= (sym->count[counter] + 1); | 424 | weight /= (sym->count[counter] + 1); |
@@ -501,7 +505,7 @@ static void print_sym_table(void) | |||
501 | rb_insert_active_sym(&tmp, syme); | 505 | rb_insert_active_sym(&tmp, syme); |
502 | sum_ksamples += syme->snap_count; | 506 | sum_ksamples += syme->snap_count; |
503 | 507 | ||
504 | for (j = 0; j < nr_counters; j++) | 508 | for (j = 0; j < evsel_list->nr_entries; j++) |
505 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; | 509 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; |
506 | } else | 510 | } else |
507 | list_remove_active_sym(syme); | 511 | list_remove_active_sym(syme); |
@@ -535,9 +539,9 @@ static void print_sym_table(void) | |||
535 | esamples_percent); | 539 | esamples_percent); |
536 | } | 540 | } |
537 | 541 | ||
538 | if (nr_counters == 1 || !display_weighted) { | 542 | if (evsel_list->nr_entries == 1 || !display_weighted) { |
539 | struct perf_evsel *first; | 543 | struct perf_evsel *first; |
540 | first = list_entry(evsel_list.next, struct perf_evsel, node); | 544 | first = list_entry(evsel_list->entries.next, struct perf_evsel, node); |
541 | printf("%" PRIu64, (uint64_t)first->attr.sample_period); | 545 | printf("%" PRIu64, (uint64_t)first->attr.sample_period); |
542 | if (freq) | 546 | if (freq) |
543 | printf("Hz "); | 547 | printf("Hz "); |
@@ -547,7 +551,7 @@ static void print_sym_table(void) | |||
547 | 551 | ||
548 | if (!display_weighted) | 552 | if (!display_weighted) |
549 | printf("%s", event_name(sym_evsel)); | 553 | printf("%s", event_name(sym_evsel)); |
550 | else list_for_each_entry(counter, &evsel_list, node) { | 554 | else list_for_each_entry(counter, &evsel_list->entries, node) { |
551 | if (counter->idx) | 555 | if (counter->idx) |
552 | printf("/"); | 556 | printf("/"); |
553 | 557 | ||
@@ -606,7 +610,7 @@ static void print_sym_table(void) | |||
606 | sym_width = winsize.ws_col - dso_width - 29; | 610 | sym_width = winsize.ws_col - dso_width - 29; |
607 | } | 611 | } |
608 | putchar('\n'); | 612 | putchar('\n'); |
609 | if (nr_counters == 1) | 613 | if (evsel_list->nr_entries == 1) |
610 | printf(" samples pcnt"); | 614 | printf(" samples pcnt"); |
611 | else | 615 | else |
612 | printf(" weight samples pcnt"); | 616 | printf(" weight samples pcnt"); |
@@ -615,7 +619,7 @@ static void print_sym_table(void) | |||
615 | printf(" RIP "); | 619 | printf(" RIP "); |
616 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); | 620 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); |
617 | printf(" %s _______ _____", | 621 | printf(" %s _______ _____", |
618 | nr_counters == 1 ? " " : "______"); | 622 | evsel_list->nr_entries == 1 ? " " : "______"); |
619 | if (verbose) | 623 | if (verbose) |
620 | printf(" ________________"); | 624 | printf(" ________________"); |
621 | printf(" %-*.*s", sym_width, sym_width, graph_line); | 625 | printf(" %-*.*s", sym_width, sym_width, graph_line); |
@@ -634,7 +638,7 @@ static void print_sym_table(void) | |||
634 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / | 638 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / |
635 | sum_ksamples)); | 639 | sum_ksamples)); |
636 | 640 | ||
637 | if (nr_counters == 1 || !display_weighted) | 641 | if (evsel_list->nr_entries == 1 || !display_weighted) |
638 | printf("%20.2f ", syme->weight); | 642 | printf("%20.2f ", syme->weight); |
639 | else | 643 | else |
640 | printf("%9.1f %10ld ", syme->weight, syme->snap_count); | 644 | printf("%9.1f %10ld ", syme->weight, syme->snap_count); |
@@ -744,7 +748,7 @@ static void print_mapped_keys(void) | |||
744 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); | 748 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); |
745 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); | 749 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); |
746 | 750 | ||
747 | if (nr_counters > 1) | 751 | if (evsel_list->nr_entries > 1) |
748 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); | 752 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); |
749 | 753 | ||
750 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); | 754 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); |
@@ -753,7 +757,7 @@ static void print_mapped_keys(void) | |||
753 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 757 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
754 | fprintf(stdout, "\t[S] stop annotation.\n"); | 758 | fprintf(stdout, "\t[S] stop annotation.\n"); |
755 | 759 | ||
756 | if (nr_counters > 1) | 760 | if (evsel_list->nr_entries > 1) |
757 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); | 761 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); |
758 | 762 | ||
759 | fprintf(stdout, | 763 | fprintf(stdout, |
@@ -783,7 +787,7 @@ static int key_mapped(int c) | |||
783 | return 1; | 787 | return 1; |
784 | case 'E': | 788 | case 'E': |
785 | case 'w': | 789 | case 'w': |
786 | return nr_counters > 1 ? 1 : 0; | 790 | return evsel_list->nr_entries > 1 ? 1 : 0; |
787 | default: | 791 | default: |
788 | break; | 792 | break; |
789 | } | 793 | } |
@@ -831,22 +835,22 @@ static void handle_keypress(struct perf_session *session, int c) | |||
831 | signal(SIGWINCH, SIG_DFL); | 835 | signal(SIGWINCH, SIG_DFL); |
832 | break; | 836 | break; |
833 | case 'E': | 837 | case 'E': |
834 | if (nr_counters > 1) { | 838 | if (evsel_list->nr_entries > 1) { |
835 | fprintf(stderr, "\nAvailable events:"); | 839 | fprintf(stderr, "\nAvailable events:"); |
836 | 840 | ||
837 | list_for_each_entry(sym_evsel, &evsel_list, node) | 841 | list_for_each_entry(sym_evsel, &evsel_list->entries, node) |
838 | fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); | 842 | fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); |
839 | 843 | ||
840 | prompt_integer(&sym_counter, "Enter details event counter"); | 844 | prompt_integer(&sym_counter, "Enter details event counter"); |
841 | 845 | ||
842 | if (sym_counter >= nr_counters) { | 846 | if (sym_counter >= evsel_list->nr_entries) { |
843 | sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); | 847 | sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); |
844 | sym_counter = 0; | 848 | sym_counter = 0; |
845 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); | 849 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); |
846 | sleep(1); | 850 | sleep(1); |
847 | break; | 851 | break; |
848 | } | 852 | } |
849 | list_for_each_entry(sym_evsel, &evsel_list, node) | 853 | list_for_each_entry(sym_evsel, &evsel_list->entries, node) |
850 | if (sym_evsel->idx == sym_counter) | 854 | if (sym_evsel->idx == sym_counter) |
851 | break; | 855 | break; |
852 | } else sym_counter = 0; | 856 | } else sym_counter = 0; |
@@ -930,6 +934,7 @@ repeat: | |||
930 | /* Tag samples to be skipped. */ | 934 | /* Tag samples to be skipped. */ |
931 | static const char *skip_symbols[] = { | 935 | static const char *skip_symbols[] = { |
932 | "default_idle", | 936 | "default_idle", |
937 | "native_safe_halt", | ||
933 | "cpu_idle", | 938 | "cpu_idle", |
934 | "enter_idle", | 939 | "enter_idle", |
935 | "exit_idle", | 940 | "exit_idle", |
@@ -988,8 +993,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
988 | 993 | ||
989 | static void event__process_sample(const event_t *self, | 994 | static void event__process_sample(const event_t *self, |
990 | struct sample_data *sample, | 995 | struct sample_data *sample, |
991 | struct perf_session *session, | 996 | struct perf_session *session) |
992 | struct perf_evsel *evsel) | ||
993 | { | 997 | { |
994 | u64 ip = self->ip.ip; | 998 | u64 ip = self->ip.ip; |
995 | struct sym_entry *syme; | 999 | struct sym_entry *syme; |
@@ -1082,8 +1086,12 @@ static void event__process_sample(const event_t *self, | |||
1082 | 1086 | ||
1083 | syme = symbol__priv(al.sym); | 1087 | syme = symbol__priv(al.sym); |
1084 | if (!syme->skip) { | 1088 | if (!syme->skip) { |
1085 | syme->count[evsel->idx]++; | 1089 | struct perf_evsel *evsel; |
1090 | |||
1086 | syme->origin = origin; | 1091 | syme->origin = origin; |
1092 | evsel = perf_evlist__id2evsel(evsel_list, sample->id); | ||
1093 | assert(evsel != NULL); | ||
1094 | syme->count[evsel->idx]++; | ||
1087 | record_precise_ip(syme, evsel->idx, ip); | 1095 | record_precise_ip(syme, evsel->idx, ip); |
1088 | pthread_mutex_lock(&active_symbols_lock); | 1096 | pthread_mutex_lock(&active_symbols_lock); |
1089 | if (list_empty(&syme->node) || !syme->node.next) | 1097 | if (list_empty(&syme->node) || !syme->node.next) |
@@ -1092,156 +1100,52 @@ static void event__process_sample(const event_t *self, | |||
1092 | } | 1100 | } |
1093 | } | 1101 | } |
1094 | 1102 | ||
1095 | struct mmap_data { | 1103 | static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) |
1096 | void *base; | ||
1097 | int mask; | ||
1098 | unsigned int prev; | ||
1099 | }; | ||
1100 | |||
1101 | static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, | ||
1102 | int ncpus, int nthreads) | ||
1103 | { | ||
1104 | evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); | ||
1105 | return evsel->priv != NULL ? 0 : -ENOMEM; | ||
1106 | } | ||
1107 | |||
1108 | static void perf_evsel__free_mmap(struct perf_evsel *evsel) | ||
1109 | { | ||
1110 | xyarray__delete(evsel->priv); | ||
1111 | evsel->priv = NULL; | ||
1112 | } | ||
1113 | |||
1114 | static unsigned int mmap_read_head(struct mmap_data *md) | ||
1115 | { | ||
1116 | struct perf_event_mmap_page *pc = md->base; | ||
1117 | int head; | ||
1118 | |||
1119 | head = pc->data_head; | ||
1120 | rmb(); | ||
1121 | |||
1122 | return head; | ||
1123 | } | ||
1124 | |||
1125 | static void perf_session__mmap_read_counter(struct perf_session *self, | ||
1126 | struct perf_evsel *evsel, | ||
1127 | int cpu, int thread_idx) | ||
1128 | { | 1104 | { |
1129 | struct xyarray *mmap_array = evsel->priv; | ||
1130 | struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); | ||
1131 | unsigned int head = mmap_read_head(md); | ||
1132 | unsigned int old = md->prev; | ||
1133 | unsigned char *data = md->base + page_size; | ||
1134 | struct sample_data sample; | 1105 | struct sample_data sample; |
1135 | int diff; | 1106 | event_t *event; |
1136 | |||
1137 | /* | ||
1138 | * If we're further behind than half the buffer, there's a chance | ||
1139 | * the writer will bite our tail and mess up the samples under us. | ||
1140 | * | ||
1141 | * If we somehow ended up ahead of the head, we got messed up. | ||
1142 | * | ||
1143 | * In either case, truncate and restart at head. | ||
1144 | */ | ||
1145 | diff = head - old; | ||
1146 | if (diff > md->mask / 2 || diff < 0) { | ||
1147 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | ||
1148 | |||
1149 | /* | ||
1150 | * head points to a known good entry, start there. | ||
1151 | */ | ||
1152 | old = head; | ||
1153 | } | ||
1154 | |||
1155 | for (; old != head;) { | ||
1156 | event_t *event = (event_t *)&data[old & md->mask]; | ||
1157 | 1107 | ||
1158 | event_t event_copy; | 1108 | while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { |
1159 | 1109 | perf_session__parse_sample(self, event, &sample); | |
1160 | size_t size = event->header.size; | ||
1161 | |||
1162 | /* | ||
1163 | * Event straddles the mmap boundary -- header should always | ||
1164 | * be inside due to u64 alignment of output. | ||
1165 | */ | ||
1166 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | ||
1167 | unsigned int offset = old; | ||
1168 | unsigned int len = min(sizeof(*event), size), cpy; | ||
1169 | void *dst = &event_copy; | ||
1170 | |||
1171 | do { | ||
1172 | cpy = min(md->mask + 1 - (offset & md->mask), len); | ||
1173 | memcpy(dst, &data[offset & md->mask], cpy); | ||
1174 | offset += cpy; | ||
1175 | dst += cpy; | ||
1176 | len -= cpy; | ||
1177 | } while (len); | ||
1178 | |||
1179 | event = &event_copy; | ||
1180 | } | ||
1181 | 1110 | ||
1182 | event__parse_sample(event, self, &sample); | ||
1183 | if (event->header.type == PERF_RECORD_SAMPLE) | 1111 | if (event->header.type == PERF_RECORD_SAMPLE) |
1184 | event__process_sample(event, &sample, self, evsel); | 1112 | event__process_sample(event, &sample, self); |
1185 | else | 1113 | else |
1186 | event__process(event, &sample, self); | 1114 | event__process(event, &sample, self); |
1187 | old += size; | ||
1188 | } | 1115 | } |
1189 | |||
1190 | md->prev = old; | ||
1191 | } | 1116 | } |
1192 | 1117 | ||
1193 | static struct pollfd *event_array; | ||
1194 | |||
1195 | static void perf_session__mmap_read(struct perf_session *self) | 1118 | static void perf_session__mmap_read(struct perf_session *self) |
1196 | { | 1119 | { |
1197 | struct perf_evsel *counter; | 1120 | int i; |
1198 | int i, thread_index; | ||
1199 | |||
1200 | for (i = 0; i < cpus->nr; i++) { | ||
1201 | list_for_each_entry(counter, &evsel_list, node) { | ||
1202 | for (thread_index = 0; | ||
1203 | thread_index < threads->nr; | ||
1204 | thread_index++) { | ||
1205 | perf_session__mmap_read_counter(self, | ||
1206 | counter, i, thread_index); | ||
1207 | } | ||
1208 | } | ||
1209 | } | ||
1210 | } | ||
1211 | 1121 | ||
1212 | int nr_poll; | 1122 | for (i = 0; i < cpus->nr; i++) |
1213 | int group_fd; | 1123 | perf_session__mmap_read_cpu(self, i); |
1124 | } | ||
1214 | 1125 | ||
1215 | static void start_counter(int i, struct perf_evsel *evsel) | 1126 | static void start_counters(struct perf_evlist *evlist) |
1216 | { | 1127 | { |
1217 | struct xyarray *mmap_array = evsel->priv; | 1128 | struct perf_evsel *counter; |
1218 | struct mmap_data *mm; | ||
1219 | struct perf_event_attr *attr; | ||
1220 | int cpu = -1; | ||
1221 | int thread_index; | ||
1222 | |||
1223 | if (target_tid == -1) | ||
1224 | cpu = cpus->map[i]; | ||
1225 | 1129 | ||
1226 | attr = &evsel->attr; | 1130 | list_for_each_entry(counter, &evlist->entries, node) { |
1131 | struct perf_event_attr *attr = &counter->attr; | ||
1227 | 1132 | ||
1228 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 1133 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
1229 | 1134 | ||
1230 | if (freq) { | 1135 | if (freq) { |
1231 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 1136 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
1232 | attr->freq = 1; | 1137 | attr->freq = 1; |
1233 | attr->sample_freq = freq; | 1138 | attr->sample_freq = freq; |
1234 | } | 1139 | } |
1235 | 1140 | ||
1236 | attr->inherit = (cpu < 0) && inherit; | 1141 | if (evlist->nr_entries > 1) { |
1237 | attr->mmap = 1; | 1142 | attr->sample_type |= PERF_SAMPLE_ID; |
1143 | attr->read_format |= PERF_FORMAT_ID; | ||
1144 | } | ||
1238 | 1145 | ||
1239 | for (thread_index = 0; thread_index < threads->nr; thread_index++) { | 1146 | attr->mmap = 1; |
1240 | try_again: | 1147 | try_again: |
1241 | FD(evsel, i, thread_index) = sys_perf_event_open(attr, | 1148 | if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) { |
1242 | threads->map[thread_index], cpu, group_fd, 0); | ||
1243 | |||
1244 | if (FD(evsel, i, thread_index) < 0) { | ||
1245 | int err = errno; | 1149 | int err = errno; |
1246 | 1150 | ||
1247 | if (err == EPERM || err == EACCES) | 1151 | if (err == EPERM || err == EACCES) |
@@ -1253,8 +1157,8 @@ try_again: | |||
1253 | * based cpu-clock-tick sw counter, which | 1157 | * based cpu-clock-tick sw counter, which |
1254 | * is always available even if no PMU support: | 1158 | * is always available even if no PMU support: |
1255 | */ | 1159 | */ |
1256 | if (attr->type == PERF_TYPE_HARDWARE | 1160 | if (attr->type == PERF_TYPE_HARDWARE && |
1257 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { | 1161 | attr->config == PERF_COUNT_HW_CPU_CYCLES) { |
1258 | 1162 | ||
1259 | if (verbose) | 1163 | if (verbose) |
1260 | warning(" ... trying to fall back to cpu-clock-ticks\n"); | 1164 | warning(" ... trying to fall back to cpu-clock-ticks\n"); |
@@ -1264,39 +1168,23 @@ try_again: | |||
1264 | goto try_again; | 1168 | goto try_again; |
1265 | } | 1169 | } |
1266 | printf("\n"); | 1170 | printf("\n"); |
1267 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", | 1171 | error("sys_perf_event_open() syscall returned with %d " |
1268 | FD(evsel, i, thread_index), strerror(err)); | 1172 | "(%s). /bin/dmesg may provide additional information.\n", |
1173 | err, strerror(err)); | ||
1269 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1174 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
1270 | exit(-1); | 1175 | exit(-1); |
1271 | } | 1176 | } |
1272 | assert(FD(evsel, i, thread_index) >= 0); | ||
1273 | fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); | ||
1274 | |||
1275 | /* | ||
1276 | * First counter acts as the group leader: | ||
1277 | */ | ||
1278 | if (group && group_fd == -1) | ||
1279 | group_fd = FD(evsel, i, thread_index); | ||
1280 | |||
1281 | event_array[nr_poll].fd = FD(evsel, i, thread_index); | ||
1282 | event_array[nr_poll].events = POLLIN; | ||
1283 | nr_poll++; | ||
1284 | |||
1285 | mm = xyarray__entry(mmap_array, i, thread_index); | ||
1286 | mm->prev = 0; | ||
1287 | mm->mask = mmap_pages*page_size - 1; | ||
1288 | mm->base = mmap(NULL, (mmap_pages+1)*page_size, | ||
1289 | PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); | ||
1290 | if (mm->base == MAP_FAILED) | ||
1291 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | ||
1292 | } | 1177 | } |
1178 | |||
1179 | if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0) | ||
1180 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | ||
1293 | } | 1181 | } |
1294 | 1182 | ||
1295 | static int __cmd_top(void) | 1183 | static int __cmd_top(void) |
1296 | { | 1184 | { |
1297 | pthread_t thread; | 1185 | pthread_t thread; |
1298 | struct perf_evsel *counter; | 1186 | struct perf_evsel *first; |
1299 | int i, ret; | 1187 | int ret; |
1300 | /* | 1188 | /* |
1301 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 1189 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this |
1302 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | 1190 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. |
@@ -1310,14 +1198,12 @@ static int __cmd_top(void) | |||
1310 | else | 1198 | else |
1311 | event__synthesize_threads(event__process, session); | 1199 | event__synthesize_threads(event__process, session); |
1312 | 1200 | ||
1313 | for (i = 0; i < cpus->nr; i++) { | 1201 | start_counters(evsel_list); |
1314 | group_fd = -1; | 1202 | first = list_entry(evsel_list->entries.next, struct perf_evsel, node); |
1315 | list_for_each_entry(counter, &evsel_list, node) | 1203 | perf_session__set_sample_type(session, first->attr.sample_type); |
1316 | start_counter(i, counter); | ||
1317 | } | ||
1318 | 1204 | ||
1319 | /* Wait for a minimal set of events before starting the snapshot */ | 1205 | /* Wait for a minimal set of events before starting the snapshot */ |
1320 | poll(&event_array[0], nr_poll, 100); | 1206 | poll(evsel_list->pollfd, evsel_list->nr_fds, 100); |
1321 | 1207 | ||
1322 | perf_session__mmap_read(session); | 1208 | perf_session__mmap_read(session); |
1323 | 1209 | ||
@@ -1342,7 +1228,7 @@ static int __cmd_top(void) | |||
1342 | perf_session__mmap_read(session); | 1228 | perf_session__mmap_read(session); |
1343 | 1229 | ||
1344 | if (hits == samples) | 1230 | if (hits == samples) |
1345 | ret = poll(event_array, nr_poll, 100); | 1231 | ret = poll(evsel_list->pollfd, evsel_list->nr_fds, 100); |
1346 | } | 1232 | } |
1347 | 1233 | ||
1348 | return 0; | 1234 | return 0; |
@@ -1354,7 +1240,7 @@ static const char * const top_usage[] = { | |||
1354 | }; | 1240 | }; |
1355 | 1241 | ||
1356 | static const struct option options[] = { | 1242 | static const struct option options[] = { |
1357 | OPT_CALLBACK('e', "event", NULL, "event", | 1243 | OPT_CALLBACK('e', "event", &evsel_list, "event", |
1358 | "event selector. use 'perf list' to list available events", | 1244 | "event selector. use 'perf list' to list available events", |
1359 | parse_events), | 1245 | parse_events), |
1360 | OPT_INTEGER('c', "count", &default_interval, | 1246 | OPT_INTEGER('c', "count", &default_interval, |
@@ -1404,6 +1290,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1404 | struct perf_evsel *pos; | 1290 | struct perf_evsel *pos; |
1405 | int status = -ENOMEM; | 1291 | int status = -ENOMEM; |
1406 | 1292 | ||
1293 | evsel_list = perf_evlist__new(); | ||
1294 | if (evsel_list == NULL) | ||
1295 | return -ENOMEM; | ||
1296 | |||
1407 | page_size = sysconf(_SC_PAGE_SIZE); | 1297 | page_size = sysconf(_SC_PAGE_SIZE); |
1408 | 1298 | ||
1409 | argc = parse_options(argc, argv, options, top_usage, 0); | 1299 | argc = parse_options(argc, argv, options, top_usage, 0); |
@@ -1419,11 +1309,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1419 | usage_with_options(top_usage, options); | 1309 | usage_with_options(top_usage, options); |
1420 | } | 1310 | } |
1421 | 1311 | ||
1422 | event_array = malloc((sizeof(struct pollfd) * | ||
1423 | MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); | ||
1424 | if (!event_array) | ||
1425 | return -ENOMEM; | ||
1426 | |||
1427 | /* CPU and PID are mutually exclusive */ | 1312 | /* CPU and PID are mutually exclusive */ |
1428 | if (target_tid > 0 && cpu_list) { | 1313 | if (target_tid > 0 && cpu_list) { |
1429 | printf("WARNING: PID switch overriding CPU\n"); | 1314 | printf("WARNING: PID switch overriding CPU\n"); |
@@ -1431,7 +1316,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1431 | cpu_list = NULL; | 1316 | cpu_list = NULL; |
1432 | } | 1317 | } |
1433 | 1318 | ||
1434 | if (!nr_counters && perf_evsel_list__create_default() < 0) { | 1319 | if (!evsel_list->nr_entries && |
1320 | perf_evlist__add_default(evsel_list) < 0) { | ||
1435 | pr_err("Not enough memory for event selector list\n"); | 1321 | pr_err("Not enough memory for event selector list\n"); |
1436 | return -ENOMEM; | 1322 | return -ENOMEM; |
1437 | } | 1323 | } |
@@ -1459,9 +1345,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1459 | if (cpus == NULL) | 1345 | if (cpus == NULL) |
1460 | usage_with_options(top_usage, options); | 1346 | usage_with_options(top_usage, options); |
1461 | 1347 | ||
1462 | list_for_each_entry(pos, &evsel_list, node) { | 1348 | list_for_each_entry(pos, &evsel_list->entries, node) { |
1463 | if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || | 1349 | if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) |
1464 | perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) | ||
1465 | goto out_free_fd; | 1350 | goto out_free_fd; |
1466 | /* | 1351 | /* |
1467 | * Fill in the ones not specifically initialized via -c: | 1352 | * Fill in the ones not specifically initialized via -c: |
@@ -1472,10 +1357,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1472 | pos->attr.sample_period = default_interval; | 1357 | pos->attr.sample_period = default_interval; |
1473 | } | 1358 | } |
1474 | 1359 | ||
1475 | sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); | 1360 | if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 || |
1361 | perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0) | ||
1362 | goto out_free_fd; | ||
1363 | |||
1364 | sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); | ||
1476 | 1365 | ||
1477 | symbol_conf.priv_size = (sizeof(struct sym_entry) + | 1366 | symbol_conf.priv_size = (sizeof(struct sym_entry) + |
1478 | (nr_counters + 1) * sizeof(unsigned long)); | 1367 | (evsel_list->nr_entries + 1) * sizeof(unsigned long)); |
1479 | 1368 | ||
1480 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1369 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1481 | if (symbol__init() < 0) | 1370 | if (symbol__init() < 0) |
@@ -1489,9 +1378,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1489 | 1378 | ||
1490 | status = __cmd_top(); | 1379 | status = __cmd_top(); |
1491 | out_free_fd: | 1380 | out_free_fd: |
1492 | list_for_each_entry(pos, &evsel_list, node) | 1381 | perf_evlist__delete(evsel_list); |
1493 | perf_evsel__free_mmap(pos); | ||
1494 | perf_evsel_list__delete(); | ||
1495 | 1382 | ||
1496 | return status; | 1383 | return status; |
1497 | } | 1384 | } |