1 /*
2  * Copyright 2012 William Pitcock <nenolod@dereferenced.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright 2003 Niels Provos <provos@citi.umich.edu>
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 4. The name of the author may not be used to endorse or promote products
45  *    derived from this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57  *
58  *
59  * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
60  *
61  *     Added chain event propagation to improve the sensitivity of
62  *     the measure respect to the event loop efficency.
63  *
64  *
65  */
66 
67 #define timersub(tvp, uvp, vvp)	\
68 	do \
69 	{ \
70 		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
71 		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
72 		if ((vvp)->tv_usec < 0)	\
73 		{ \
74 			(vvp)->tv_sec--; \
75 			(vvp)->tv_usec += 1000000; \
76 		} \
77 	} while (0)
78 
79 #include <mowgli.h>
80 
81 static int count, writes, fired;
82 static mowgli_eventloop_t *base_eventloop;
83 static mowgli_descriptor_t *pipes;
84 static int num_pipes, num_active, num_writes;
85 static mowgli_eventloop_pollable_t **events;
86 static int timers;
87 
88 void
timer_cb(void * unused)89 timer_cb(void *unused)
90 {
91 	/* nop */
92 }
93 
94 void
read_cb(mowgli_eventloop_t * eventloop,mowgli_eventloop_io_t * io,mowgli_eventloop_io_dir_t dir,void * arg)95 read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *arg)
96 {
97 	mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io);
98 
99 	int idx = (int) (long) arg, widx = idx + 1;
100 	u_char ch;
101 
102 	count += read(pollable->fd, &ch, sizeof(ch));
103 
104 	if (writes)
105 	{
106 		if (widx >= num_pipes)
107 			widx -= num_pipes;
108 
109 		write(pipes[2 * widx + 1], "e", 1);
110 		writes--;
111 		fired++;
112 	}
113 }
114 
115 #if NATIVE
116 void
read_thunk(struct ev_io * w,int revents)117 read_thunk(struct ev_io *w, int revents)
118 {
119 	read_cb(w->fd, revents, w->data);
120 }
121 
122 void
timer_cb(struct ev_timer * w,int revents)123 timer_cb(struct ev_timer *w, int revents)
124 {
125 	/* nop */
126 }
127 
128 #endif
129 
130 struct timeval *
run_once(void)131 run_once(void)
132 {
133 	int *cp, i, space;
134 
135 	static struct timeval ta, ts, te;
136 
137 	gettimeofday(&ta, NULL);
138 
139 	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2)
140 	{
141 		if (events[i] != NULL)
142 			mowgli_pollable_destroy(base_eventloop, events[i]);
143 
144 		events[i] = mowgli_pollable_create(base_eventloop, cp[0], (void *) (long) i);
145 		mowgli_pollable_setselect(base_eventloop, events[i], MOWGLI_EVENTLOOP_IO_READ, read_cb);
146 	}
147 
148 	fired = 0;
149 	space = num_pipes / num_active;
150 	space = space * 2;
151 
152 	for (i = 0; i < num_active; i++, fired++)
153 		write(pipes[i * space + 1], "e", 1);
154 
155 	count = 0;
156 	writes = num_writes;
157 
158 	int xcount = 0;
159 	gettimeofday(&ts, NULL);
160 
161 	do
162 	{
163 		mowgli_eventloop_run_once(base_eventloop);
164 		xcount++;
165 	} while (count != fired);
166 
167 	gettimeofday(&te, NULL);
168 
169 	timersub(&te, &ta, &ta);
170 	timersub(&te, &ts, &ts);
171 	fprintf(stdout, "%ld\t%ld\n",
172 		ta.tv_sec * 1000000L + ta.tv_usec,
173 		ts.tv_sec * 1000000L + ts.tv_usec
174 		);
175 
176 	return &te;
177 }
178 
179 int
main(int argc,char ** argv)180 main(int argc, char **argv)
181 {
182 	struct rlimit rl;
183 
184 	int i, c;
185 	int *cp;
186 	extern char *optarg;
187 
188 	num_pipes = 100;
189 	num_active = 1;
190 	num_writes = num_pipes;
191 
192 	while ((c = getopt(argc, argv, "n:a:w:te")) != -1)
193 	{
194 		switch (c)
195 		{
196 		case 'n':
197 			num_pipes = atoi(optarg);
198 			break;
199 		case 'a':
200 			num_active = atoi(optarg);
201 			break;
202 		case 'w':
203 			num_writes = atoi(optarg);
204 			break;
205 		case 't':
206 			timers = 1;
207 			break;
208 		default:
209 			fprintf(stderr, "Illegal argument \"%c\"\n", c);
210 			exit(1);
211 		}
212 	}
213 
214 #if 1
215 	rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
216 
217 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
218 		perror("setrlimit");
219 
220 #endif
221 
222 	events = calloc(num_pipes * 2, sizeof(mowgli_eventloop_pollable_t *));
223 	pipes = calloc(num_pipes * 2, sizeof(mowgli_descriptor_t));
224 
225 	if ((events == NULL) || (pipes == NULL))
226 	{
227 		perror("malloc");
228 		exit(1);
229 	}
230 
231 	mowgli_thread_set_policy(MOWGLI_THREAD_POLICY_DISABLED);
232 	base_eventloop = mowgli_eventloop_create();
233 
234 	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2)
235 	{
236 #ifdef USE_PIPES
237 
238 		if (pipe(cp) == -1)
239 		{
240 #else
241 
242 		if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1)
243 		{
244 #endif
245 			perror("pipe");
246 			exit(1);
247 		}
248 	}
249 
250 	for (i = 0; i < 2; i++)
251 		run_once();
252 
253 	exit(0);
254 }
255