diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-09-03 17:02:59 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-09-25 15:46:55 -0400 |
commit | 1b85337d0685d1dc5a6f9061434ba4316d69f3b8 (patch) | |
tree | 2aae4189996ae07c65c8aaa2fc205ceba58cc7fb | |
parent | f66a889dbc96dd342c87232d74f0956076707746 (diff) |
tools lib api: Adopt fdarray class from perf's evlist
The extensible file description array that grew in the perf_evlist class
can be useful for other tools, as it is not something that only evlists
need, so move it to tools/lib/api/fd to ease sharing it.
v2: Don't use {} like in:
libapi_dirs:
$(QUIET_MKDIR)mkdir -p $(OUTPUT){fs,fd}/
in Makefiles, as it will not work in some systems, as in ubuntu13.10.
v3: Add fd/*.[ch] to LIBAPIKFS_SOURCES (Fix from Jiri Olsa)
v4: Leave the fcntl(fd, O_NONBLOCK) in the evlist layer, remains to
be checked if it is really needed there, but has no place in the
fdarray class (Fix from Jiri Olsa)
v5: Remove evlist details from fdarray grow/filter tests. Improve it a
bit doing more tests about expected internal state.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jean Pihet <jean.pihet@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/n/tip-kleuni3hckbc3s0lu6yb9x40@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/lib/api/Makefile | 7 | ||||
-rw-r--r-- | tools/lib/api/fd/array.c | 107 | ||||
-rw-r--r-- | tools/lib/api/fd/array.h | 32 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 4 | ||||
-rw-r--r-- | tools/perf/builtin-kvm.c | 4 | ||||
-rw-r--r-- | tools/perf/tests/builtin-test.c | 8 | ||||
-rw-r--r-- | tools/perf/tests/evlist.c | 214 | ||||
-rw-r--r-- | tools/perf/tests/fdarray.c | 174 | ||||
-rw-r--r-- | tools/perf/tests/tests.h | 4 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 57 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/python.c | 4 |
12 files changed, 342 insertions, 278 deletions
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index ce00f7ee6455..36c08b1f4afb 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile | |||
@@ -10,9 +10,14 @@ LIB_OBJS= | |||
10 | 10 | ||
11 | LIB_H += fs/debugfs.h | 11 | LIB_H += fs/debugfs.h |
12 | LIB_H += fs/fs.h | 12 | LIB_H += fs/fs.h |
13 | # See comment below about piggybacking... | ||
14 | LIB_H += fd/array.h | ||
13 | 15 | ||
14 | LIB_OBJS += $(OUTPUT)fs/debugfs.o | 16 | LIB_OBJS += $(OUTPUT)fs/debugfs.o |
15 | LIB_OBJS += $(OUTPUT)fs/fs.o | 17 | LIB_OBJS += $(OUTPUT)fs/fs.o |
18 | # XXX piggybacking here, need to introduce libapikfd, or rename this | ||
19 | # to plain libapik.a and make it have it all api goodies | ||
20 | LIB_OBJS += $(OUTPUT)fd/array.o | ||
16 | 21 | ||
17 | LIBFILE = libapikfs.a | 22 | LIBFILE = libapikfs.a |
18 | 23 | ||
@@ -29,7 +34,7 @@ $(LIBFILE): $(LIB_OBJS) | |||
29 | $(LIB_OBJS): $(LIB_H) | 34 | $(LIB_OBJS): $(LIB_H) |
30 | 35 | ||
31 | libapi_dirs: | 36 | libapi_dirs: |
32 | $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/ | 37 | $(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs |
33 | 38 | ||
34 | $(OUTPUT)%.o: %.c libapi_dirs | 39 | $(OUTPUT)%.o: %.c libapi_dirs |
35 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | 40 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< |
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c new file mode 100644 index 000000000000..4889c7d42961 --- /dev/null +++ b/tools/lib/api/fd/array.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
3 | * | ||
4 | * Released under the GPL v2. (and only v2, not any later version) | ||
5 | */ | ||
6 | #include "array.h" | ||
7 | #include <errno.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <poll.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <unistd.h> | ||
12 | |||
13 | void fdarray__init(struct fdarray *fda, int nr_autogrow) | ||
14 | { | ||
15 | fda->entries = NULL; | ||
16 | fda->nr = fda->nr_alloc = 0; | ||
17 | fda->nr_autogrow = nr_autogrow; | ||
18 | } | ||
19 | |||
20 | int fdarray__grow(struct fdarray *fda, int nr) | ||
21 | { | ||
22 | int nr_alloc = fda->nr_alloc + nr; | ||
23 | size_t size = sizeof(struct pollfd) * nr_alloc; | ||
24 | struct pollfd *entries = realloc(fda->entries, size); | ||
25 | |||
26 | if (entries == NULL) | ||
27 | return -ENOMEM; | ||
28 | |||
29 | fda->nr_alloc = nr_alloc; | ||
30 | fda->entries = entries; | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow) | ||
35 | { | ||
36 | struct fdarray *fda = calloc(1, sizeof(*fda)); | ||
37 | |||
38 | if (fda != NULL) { | ||
39 | if (fdarray__grow(fda, nr_alloc)) { | ||
40 | free(fda); | ||
41 | fda = NULL; | ||
42 | } else { | ||
43 | fda->nr_autogrow = nr_autogrow; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | return fda; | ||
48 | } | ||
49 | |||
50 | void fdarray__exit(struct fdarray *fda) | ||
51 | { | ||
52 | free(fda->entries); | ||
53 | fdarray__init(fda, 0); | ||
54 | } | ||
55 | |||
56 | void fdarray__delete(struct fdarray *fda) | ||
57 | { | ||
58 | fdarray__exit(fda); | ||
59 | free(fda); | ||
60 | } | ||
61 | |||
62 | int fdarray__add(struct fdarray *fda, int fd, short revents) | ||
63 | { | ||
64 | if (fda->nr == fda->nr_alloc && | ||
65 | fdarray__grow(fda, fda->nr_autogrow) < 0) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | fda->entries[fda->nr].fd = fd; | ||
69 | fda->entries[fda->nr].events = revents; | ||
70 | fda->nr++; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | int fdarray__filter(struct fdarray *fda, short revents) | ||
75 | { | ||
76 | int fd, nr = 0; | ||
77 | |||
78 | if (fda->nr == 0) | ||
79 | return 0; | ||
80 | |||
81 | for (fd = 0; fd < fda->nr; ++fd) { | ||
82 | if (fda->entries[fd].revents & revents) | ||
83 | continue; | ||
84 | |||
85 | if (fd != nr) | ||
86 | fda->entries[nr] = fda->entries[fd]; | ||
87 | |||
88 | ++nr; | ||
89 | } | ||
90 | |||
91 | return fda->nr = nr; | ||
92 | } | ||
93 | |||
94 | int fdarray__poll(struct fdarray *fda, int timeout) | ||
95 | { | ||
96 | return poll(fda->entries, fda->nr, timeout); | ||
97 | } | ||
98 | |||
99 | int fdarray__fprintf(struct fdarray *fda, FILE *fp) | ||
100 | { | ||
101 | int fd, printed = fprintf(fp, "%d [ ", fda->nr); | ||
102 | |||
103 | for (fd = 0; fd < fda->nr; ++fd) | ||
104 | printed += fprintf(fp, "%s%d", fd ? ", " : "", fda->entries[fd].fd); | ||
105 | |||
106 | return printed + fprintf(fp, " ]"); | ||
107 | } | ||
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h new file mode 100644 index 000000000000..de38361ba69e --- /dev/null +++ b/tools/lib/api/fd/array.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef __API_FD_ARRAY__ | ||
2 | #define __API_FD_ARRAY__ | ||
3 | |||
4 | #include <stdio.h> | ||
5 | |||
6 | struct pollfd; | ||
7 | |||
8 | struct fdarray { | ||
9 | int nr; | ||
10 | int nr_alloc; | ||
11 | int nr_autogrow; | ||
12 | struct pollfd *entries; | ||
13 | }; | ||
14 | |||
15 | void fdarray__init(struct fdarray *fda, int nr_autogrow); | ||
16 | void fdarray__exit(struct fdarray *fda); | ||
17 | |||
18 | struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow); | ||
19 | void fdarray__delete(struct fdarray *fda); | ||
20 | |||
21 | int fdarray__add(struct fdarray *fda, int fd, short revents); | ||
22 | int fdarray__poll(struct fdarray *fda, int timeout); | ||
23 | int fdarray__filter(struct fdarray *fda, short revents); | ||
24 | int fdarray__grow(struct fdarray *fda, int extra); | ||
25 | int fdarray__fprintf(struct fdarray *fda, FILE *fp); | ||
26 | |||
27 | static inline int fdarray__available_entries(struct fdarray *fda) | ||
28 | { | ||
29 | return fda->nr_alloc - fda->nr; | ||
30 | } | ||
31 | |||
32 | #endif /* __API_FD_ARRAY__ */ | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index f287c2522cf5..262916f4a377 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -400,9 +400,9 @@ LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o | |||
400 | LIB_OBJS += $(OUTPUT)tests/mmap-basic.o | 400 | LIB_OBJS += $(OUTPUT)tests/mmap-basic.o |
401 | LIB_OBJS += $(OUTPUT)tests/perf-record.o | 401 | LIB_OBJS += $(OUTPUT)tests/perf-record.o |
402 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o | 402 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o |
403 | LIB_OBJS += $(OUTPUT)tests/evlist.o | ||
404 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 403 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
405 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 404 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
405 | LIB_OBJS += $(OUTPUT)tests/fdarray.o | ||
406 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 406 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
407 | LIB_OBJS += $(OUTPUT)tests/hists_common.o | 407 | LIB_OBJS += $(OUTPUT)tests/hists_common.o |
408 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | 408 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
@@ -770,7 +770,7 @@ $(LIBTRACEEVENT)-clean: | |||
770 | install-traceevent-plugins: $(LIBTRACEEVENT) | 770 | install-traceevent-plugins: $(LIBTRACEEVENT) |
771 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | 771 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins |
772 | 772 | ||
773 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch]) | 773 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch]) |
774 | 774 | ||
775 | # if subdir is set, we've been called from above so target has been built | 775 | # if subdir is set, we've been called from above so target has been built |
776 | # already | 776 | # already |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index a440219b0be0..1e639d6265cc 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -920,7 +920,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
920 | signal(SIGTERM, sig_handler); | 920 | signal(SIGTERM, sig_handler); |
921 | 921 | ||
922 | /* use pollfds -- need to add timerfd and stdin */ | 922 | /* use pollfds -- need to add timerfd and stdin */ |
923 | nr_fds = kvm->evlist->nr_fds; | 923 | nr_fds = kvm->evlist->pollfd.nr; |
924 | 924 | ||
925 | /* add timer fd */ | 925 | /* add timer fd */ |
926 | if (perf_kvm__timerfd_create(kvm) < 0) { | 926 | if (perf_kvm__timerfd_create(kvm) < 0) { |
@@ -941,7 +941,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
941 | if (fd_set_nonblock(fileno(stdin)) != 0) | 941 | if (fd_set_nonblock(fileno(stdin)) != 0) |
942 | goto out; | 942 | goto out; |
943 | 943 | ||
944 | pollfds = kvm->evlist->pollfd; | 944 | pollfds = kvm->evlist->pollfd.entries; |
945 | 945 | ||
946 | /* everything is good - enable the events and process */ | 946 | /* everything is good - enable the events and process */ |
947 | perf_evlist__enable(kvm->evlist); | 947 | perf_evlist__enable(kvm->evlist); |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 174c3ffc5713..ac655b0700e7 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -158,12 +158,12 @@ static struct test { | |||
158 | .func = test__switch_tracking, | 158 | .func = test__switch_tracking, |
159 | }, | 159 | }, |
160 | { | 160 | { |
161 | .desc = "Filter fds with revents mask in a pollfd array", | 161 | .desc = "Filter fds with revents mask in a fdarray", |
162 | .func = test__perf_evlist__filter_pollfd, | 162 | .func = test__fdarray__filter, |
163 | }, | 163 | }, |
164 | { | 164 | { |
165 | .desc = "Add fd to pollfd array, making it autogrow", | 165 | .desc = "Add fd to a fdarray, making it autogrow", |
166 | .func = test__perf_evlist__add_pollfd, | 166 | .func = test__fdarray__add, |
167 | }, | 167 | }, |
168 | { | 168 | { |
169 | .func = NULL, | 169 | .func = NULL, |
diff --git a/tools/perf/tests/evlist.c b/tools/perf/tests/evlist.c deleted file mode 100644 index 99d7dfd4e20a..000000000000 --- a/tools/perf/tests/evlist.c +++ /dev/null | |||
@@ -1,214 +0,0 @@ | |||
1 | #include "util/evlist.h" | ||
2 | #include "util/debug.h" | ||
3 | #include "util/thread_map.h" | ||
4 | #include "util/cpumap.h" | ||
5 | #include "tests/tests.h" | ||
6 | |||
7 | static void perf_evlist__init_pollfd(struct perf_evlist *evlist, | ||
8 | int nr_fds_alloc, short revents) | ||
9 | { | ||
10 | int fd; | ||
11 | |||
12 | evlist->nr_fds = nr_fds_alloc; | ||
13 | |||
14 | for (fd = 0; fd < nr_fds_alloc; ++fd) { | ||
15 | evlist->pollfd[fd].fd = nr_fds_alloc - fd; | ||
16 | evlist->pollfd[fd].revents = revents; | ||
17 | } | ||
18 | } | ||
19 | |||
20 | static int perf_evlist__fprintf_pollfd(struct perf_evlist *evlist, | ||
21 | const char *prefix, FILE *fp) | ||
22 | { | ||
23 | int printed = 0, fd; | ||
24 | |||
25 | if (!verbose) | ||
26 | return 0; | ||
27 | |||
28 | printed += fprintf(fp, "\n%s: %3d [ ", prefix, evlist->nr_fds); | ||
29 | for (fd = 0; fd < evlist->nr_fds; ++fd) | ||
30 | printed += fprintf(fp, "%s%d", fd ? ", " : "", evlist->pollfd[fd].fd); | ||
31 | printed += fprintf(fp, " ]"); | ||
32 | return printed; | ||
33 | } | ||
34 | |||
35 | int test__perf_evlist__filter_pollfd(void) | ||
36 | { | ||
37 | const int nr_fds_alloc = 5; | ||
38 | int nr_fds, expected_fd[2], fd; | ||
39 | struct pollfd pollfd[nr_fds_alloc]; | ||
40 | struct perf_evlist evlist_alloc = { | ||
41 | .pollfd = pollfd, | ||
42 | }, *evlist = &evlist_alloc; | ||
43 | |||
44 | perf_evlist__init_pollfd(evlist, nr_fds_alloc, POLLIN); | ||
45 | nr_fds = perf_evlist__filter_pollfd(evlist, POLLHUP); | ||
46 | if (nr_fds != nr_fds_alloc) { | ||
47 | pr_debug("\nperf_evlist__filter_pollfd()=%d != %d shouldn't have filtered anything", | ||
48 | nr_fds, nr_fds_alloc); | ||
49 | return TEST_FAIL; | ||
50 | } | ||
51 | |||
52 | perf_evlist__init_pollfd(evlist, nr_fds_alloc, POLLHUP); | ||
53 | nr_fds = perf_evlist__filter_pollfd(evlist, POLLHUP); | ||
54 | if (nr_fds != 0) { | ||
55 | pr_debug("\nperf_evlist__filter_pollfd()=%d != %d, should have filtered all fds", | ||
56 | nr_fds, nr_fds_alloc); | ||
57 | return TEST_FAIL; | ||
58 | } | ||
59 | |||
60 | perf_evlist__init_pollfd(evlist, nr_fds_alloc, POLLHUP); | ||
61 | pollfd[2].revents = POLLIN; | ||
62 | expected_fd[0] = pollfd[2].fd; | ||
63 | |||
64 | pr_debug("\nfiltering all but pollfd[2]:"); | ||
65 | perf_evlist__fprintf_pollfd(evlist, "before", stderr); | ||
66 | nr_fds = perf_evlist__filter_pollfd(evlist, POLLHUP); | ||
67 | perf_evlist__fprintf_pollfd(evlist, " after", stderr); | ||
68 | if (nr_fds != 1) { | ||
69 | pr_debug("\nperf_evlist__filter_pollfd()=%d != 1, should have left just one event", | ||
70 | nr_fds); | ||
71 | return TEST_FAIL; | ||
72 | } | ||
73 | |||
74 | if (pollfd[0].fd != expected_fd[0]) { | ||
75 | pr_debug("\npollfd[0].fd=%d != %d\n", pollfd[0].fd, expected_fd[0]); | ||
76 | return TEST_FAIL; | ||
77 | } | ||
78 | |||
79 | perf_evlist__init_pollfd(evlist, nr_fds_alloc, POLLHUP); | ||
80 | pollfd[0].revents = POLLIN; | ||
81 | expected_fd[0] = pollfd[0].fd; | ||
82 | pollfd[3].revents = POLLIN; | ||
83 | expected_fd[1] = pollfd[3].fd; | ||
84 | |||
85 | pr_debug("\nfiltering all but (pollfd[0], pollfd[3]):"); | ||
86 | perf_evlist__fprintf_pollfd(evlist, "before", stderr); | ||
87 | nr_fds = perf_evlist__filter_pollfd(evlist, POLLHUP); | ||
88 | perf_evlist__fprintf_pollfd(evlist, " after", stderr); | ||
89 | if (nr_fds != 2) { | ||
90 | pr_debug("\nperf_evlist__filter_pollfd()=%d != 2, should have left just two events", | ||
91 | nr_fds); | ||
92 | return TEST_FAIL; | ||
93 | } | ||
94 | |||
95 | for (fd = 0; fd < 2; ++fd) { | ||
96 | if (pollfd[fd].fd != expected_fd[fd]) { | ||
97 | pr_debug("\npollfd[%d].fd=%d != %d\n", fd, pollfd[fd].fd, expected_fd[fd]); | ||
98 | return TEST_FAIL; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | pr_debug("\n"); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int test__perf_evlist__add_pollfd(void) | ||
108 | { | ||
109 | struct perf_evsel evsel = { | ||
110 | .system_wide = false, | ||
111 | }; | ||
112 | struct thread_map threads = { | ||
113 | .nr = 2, | ||
114 | }; | ||
115 | struct perf_evlist evlist_alloc = { | ||
116 | .pollfd = NULL, | ||
117 | .threads = &threads, | ||
118 | }, *evlist = &evlist_alloc; | ||
119 | |||
120 | INIT_LIST_HEAD(&evlist->entries); | ||
121 | list_add(&evsel.node, &evlist->entries); | ||
122 | |||
123 | if (perf_evlist__alloc_pollfd(evlist) < 0) { | ||
124 | pr_debug("\nperf_evlist__alloc_pollfd(evlist) failed!"); | ||
125 | return TEST_FAIL; | ||
126 | } | ||
127 | |||
128 | if (evlist->nr_fds_alloc != threads.nr) { | ||
129 | pr_debug("\n_evlist__alloc_pollfd: nr_fds_alloc=%d != (threads->nr(%d) * cpu_map->nr(%d))=%d", | ||
130 | evlist->nr_fds_alloc, thread_map__nr(evlist->threads), cpu_map__nr(evlist->cpus), | ||
131 | thread_map__nr(evlist->threads) * cpu_map__nr(evlist->cpus)); | ||
132 | return TEST_FAIL; | ||
133 | } | ||
134 | |||
135 | if (perf_evlist__add_pollfd(evlist, 1) < 0) { | ||
136 | pr_debug("\nperf_evlist__add_pollfd(evlist, 1) failed!"); | ||
137 | return TEST_FAIL; | ||
138 | } | ||
139 | |||
140 | if (evlist->nr_fds != 1) { | ||
141 | pr_debug("\nperf_evlist__add_pollfd(evlist, 1)=%d != 1", evlist->nr_fds); | ||
142 | return TEST_FAIL; | ||
143 | } | ||
144 | |||
145 | if (perf_evlist__add_pollfd(evlist, 2) < 0) { | ||
146 | pr_debug("\nperf_evlist__add_pollfd(evlist, 2) failed!"); | ||
147 | return TEST_FAIL; | ||
148 | } | ||
149 | |||
150 | if (evlist->nr_fds != 2) { | ||
151 | pr_debug("\nperf_evlist__add_pollfd(evlist, 2)=%d != 2", evlist->nr_fds); | ||
152 | return TEST_FAIL; | ||
153 | } | ||
154 | |||
155 | perf_evlist__fprintf_pollfd(evlist, "before growing array", stderr); | ||
156 | |||
157 | if (perf_evlist__add_pollfd(evlist, 35) < 0) { | ||
158 | pr_debug("\nperf_evlist__add_pollfd(evlist, 35) failed!"); | ||
159 | return TEST_FAIL; | ||
160 | } | ||
161 | |||
162 | if (evlist->nr_fds != 3) { | ||
163 | pr_debug("\nperf_evlist__add_pollfd(evlist, 35)=%d != 3", evlist->nr_fds); | ||
164 | return TEST_FAIL; | ||
165 | } | ||
166 | |||
167 | if (evlist->pollfd == NULL) { | ||
168 | pr_debug("\nperf_evlist__add_pollfd(evlist, 35) should have allocated evlist->pollfd!"); | ||
169 | return TEST_FAIL; | ||
170 | } | ||
171 | |||
172 | perf_evlist__fprintf_pollfd(evlist, "after 3rd add_pollfd", stderr); | ||
173 | |||
174 | if (evlist->pollfd[2].fd != 35) { | ||
175 | pr_debug("\nevlist->pollfd[2](%d) != 35!", evlist->pollfd[2].fd); | ||
176 | return TEST_FAIL; | ||
177 | } | ||
178 | |||
179 | if (perf_evlist__add_pollfd(evlist, 88) < 0) { | ||
180 | pr_debug("\nperf_evlist__add_pollfd(evlist, 88) failed!"); | ||
181 | return TEST_FAIL; | ||
182 | } | ||
183 | |||
184 | if (evlist->nr_fds != 4) { | ||
185 | pr_debug("\nperf_evlist__add_pollfd(evlist, 88)=%d != 2", evlist->nr_fds); | ||
186 | return TEST_FAIL; | ||
187 | } | ||
188 | |||
189 | perf_evlist__fprintf_pollfd(evlist, "after 4th add_pollfd", stderr); | ||
190 | |||
191 | if (evlist->pollfd[0].fd != 1) { | ||
192 | pr_debug("\nevlist->pollfd[0](%d) != 1!", evlist->pollfd[0].fd); | ||
193 | return TEST_FAIL; | ||
194 | } | ||
195 | |||
196 | if (evlist->pollfd[1].fd != 2) { | ||
197 | pr_debug("\nevlist->pollfd[1](%d) != 2!", evlist->pollfd[1].fd); | ||
198 | return TEST_FAIL; | ||
199 | } | ||
200 | |||
201 | if (evlist->pollfd[2].fd != 35) { | ||
202 | pr_debug("\nevlist->pollfd[2](%d) != 35!", evlist->pollfd[2].fd); | ||
203 | return TEST_FAIL; | ||
204 | } | ||
205 | |||
206 | if (evlist->pollfd[3].fd != 88) { | ||
207 | pr_debug("\nevlist->pollfd[3](%d) != 88!", evlist->pollfd[3].fd); | ||
208 | return TEST_FAIL; | ||
209 | } | ||
210 | |||
211 | pr_debug("\n"); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c new file mode 100644 index 000000000000..a0fea62ec368 --- /dev/null +++ b/tools/perf/tests/fdarray.c | |||
@@ -0,0 +1,174 @@ | |||
1 | #include <api/fd/array.h> | ||
2 | #include "util/debug.h" | ||
3 | #include "tests/tests.h" | ||
4 | |||
5 | static void fdarray__init_revents(struct fdarray *fda, short revents) | ||
6 | { | ||
7 | int fd; | ||
8 | |||
9 | fda->nr = fda->nr_alloc; | ||
10 | |||
11 | for (fd = 0; fd < fda->nr; ++fd) { | ||
12 | fda->entries[fd].fd = fda->nr - fd; | ||
13 | fda->entries[fd].revents = revents; | ||
14 | } | ||
15 | } | ||
16 | |||
17 | static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp) | ||
18 | { | ||
19 | int printed = 0; | ||
20 | |||
21 | if (!verbose) | ||
22 | return 0; | ||
23 | |||
24 | printed += fprintf(fp, "\n%s: ", prefix); | ||
25 | return printed + fdarray__fprintf(fda, fp); | ||
26 | } | ||
27 | |||
28 | int test__fdarray__filter(void) | ||
29 | { | ||
30 | int nr_fds, expected_fd[2], fd, err = TEST_FAIL; | ||
31 | struct fdarray *fda = fdarray__new(5, 5); | ||
32 | |||
33 | if (fda == NULL) { | ||
34 | pr_debug("\nfdarray__new() failed!"); | ||
35 | goto out; | ||
36 | } | ||
37 | |||
38 | fdarray__init_revents(fda, POLLIN); | ||
39 | nr_fds = fdarray__filter(fda, POLLHUP); | ||
40 | if (nr_fds != fda->nr_alloc) { | ||
41 | pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything", | ||
42 | nr_fds, fda->nr_alloc); | ||
43 | goto out_delete; | ||
44 | } | ||
45 | |||
46 | fdarray__init_revents(fda, POLLHUP); | ||
47 | nr_fds = fdarray__filter(fda, POLLHUP); | ||
48 | if (nr_fds != 0) { | ||
49 | pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds", | ||
50 | nr_fds, fda->nr_alloc); | ||
51 | goto out_delete; | ||
52 | } | ||
53 | |||
54 | fdarray__init_revents(fda, POLLHUP); | ||
55 | fda->entries[2].revents = POLLIN; | ||
56 | expected_fd[0] = fda->entries[2].fd; | ||
57 | |||
58 | pr_debug("\nfiltering all but fda->entries[2]:"); | ||
59 | fdarray__fprintf_prefix(fda, "before", stderr); | ||
60 | nr_fds = fdarray__filter(fda, POLLHUP); | ||
61 | fdarray__fprintf_prefix(fda, " after", stderr); | ||
62 | if (nr_fds != 1) { | ||
63 | pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds); | ||
64 | goto out_delete; | ||
65 | } | ||
66 | |||
67 | if (fda->entries[0].fd != expected_fd[0]) { | ||
68 | pr_debug("\nfda->entries[0].fd=%d != %d\n", | ||
69 | fda->entries[0].fd, expected_fd[0]); | ||
70 | goto out_delete; | ||
71 | } | ||
72 | |||
73 | fdarray__init_revents(fda, POLLHUP); | ||
74 | fda->entries[0].revents = POLLIN; | ||
75 | expected_fd[0] = fda->entries[0].fd; | ||
76 | fda->entries[3].revents = POLLIN; | ||
77 | expected_fd[1] = fda->entries[3].fd; | ||
78 | |||
79 | pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):"); | ||
80 | fdarray__fprintf_prefix(fda, "before", stderr); | ||
81 | nr_fds = fdarray__filter(fda, POLLHUP); | ||
82 | fdarray__fprintf_prefix(fda, " after", stderr); | ||
83 | if (nr_fds != 2) { | ||
84 | pr_debug("\nfdarray__filter()=%d != 2, should have left just two events", | ||
85 | nr_fds); | ||
86 | goto out_delete; | ||
87 | } | ||
88 | |||
89 | for (fd = 0; fd < 2; ++fd) { | ||
90 | if (fda->entries[fd].fd != expected_fd[fd]) { | ||
91 | pr_debug("\nfda->entries[%d].fd=%d != %d\n", fd, | ||
92 | fda->entries[fd].fd, expected_fd[fd]); | ||
93 | goto out_delete; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | pr_debug("\n"); | ||
98 | |||
99 | err = 0; | ||
100 | out_delete: | ||
101 | fdarray__delete(fda); | ||
102 | out: | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | int test__fdarray__add(void) | ||
107 | { | ||
108 | int err = TEST_FAIL; | ||
109 | struct fdarray *fda = fdarray__new(2, 2); | ||
110 | |||
111 | if (fda == NULL) { | ||
112 | pr_debug("\nfdarray__new() failed!"); | ||
113 | goto out; | ||
114 | } | ||
115 | |||
116 | #define FDA_CHECK(_idx, _fd, _revents) \ | ||
117 | if (fda->entries[_idx].fd != _fd) { \ | ||
118 | pr_debug("\n%d: fda->entries[%d](%d) != %d!", \ | ||
119 | __LINE__, _idx, fda->entries[1].fd, _fd); \ | ||
120 | goto out_delete; \ | ||
121 | } \ | ||
122 | if (fda->entries[_idx].events != (_revents)) { \ | ||
123 | pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!", \ | ||
124 | __LINE__, _idx, fda->entries[_idx].fd, _revents); \ | ||
125 | goto out_delete; \ | ||
126 | } | ||
127 | |||
128 | #define FDA_ADD(_idx, _fd, _revents, _nr) \ | ||
129 | if (fdarray__add(fda, _fd, _revents) < 0) { \ | ||
130 | pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!", \ | ||
131 | __LINE__,_fd, _revents); \ | ||
132 | goto out_delete; \ | ||
133 | } \ | ||
134 | if (fda->nr != _nr) { \ | ||
135 | pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d", \ | ||
136 | __LINE__,_fd, _revents, fda->nr, _nr); \ | ||
137 | goto out_delete; \ | ||
138 | } \ | ||
139 | FDA_CHECK(_idx, _fd, _revents) | ||
140 | |||
141 | FDA_ADD(0, 1, POLLIN, 1); | ||
142 | FDA_ADD(1, 2, POLLERR, 2); | ||
143 | |||
144 | fdarray__fprintf_prefix(fda, "before growing array", stderr); | ||
145 | |||
146 | FDA_ADD(2, 35, POLLHUP, 3); | ||
147 | |||
148 | if (fda->entries == NULL) { | ||
149 | pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!"); | ||
150 | goto out_delete; | ||
151 | } | ||
152 | |||
153 | fdarray__fprintf_prefix(fda, "after 3rd add", stderr); | ||
154 | |||
155 | FDA_ADD(3, 88, POLLIN | POLLOUT, 4); | ||
156 | |||
157 | fdarray__fprintf_prefix(fda, "after 4th add", stderr); | ||
158 | |||
159 | FDA_CHECK(0, 1, POLLIN); | ||
160 | FDA_CHECK(1, 2, POLLERR); | ||
161 | FDA_CHECK(2, 35, POLLHUP); | ||
162 | FDA_CHECK(3, 88, POLLIN | POLLOUT); | ||
163 | |||
164 | #undef FDA_ADD | ||
165 | #undef FDA_CHECK | ||
166 | |||
167 | pr_debug("\n"); | ||
168 | |||
169 | err = 0; | ||
170 | out_delete: | ||
171 | fdarray__delete(fda); | ||
172 | out: | ||
173 | return err; | ||
174 | } | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 699d4bb61dc7..00e776a87a9c 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -49,8 +49,8 @@ int test__thread_mg_share(void); | |||
49 | int test__hists_output(void); | 49 | int test__hists_output(void); |
50 | int test__hists_cumulate(void); | 50 | int test__hists_cumulate(void); |
51 | int test__switch_tracking(void); | 51 | int test__switch_tracking(void); |
52 | int test__perf_evlist__filter_pollfd(void); | 52 | int test__fdarray__filter(void); |
53 | int test__perf_evlist__add_pollfd(void); | 53 | int test__fdarray__add(void); |
54 | 54 | ||
55 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) | 55 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) |
56 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 56 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5ff3c667542f..398dab1a08cc 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -37,6 +37,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
37 | INIT_HLIST_HEAD(&evlist->heads[i]); | 37 | INIT_HLIST_HEAD(&evlist->heads[i]); |
38 | INIT_LIST_HEAD(&evlist->entries); | 38 | INIT_LIST_HEAD(&evlist->entries); |
39 | perf_evlist__set_maps(evlist, cpus, threads); | 39 | perf_evlist__set_maps(evlist, cpus, threads); |
40 | fdarray__init(&evlist->pollfd, 64); | ||
40 | evlist->workload.pid = -1; | 41 | evlist->workload.pid = -1; |
41 | } | 42 | } |
42 | 43 | ||
@@ -102,7 +103,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
102 | void perf_evlist__exit(struct perf_evlist *evlist) | 103 | void perf_evlist__exit(struct perf_evlist *evlist) |
103 | { | 104 | { |
104 | zfree(&evlist->mmap); | 105 | zfree(&evlist->mmap); |
105 | zfree(&evlist->pollfd); | 106 | fdarray__exit(&evlist->pollfd); |
106 | } | 107 | } |
107 | 108 | ||
108 | void perf_evlist__delete(struct perf_evlist *evlist) | 109 | void perf_evlist__delete(struct perf_evlist *evlist) |
@@ -402,20 +403,6 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist, | |||
402 | return perf_evlist__enable_event_thread(evlist, evsel, idx); | 403 | return perf_evlist__enable_event_thread(evlist, evsel, idx); |
403 | } | 404 | } |
404 | 405 | ||
405 | static int perf_evlist__grow_pollfd(struct perf_evlist *evlist, int hint) | ||
406 | { | ||
407 | int nr_fds_alloc = evlist->nr_fds_alloc + hint; | ||
408 | size_t size = sizeof(struct pollfd) * nr_fds_alloc; | ||
409 | struct pollfd *pollfd = realloc(evlist->pollfd, size); | ||
410 | |||
411 | if (pollfd == NULL) | ||
412 | return -ENOMEM; | ||
413 | |||
414 | evlist->nr_fds_alloc = nr_fds_alloc; | ||
415 | evlist->pollfd = pollfd; | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 406 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
420 | { | 407 | { |
421 | int nr_cpus = cpu_map__nr(evlist->cpus); | 408 | int nr_cpus = cpu_map__nr(evlist->cpus); |
@@ -430,8 +417,8 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | |||
430 | nfds += nr_cpus * nr_threads; | 417 | nfds += nr_cpus * nr_threads; |
431 | } | 418 | } |
432 | 419 | ||
433 | if (evlist->nr_fds_alloc - evlist->nr_fds < nfds && | 420 | if (fdarray__available_entries(&evlist->pollfd) < nfds && |
434 | perf_evlist__grow_pollfd(evlist, nfds) < 0) | 421 | fdarray__grow(&evlist->pollfd, nfds) < 0) |
435 | return -ENOMEM; | 422 | return -ENOMEM; |
436 | 423 | ||
437 | return 0; | 424 | return 0; |
@@ -439,45 +426,19 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | |||
439 | 426 | ||
440 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | 427 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) |
441 | { | 428 | { |
442 | /* | ||
443 | * XXX: 64 is arbitrary, just not to call realloc at each fd. | ||
444 | * Find a better autogrowing heuristic | ||
445 | */ | ||
446 | if (evlist->nr_fds == evlist->nr_fds_alloc && | ||
447 | perf_evlist__grow_pollfd(evlist, 64) < 0) | ||
448 | return -ENOMEM; | ||
449 | |||
450 | fcntl(fd, F_SETFL, O_NONBLOCK); | 429 | fcntl(fd, F_SETFL, O_NONBLOCK); |
451 | evlist->pollfd[evlist->nr_fds].fd = fd; | 430 | |
452 | evlist->pollfd[evlist->nr_fds].events = POLLIN | POLLERR | POLLHUP; | 431 | return fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP); |
453 | evlist->nr_fds++; | ||
454 | return 0; | ||
455 | } | 432 | } |
456 | 433 | ||
457 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) | 434 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) |
458 | { | 435 | { |
459 | int fd, nr_fds = 0; | 436 | return fdarray__filter(&evlist->pollfd, revents_and_mask); |
460 | |||
461 | if (evlist->nr_fds == 0) | ||
462 | return 0; | ||
463 | |||
464 | for (fd = 0; fd < evlist->nr_fds; ++fd) { | ||
465 | if (evlist->pollfd[fd].revents & revents_and_mask) | ||
466 | continue; | ||
467 | |||
468 | if (fd != nr_fds) | ||
469 | evlist->pollfd[nr_fds] = evlist->pollfd[fd]; | ||
470 | |||
471 | ++nr_fds; | ||
472 | } | ||
473 | |||
474 | evlist->nr_fds = nr_fds; | ||
475 | return nr_fds; | ||
476 | } | 437 | } |
477 | 438 | ||
478 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout) | 439 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout) |
479 | { | 440 | { |
480 | return poll(evlist->pollfd, evlist->nr_fds, timeout); | 441 | return fdarray__poll(&evlist->pollfd, timeout); |
481 | } | 442 | } |
482 | 443 | ||
483 | static void perf_evlist__id_hash(struct perf_evlist *evlist, | 444 | static void perf_evlist__id_hash(struct perf_evlist *evlist, |
@@ -935,7 +896,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
935 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) | 896 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) |
936 | return -ENOMEM; | 897 | return -ENOMEM; |
937 | 898 | ||
938 | if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) | 899 | if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) |
939 | return -ENOMEM; | 900 | return -ENOMEM; |
940 | 901 | ||
941 | evlist->overwrite = overwrite; | 902 | evlist->overwrite = overwrite; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index d7e99b67c94f..fc013704d903 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __PERF_EVLIST_H 1 | 2 | #define __PERF_EVLIST_H 1 |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <api/fd/array.h> | ||
5 | #include <stdio.h> | 6 | #include <stdio.h> |
6 | #include "../perf.h" | 7 | #include "../perf.h" |
7 | #include "event.h" | 8 | #include "event.h" |
@@ -29,8 +30,6 @@ struct perf_evlist { | |||
29 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 30 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
30 | int nr_entries; | 31 | int nr_entries; |
31 | int nr_groups; | 32 | int nr_groups; |
32 | int nr_fds; | ||
33 | int nr_fds_alloc; | ||
34 | int nr_mmaps; | 33 | int nr_mmaps; |
35 | size_t mmap_len; | 34 | size_t mmap_len; |
36 | int id_pos; | 35 | int id_pos; |
@@ -41,8 +40,8 @@ struct perf_evlist { | |||
41 | pid_t pid; | 40 | pid_t pid; |
42 | } workload; | 41 | } workload; |
43 | bool overwrite; | 42 | bool overwrite; |
43 | struct fdarray pollfd; | ||
44 | struct perf_mmap *mmap; | 44 | struct perf_mmap *mmap; |
45 | struct pollfd *pollfd; | ||
46 | struct thread_map *threads; | 45 | struct thread_map *threads; |
47 | struct cpu_map *cpus; | 46 | struct cpu_map *cpus; |
48 | struct perf_evsel *selected; | 47 | struct perf_evsel *selected; |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 4472f8be8e35..3dda85ca50c1 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -753,9 +753,9 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, | |||
753 | PyObject *list = PyList_New(0); | 753 | PyObject *list = PyList_New(0); |
754 | int i; | 754 | int i; |
755 | 755 | ||
756 | for (i = 0; i < evlist->nr_fds; ++i) { | 756 | for (i = 0; i < evlist->pollfd.nr; ++i) { |
757 | PyObject *file; | 757 | PyObject *file; |
758 | FILE *fp = fdopen(evlist->pollfd[i].fd, "r"); | 758 | FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r"); |
759 | 759 | ||
760 | if (fp == NULL) | 760 | if (fp == NULL) |
761 | goto free_list; | 761 | goto free_list; |