diff options
-rw-r--r-- | tools/perf/builtin-top.c | 71 | ||||
-rw-r--r-- | tools/perf/perf.h | 14 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 8 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 71 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 8 |
6 files changed, 107 insertions, 66 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 15d89bede2f..7d723ad0bfa 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -1095,43 +1095,12 @@ static void event__process_sample(const event_t *self, | |||
1095 | } | 1095 | } |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | struct mmap_data { | ||
1099 | void *base; | ||
1100 | int mask; | ||
1101 | unsigned int prev; | ||
1102 | }; | ||
1103 | |||
1104 | static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, | ||
1105 | int ncpus, int nthreads) | ||
1106 | { | ||
1107 | evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); | ||
1108 | return evsel->priv != NULL ? 0 : -ENOMEM; | ||
1109 | } | ||
1110 | |||
1111 | static void perf_evsel__free_mmap(struct perf_evsel *evsel) | ||
1112 | { | ||
1113 | xyarray__delete(evsel->priv); | ||
1114 | evsel->priv = NULL; | ||
1115 | } | ||
1116 | |||
1117 | static unsigned int mmap_read_head(struct mmap_data *md) | ||
1118 | { | ||
1119 | struct perf_event_mmap_page *pc = md->base; | ||
1120 | int head; | ||
1121 | |||
1122 | head = pc->data_head; | ||
1123 | rmb(); | ||
1124 | |||
1125 | return head; | ||
1126 | } | ||
1127 | |||
1128 | static void perf_session__mmap_read_counter(struct perf_session *self, | 1098 | static void perf_session__mmap_read_counter(struct perf_session *self, |
1129 | struct perf_evsel *evsel, | 1099 | struct perf_evsel *evsel, |
1130 | int cpu, int thread_idx) | 1100 | int cpu, int thread_idx) |
1131 | { | 1101 | { |
1132 | struct xyarray *mmap_array = evsel->priv; | 1102 | struct perf_mmap *md = xyarray__entry(evsel->mmap, cpu, thread_idx); |
1133 | struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); | 1103 | unsigned int head = perf_mmap__read_head(md); |
1134 | unsigned int head = mmap_read_head(md); | ||
1135 | unsigned int old = md->prev; | 1104 | unsigned int old = md->prev; |
1136 | unsigned char *data = md->base + page_size; | 1105 | unsigned char *data = md->base + page_size; |
1137 | struct sample_data sample; | 1106 | struct sample_data sample; |
@@ -1210,35 +1179,9 @@ static void perf_session__mmap_read(struct perf_session *self) | |||
1210 | } | 1179 | } |
1211 | } | 1180 | } |
1212 | 1181 | ||
1213 | static void start_counter(int i, struct perf_evlist *evlist, | ||
1214 | struct perf_evsel *evsel) | ||
1215 | { | ||
1216 | struct xyarray *mmap_array = evsel->priv; | ||
1217 | struct mmap_data *mm; | ||
1218 | int thread_index; | ||
1219 | |||
1220 | for (thread_index = 0; thread_index < threads->nr; thread_index++) { | ||
1221 | assert(FD(evsel, i, thread_index) >= 0); | ||
1222 | fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); | ||
1223 | |||
1224 | evlist->pollfd[evlist->nr_fds].fd = FD(evsel, i, thread_index); | ||
1225 | evlist->pollfd[evlist->nr_fds].events = POLLIN; | ||
1226 | evlist->nr_fds++; | ||
1227 | |||
1228 | mm = xyarray__entry(mmap_array, i, thread_index); | ||
1229 | mm->prev = 0; | ||
1230 | mm->mask = mmap_pages*page_size - 1; | ||
1231 | mm->base = mmap(NULL, (mmap_pages+1)*page_size, | ||
1232 | PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); | ||
1233 | if (mm->base == MAP_FAILED) | ||
1234 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | ||
1235 | } | ||
1236 | } | ||
1237 | |||
1238 | static void start_counters(struct perf_evlist *evlist) | 1182 | static void start_counters(struct perf_evlist *evlist) |
1239 | { | 1183 | { |
1240 | struct perf_evsel *counter; | 1184 | struct perf_evsel *counter; |
1241 | int i; | ||
1242 | 1185 | ||
1243 | list_for_each_entry(counter, &evlist->entries, node) { | 1186 | list_for_each_entry(counter, &evlist->entries, node) { |
1244 | struct perf_event_attr *attr = &counter->attr; | 1187 | struct perf_event_attr *attr = &counter->attr; |
@@ -1282,11 +1225,9 @@ try_again: | |||
1282 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1225 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
1283 | exit(-1); | 1226 | exit(-1); |
1284 | } | 1227 | } |
1285 | } | ||
1286 | 1228 | ||
1287 | for (i = 0; i < cpus->nr; i++) { | 1229 | if (perf_evsel__mmap(counter, cpus, threads, mmap_pages, evlist) < 0) |
1288 | list_for_each_entry(counter, &evlist->entries, node) | 1230 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
1289 | start_counter(i, evsel_list, counter); | ||
1290 | } | 1231 | } |
1291 | } | 1232 | } |
1292 | 1233 | ||
@@ -1453,7 +1394,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1453 | usage_with_options(top_usage, options); | 1394 | usage_with_options(top_usage, options); |
1454 | 1395 | ||
1455 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1396 | list_for_each_entry(pos, &evsel_list->entries, node) { |
1456 | if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || | 1397 | if (perf_evsel__alloc_mmap(pos, cpus->nr, threads->nr) < 0 || |
1457 | perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) | 1398 | perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) |
1458 | goto out_free_fd; | 1399 | goto out_free_fd; |
1459 | /* | 1400 | /* |
@@ -1485,8 +1426,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1485 | 1426 | ||
1486 | status = __cmd_top(); | 1427 | status = __cmd_top(); |
1487 | out_free_fd: | 1428 | out_free_fd: |
1488 | list_for_each_entry(pos, &evsel_list->entries, node) | ||
1489 | perf_evsel__free_mmap(pos); | ||
1490 | perf_evlist__delete(evsel_list); | 1429 | perf_evlist__delete(evsel_list); |
1491 | 1430 | ||
1492 | return status; | 1431 | return status; |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 95aaf565c70..5fb5e1f11d1 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -94,6 +94,20 @@ void get_term_dimensions(struct winsize *ws); | |||
94 | #include "util/types.h" | 94 | #include "util/types.h" |
95 | #include <stdbool.h> | 95 | #include <stdbool.h> |
96 | 96 | ||
97 | struct perf_mmap { | ||
98 | void *base; | ||
99 | int mask; | ||
100 | unsigned int prev; | ||
101 | }; | ||
102 | |||
103 | static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) | ||
104 | { | ||
105 | struct perf_event_mmap_page *pc = mm->base; | ||
106 | int head = pc->data_head; | ||
107 | rmb(); | ||
108 | return head; | ||
109 | } | ||
110 | |||
97 | /* | 111 | /* |
98 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all | 112 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all |
99 | * counters in the current task. | 113 | * counters in the current task. |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 2abf949259d..6d4129214ee 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -60,3 +60,11 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthread | |||
60 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 60 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
61 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 61 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
62 | } | 62 | } |
63 | |||
64 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | ||
65 | { | ||
66 | fcntl(fd, F_SETFL, O_NONBLOCK); | ||
67 | evlist->pollfd[evlist->nr_fds].fd = fd; | ||
68 | evlist->pollfd[evlist->nr_fds].events = POLLIN; | ||
69 | evlist->nr_fds++; | ||
70 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a7d7e122e3c..16bbfcba8ca 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -21,5 +21,6 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); | |||
21 | int perf_evlist__add_default(struct perf_evlist *evlist); | 21 | int perf_evlist__add_default(struct perf_evlist *evlist); |
22 | 22 | ||
23 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); | 23 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); |
24 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); | ||
24 | 25 | ||
25 | #endif /* __PERF_EVLIST_H */ | 26 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 82a00536892..f5006958f8d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1,9 +1,13 @@ | |||
1 | #include "evsel.h" | 1 | #include "evsel.h" |
2 | #include "evlist.h" | ||
2 | #include "../perf.h" | 3 | #include "../perf.h" |
3 | #include "util.h" | 4 | #include "util.h" |
4 | #include "cpumap.h" | 5 | #include "cpumap.h" |
5 | #include "thread.h" | 6 | #include "thread.h" |
6 | 7 | ||
8 | #include <unistd.h> | ||
9 | #include <sys/mman.h> | ||
10 | |||
7 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 11 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
8 | 12 | ||
9 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 13 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
@@ -49,10 +53,32 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
49 | } | 53 | } |
50 | } | 54 | } |
51 | 55 | ||
56 | void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
57 | { | ||
58 | struct perf_mmap *mm; | ||
59 | int cpu, thread; | ||
60 | |||
61 | for (cpu = 0; cpu < ncpus; cpu++) | ||
62 | for (thread = 0; thread < nthreads; ++thread) { | ||
63 | mm = xyarray__entry(evsel->mmap, cpu, thread); | ||
64 | if (mm->base != NULL) { | ||
65 | munmap(mm->base, evsel->mmap_len); | ||
66 | mm->base = NULL; | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
72 | { | ||
73 | evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap)); | ||
74 | return evsel->mmap != NULL ? 0 : -ENOMEM; | ||
75 | } | ||
76 | |||
52 | void perf_evsel__delete(struct perf_evsel *evsel) | 77 | void perf_evsel__delete(struct perf_evsel *evsel) |
53 | { | 78 | { |
54 | assert(list_empty(&evsel->node)); | 79 | assert(list_empty(&evsel->node)); |
55 | xyarray__delete(evsel->fd); | 80 | xyarray__delete(evsel->fd); |
81 | xyarray__delete(evsel->mmap); | ||
56 | free(evsel); | 82 | free(evsel); |
57 | } | 83 | } |
58 | 84 | ||
@@ -208,3 +234,48 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, | |||
208 | { | 234 | { |
209 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); | 235 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); |
210 | } | 236 | } |
237 | |||
238 | int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, | ||
239 | struct thread_map *threads, int pages, | ||
240 | struct perf_evlist *evlist) | ||
241 | { | ||
242 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | ||
243 | int mask = pages * page_size - 1, cpu; | ||
244 | struct perf_mmap *mm; | ||
245 | int thread; | ||
246 | |||
247 | if (evsel->mmap == NULL && | ||
248 | perf_evsel__alloc_mmap(evsel, cpus->nr, threads->nr) < 0) | ||
249 | return -ENOMEM; | ||
250 | |||
251 | evsel->mmap_len = (pages + 1) * page_size; | ||
252 | |||
253 | for (cpu = 0; cpu < cpus->nr; cpu++) { | ||
254 | for (thread = 0; thread < threads->nr; thread++) { | ||
255 | mm = xyarray__entry(evsel->mmap, cpu, thread); | ||
256 | mm->prev = 0; | ||
257 | mm->mask = mask; | ||
258 | mm->base = mmap(NULL, evsel->mmap_len, PROT_READ, | ||
259 | MAP_SHARED, FD(evsel, cpu, thread), 0); | ||
260 | if (mm->base == MAP_FAILED) | ||
261 | goto out_unmap; | ||
262 | |||
263 | if (evlist != NULL) | ||
264 | perf_evlist__add_pollfd(evlist, FD(evsel, cpu, thread)); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | out_unmap: | ||
271 | do { | ||
272 | while (--thread >= 0) { | ||
273 | mm = xyarray__entry(evsel->mmap, cpu, thread); | ||
274 | munmap(mm->base, evsel->mmap_len); | ||
275 | mm->base = NULL; | ||
276 | } | ||
277 | thread = threads->nr; | ||
278 | } while (--cpu >= 0); | ||
279 | |||
280 | return -1; | ||
281 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1594696bd12..c8fbef29943 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -29,19 +29,23 @@ struct perf_evsel { | |||
29 | struct perf_event_attr attr; | 29 | struct perf_event_attr attr; |
30 | char *filter; | 30 | char *filter; |
31 | struct xyarray *fd; | 31 | struct xyarray *fd; |
32 | struct xyarray *mmap; | ||
32 | struct perf_counts *counts; | 33 | struct perf_counts *counts; |
34 | size_t mmap_len; | ||
33 | int idx; | 35 | int idx; |
34 | void *priv; | 36 | void *priv; |
35 | }; | 37 | }; |
36 | 38 | ||
37 | struct cpu_map; | 39 | struct cpu_map; |
38 | struct thread_map; | 40 | struct thread_map; |
41 | struct perf_evlist; | ||
39 | 42 | ||
40 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); | 43 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); |
41 | void perf_evsel__delete(struct perf_evsel *evsel); | 44 | void perf_evsel__delete(struct perf_evsel *evsel); |
42 | 45 | ||
43 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 46 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
44 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 47 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
48 | int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
45 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 49 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
46 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 50 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
47 | 51 | ||
@@ -51,6 +55,10 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, | |||
51 | struct thread_map *threads, bool group, bool inherit); | 55 | struct thread_map *threads, bool group, bool inherit); |
52 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 56 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
53 | struct thread_map *threads, bool group, bool inherit); | 57 | struct thread_map *threads, bool group, bool inherit); |
58 | int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, | ||
59 | struct thread_map *threads, int pages, | ||
60 | struct perf_evlist *evlist); | ||
61 | void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
54 | 62 | ||
55 | #define perf_evsel__match(evsel, t, c) \ | 63 | #define perf_evsel__match(evsel, t, c) \ |
56 | (evsel->attr.type == PERF_TYPE_##t && \ | 64 | (evsel->attr.type == PERF_TYPE_##t && \ |