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