1c43e99fdSEd Maste /*
2c43e99fdSEd Maste * Copyright 2003-2007 Niels Provos <provos@citi.umich.edu>
3c43e99fdSEd Maste * Copyright 2007-2012 Niels Provos and Nick Mathewson
4c43e99fdSEd Maste *
5c43e99fdSEd Maste * Redistribution and use in source and binary forms, with or without
6c43e99fdSEd Maste * modification, are permitted provided that the following conditions
7c43e99fdSEd Maste * are met:
8c43e99fdSEd Maste * 1. Redistributions of source code must retain the above copyright
9c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer.
10c43e99fdSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
11c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer in the
12c43e99fdSEd Maste * documentation and/or other materials provided with the distribution.
13c43e99fdSEd Maste * 4. The name of the author may not be used to endorse or promote products
14c43e99fdSEd Maste * derived from this software without specific prior written permission.
15c43e99fdSEd Maste *
16c43e99fdSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17c43e99fdSEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18c43e99fdSEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19c43e99fdSEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20c43e99fdSEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21c43e99fdSEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22c43e99fdSEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23c43e99fdSEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24c43e99fdSEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25c43e99fdSEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26c43e99fdSEd Maste *
27c43e99fdSEd Maste *
28c43e99fdSEd Maste * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
29c43e99fdSEd Maste *
30c43e99fdSEd Maste * Added chain event propagation to improve the sensitivity of
31c43e99fdSEd Maste * the measure respect to the event loop efficency.
32c43e99fdSEd Maste *
33c43e99fdSEd Maste *
34c43e99fdSEd Maste */
35c43e99fdSEd Maste
36c43e99fdSEd Maste #include "event2/event-config.h"
37*b50261e2SCy Schubert #include "../util-internal.h"
38c43e99fdSEd Maste
39c43e99fdSEd Maste #include <sys/types.h>
40c43e99fdSEd Maste #include <sys/stat.h>
41c43e99fdSEd Maste #ifdef EVENT__HAVE_SYS_TIME_H
42c43e99fdSEd Maste #include <sys/time.h>
43c43e99fdSEd Maste #endif
44c43e99fdSEd Maste #ifdef _WIN32
45c43e99fdSEd Maste #define WIN32_LEAN_AND_MEAN
46c43e99fdSEd Maste #include <windows.h>
47c43e99fdSEd Maste #else
48c43e99fdSEd Maste #include <sys/socket.h>
49c43e99fdSEd Maste #include <signal.h>
50c43e99fdSEd Maste #include <sys/resource.h>
51c43e99fdSEd Maste #endif
52c43e99fdSEd Maste #include <fcntl.h>
53c43e99fdSEd Maste #include <stdlib.h>
54c43e99fdSEd Maste #include <stdio.h>
55c43e99fdSEd Maste #include <string.h>
56c43e99fdSEd Maste #ifdef EVENT__HAVE_UNISTD_H
57c43e99fdSEd Maste #include <unistd.h>
58c43e99fdSEd Maste #endif
59c43e99fdSEd Maste #include <errno.h>
60c43e99fdSEd Maste
61c43e99fdSEd Maste #ifdef _WIN32
62c43e99fdSEd Maste #include <getopt.h>
63c43e99fdSEd Maste #endif
64c43e99fdSEd Maste
65c43e99fdSEd Maste #include <event.h>
66c43e99fdSEd Maste #include <evutil.h>
67c43e99fdSEd Maste
68*b50261e2SCy Schubert static ev_ssize_t count, fired;
69*b50261e2SCy Schubert static int writes, failures;
70c43e99fdSEd Maste static evutil_socket_t *pipes;
71c43e99fdSEd Maste static int num_pipes, num_active, num_writes;
72c43e99fdSEd Maste static struct event *events;
73*b50261e2SCy Schubert static struct event_base *base;
74c43e99fdSEd Maste
75c43e99fdSEd Maste
76c43e99fdSEd Maste static void
read_cb(evutil_socket_t fd,short which,void * arg)77c43e99fdSEd Maste read_cb(evutil_socket_t fd, short which, void *arg)
78c43e99fdSEd Maste {
79c43e99fdSEd Maste ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1;
80c43e99fdSEd Maste unsigned char ch;
81c43e99fdSEd Maste ev_ssize_t n;
82c43e99fdSEd Maste
83c43e99fdSEd Maste n = recv(fd, (char*)&ch, sizeof(ch), 0);
84c43e99fdSEd Maste if (n >= 0)
85c43e99fdSEd Maste count += n;
86c43e99fdSEd Maste else
87c43e99fdSEd Maste failures++;
88c43e99fdSEd Maste if (writes) {
89c43e99fdSEd Maste if (widx >= num_pipes)
90c43e99fdSEd Maste widx -= num_pipes;
91c43e99fdSEd Maste n = send(pipes[2 * widx + 1], "e", 1, 0);
92c43e99fdSEd Maste if (n != 1)
93c43e99fdSEd Maste failures++;
94c43e99fdSEd Maste writes--;
95c43e99fdSEd Maste fired++;
96c43e99fdSEd Maste }
97c43e99fdSEd Maste }
98c43e99fdSEd Maste
99c43e99fdSEd Maste static struct timeval *
run_once(void)100c43e99fdSEd Maste run_once(void)
101c43e99fdSEd Maste {
102c43e99fdSEd Maste evutil_socket_t *cp, space;
103c43e99fdSEd Maste long i;
104c43e99fdSEd Maste static struct timeval ts, te;
105c43e99fdSEd Maste
106c43e99fdSEd Maste for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
107c43e99fdSEd Maste if (event_initialized(&events[i]))
108c43e99fdSEd Maste event_del(&events[i]);
109*b50261e2SCy Schubert event_assign(&events[i], base, cp[0], EV_READ | EV_PERSIST, read_cb, (void *)(ev_intptr_t) i);
110c43e99fdSEd Maste event_add(&events[i], NULL);
111c43e99fdSEd Maste }
112c43e99fdSEd Maste
113*b50261e2SCy Schubert event_base_loop(base, EVLOOP_ONCE | EVLOOP_NONBLOCK);
114c43e99fdSEd Maste
115c43e99fdSEd Maste fired = 0;
116c43e99fdSEd Maste space = num_pipes / num_active;
117c43e99fdSEd Maste space = space * 2;
118c43e99fdSEd Maste for (i = 0; i < num_active; i++, fired++)
119c43e99fdSEd Maste (void) send(pipes[i * space + 1], "e", 1, 0);
120c43e99fdSEd Maste
121c43e99fdSEd Maste count = 0;
122c43e99fdSEd Maste writes = num_writes;
123*b50261e2SCy Schubert {
124*b50261e2SCy Schubert int xcount = 0;
125c43e99fdSEd Maste evutil_gettimeofday(&ts, NULL);
126c43e99fdSEd Maste do {
127*b50261e2SCy Schubert event_base_loop(base, EVLOOP_ONCE | EVLOOP_NONBLOCK);
128c43e99fdSEd Maste xcount++;
129c43e99fdSEd Maste } while (count != fired);
130c43e99fdSEd Maste evutil_gettimeofday(&te, NULL);
131c43e99fdSEd Maste
132*b50261e2SCy Schubert if (xcount != count)
133*b50261e2SCy Schubert fprintf(stderr, "Xcount: %d, Rcount: " EV_SSIZE_FMT "\n",
134*b50261e2SCy Schubert xcount, count);
135c43e99fdSEd Maste }
136c43e99fdSEd Maste
137c43e99fdSEd Maste evutil_timersub(&te, &ts, &te);
138c43e99fdSEd Maste
139c43e99fdSEd Maste return (&te);
140c43e99fdSEd Maste }
141c43e99fdSEd Maste
142c43e99fdSEd Maste int
main(int argc,char ** argv)143c43e99fdSEd Maste main(int argc, char **argv)
144c43e99fdSEd Maste {
145*b50261e2SCy Schubert #ifdef EVENT__HAVE_SETRLIMIT
146c43e99fdSEd Maste struct rlimit rl;
147c43e99fdSEd Maste #endif
148c43e99fdSEd Maste int i, c;
149c43e99fdSEd Maste struct timeval *tv;
150c43e99fdSEd Maste evutil_socket_t *cp;
151*b50261e2SCy Schubert const char **methods;
152*b50261e2SCy Schubert const char *method = NULL;
153*b50261e2SCy Schubert struct event_config *cfg = NULL;
154c43e99fdSEd Maste
155c43e99fdSEd Maste #ifdef _WIN32
156c43e99fdSEd Maste WSADATA WSAData;
157c43e99fdSEd Maste WSAStartup(0x101, &WSAData);
158c43e99fdSEd Maste #endif
159c43e99fdSEd Maste num_pipes = 100;
160c43e99fdSEd Maste num_active = 1;
161c43e99fdSEd Maste num_writes = num_pipes;
162*b50261e2SCy Schubert while ((c = getopt(argc, argv, "n:a:w:m:l")) != -1) {
163c43e99fdSEd Maste switch (c) {
164c43e99fdSEd Maste case 'n':
165c43e99fdSEd Maste num_pipes = atoi(optarg);
166c43e99fdSEd Maste break;
167c43e99fdSEd Maste case 'a':
168c43e99fdSEd Maste num_active = atoi(optarg);
169c43e99fdSEd Maste break;
170c43e99fdSEd Maste case 'w':
171c43e99fdSEd Maste num_writes = atoi(optarg);
172c43e99fdSEd Maste break;
173*b50261e2SCy Schubert case 'm':
174*b50261e2SCy Schubert method = optarg;
175*b50261e2SCy Schubert break;
176*b50261e2SCy Schubert case 'l':
177*b50261e2SCy Schubert methods = event_get_supported_methods();
178*b50261e2SCy Schubert fprintf(stdout, "Using Libevent %s. Available methods are:\n",
179*b50261e2SCy Schubert event_get_version());
180*b50261e2SCy Schubert for (i = 0; methods[i] != NULL; ++i)
181*b50261e2SCy Schubert printf(" %s\n", methods[i]);
182*b50261e2SCy Schubert exit(0);
183c43e99fdSEd Maste default:
184c43e99fdSEd Maste fprintf(stderr, "Illegal argument \"%c\"\n", c);
185c43e99fdSEd Maste exit(1);
186c43e99fdSEd Maste }
187c43e99fdSEd Maste }
188c43e99fdSEd Maste
189*b50261e2SCy Schubert #ifdef EVENT__HAVE_SETRLIMIT
190c43e99fdSEd Maste rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
191c43e99fdSEd Maste if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
192c43e99fdSEd Maste perror("setrlimit");
193c43e99fdSEd Maste exit(1);
194c43e99fdSEd Maste }
195c43e99fdSEd Maste #endif
196c43e99fdSEd Maste
197c43e99fdSEd Maste events = calloc(num_pipes, sizeof(struct event));
198c43e99fdSEd Maste pipes = calloc(num_pipes * 2, sizeof(evutil_socket_t));
199c43e99fdSEd Maste if (events == NULL || pipes == NULL) {
200c43e99fdSEd Maste perror("malloc");
201c43e99fdSEd Maste exit(1);
202c43e99fdSEd Maste }
203c43e99fdSEd Maste
204*b50261e2SCy Schubert if (method != NULL) {
205*b50261e2SCy Schubert cfg = event_config_new();
206*b50261e2SCy Schubert methods = event_get_supported_methods();
207*b50261e2SCy Schubert for (i = 0; methods[i] != NULL; ++i)
208*b50261e2SCy Schubert if (strcmp(methods[i], method))
209*b50261e2SCy Schubert event_config_avoid_method(cfg, methods[i]);
210*b50261e2SCy Schubert base = event_base_new_with_config(cfg);
211*b50261e2SCy Schubert event_config_free(cfg);
212*b50261e2SCy Schubert } else
213*b50261e2SCy Schubert base = event_base_new();
214c43e99fdSEd Maste
215c43e99fdSEd Maste for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
216c43e99fdSEd Maste #ifdef USE_PIPES
217c43e99fdSEd Maste if (pipe(cp) == -1) {
218c43e99fdSEd Maste #else
219c43e99fdSEd Maste if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
220c43e99fdSEd Maste #endif
221c43e99fdSEd Maste perror("pipe");
222c43e99fdSEd Maste exit(1);
223c43e99fdSEd Maste }
224c43e99fdSEd Maste }
225c43e99fdSEd Maste
226c43e99fdSEd Maste for (i = 0; i < 25; i++) {
227c43e99fdSEd Maste tv = run_once();
228c43e99fdSEd Maste if (tv == NULL)
229c43e99fdSEd Maste exit(1);
230c43e99fdSEd Maste fprintf(stdout, "%ld\n",
231c43e99fdSEd Maste tv->tv_sec * 1000000L + tv->tv_usec);
232c43e99fdSEd Maste }
233c43e99fdSEd Maste
234c43e99fdSEd Maste exit(0);
235c43e99fdSEd Maste }
236