aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-top.c71
-rw-r--r--tools/perf/perf.h14
-rw-r--r--tools/perf/util/evlist.c8
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c71
-rw-r--r--tools/perf/util/evsel.h8
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
1098struct mmap_data {
1099 void *base;
1100 int mask;
1101 unsigned int prev;
1102};
1103
1104static 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
1111static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1112{
1113 xyarray__delete(evsel->priv);
1114 evsel->priv = NULL;
1115}
1116
1117static 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
1128static void perf_session__mmap_read_counter(struct perf_session *self, 1098static 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
1213static 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
1238static void start_counters(struct perf_evlist *evlist) 1182static 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();
1487out_free_fd: 1428out_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
97struct perf_mmap {
98 void *base;
99 int mask;
100 unsigned int prev;
101};
102
103static 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
64void 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);
21int perf_evlist__add_default(struct perf_evlist *evlist); 21int perf_evlist__add_default(struct perf_evlist *evlist);
22 22
23int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); 23int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads);
24void 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
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 13struct 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
56void 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
71int 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
52void perf_evsel__delete(struct perf_evsel *evsel) 77void 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
238int 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
270out_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
37struct cpu_map; 39struct cpu_map;
38struct thread_map; 40struct thread_map;
41struct perf_evlist;
39 42
40struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 43struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
41void perf_evsel__delete(struct perf_evsel *evsel); 44void perf_evsel__delete(struct perf_evsel *evsel);
42 45
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 46int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 47int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
48int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads);
45void perf_evsel__free_fd(struct perf_evsel *evsel); 49void perf_evsel__free_fd(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 50void 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);
52int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 56int 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);
58int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus,
59 struct thread_map *threads, int pages,
60 struct perf_evlist *evlist);
61void 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 && \