xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/test/bench_cascade.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: bench_cascade.c,v 1.6 2024/08/18 20:47:23 christos Exp $	*/
28585484eSchristos 
38585484eSchristos /*
48585484eSchristos  * Copyright 2007-2012 Niels Provos and Nick Mathewson
58585484eSchristos  *
68585484eSchristos  * Redistribution and use in source and binary forms, with or without
78585484eSchristos  * modification, are permitted provided that the following conditions
88585484eSchristos  * are met:
98585484eSchristos  * 1. Redistributions of source code must retain the above copyright
108585484eSchristos  *    notice, this list of conditions and the following disclaimer.
118585484eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
128585484eSchristos  *    notice, this list of conditions and the following disclaimer in the
138585484eSchristos  *    documentation and/or other materials provided with the distribution.
148585484eSchristos  * 4. The name of the author may not be used to endorse or promote products
158585484eSchristos  *    derived from this software without specific prior written permission.
168585484eSchristos  *
178585484eSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
188585484eSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198585484eSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208585484eSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218585484eSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228585484eSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238585484eSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248585484eSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258585484eSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268585484eSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278585484eSchristos  *
288585484eSchristos  */
298585484eSchristos 
308585484eSchristos #include "event2/event-config.h"
318585484eSchristos 
328585484eSchristos #include <sys/types.h>
338585484eSchristos #include <sys/stat.h>
348585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H
358585484eSchristos #include <sys/time.h>
368585484eSchristos #endif
378585484eSchristos #ifdef _WIN32
388585484eSchristos #define WIN32_LEAN_AND_MEAN
398585484eSchristos #include <windows.h>
40*eabc0478Schristos #include <getopt.h>
41*eabc0478Schristos #else /* _WIN32 */
428585484eSchristos #include <sys/socket.h>
438585484eSchristos #include <sys/resource.h>
448585484eSchristos #endif
458585484eSchristos #include <signal.h>
468585484eSchristos #include <fcntl.h>
478585484eSchristos #include <stdlib.h>
488585484eSchristos #include <stdio.h>
498585484eSchristos #include <string.h>
508585484eSchristos #ifdef EVENT__HAVE_UNISTD_H
518585484eSchristos #include <unistd.h>
528585484eSchristos #endif
538585484eSchristos #include <errno.h>
548585484eSchristos #include <event.h>
558585484eSchristos #include <evutil.h>
568585484eSchristos 
578585484eSchristos /*
588585484eSchristos  * This benchmark tests how quickly we can propagate a write down a chain
598585484eSchristos  * of socket pairs.  We start by writing to the first socket pair and all
608585484eSchristos  * events will fire subsequently until the last socket pair has been reached
618585484eSchristos  * and the benchmark terminates.
628585484eSchristos  */
638585484eSchristos 
648585484eSchristos static int fired;
658585484eSchristos static evutil_socket_t *pipes;
668585484eSchristos static struct event *events;
678585484eSchristos 
688585484eSchristos static void
698585484eSchristos read_cb(evutil_socket_t fd, short which, void *arg)
708585484eSchristos {
718585484eSchristos 	char ch;
728585484eSchristos 	evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg;
738585484eSchristos 
74b8ecfcfeSchristos 	(void) recv(fd, &ch, sizeof(ch), 0);
758585484eSchristos 	if (sock >= 0) {
768585484eSchristos 		if (send(sock, "e", 1, 0) < 0)
778585484eSchristos 			perror("send");
788585484eSchristos 	}
798585484eSchristos 	fired++;
808585484eSchristos }
818585484eSchristos 
828585484eSchristos static struct timeval *
838585484eSchristos run_once(int num_pipes)
848585484eSchristos {
858585484eSchristos 	int i;
868585484eSchristos 	evutil_socket_t *cp;
878585484eSchristos 	static struct timeval ts, te, tv_timeout;
888585484eSchristos 
89b8ecfcfeSchristos 	events = (struct event *)calloc(num_pipes, sizeof(struct event));
90b8ecfcfeSchristos 	pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t));
918585484eSchristos 
928585484eSchristos 	if (events == NULL || pipes == NULL) {
938585484eSchristos 		perror("malloc");
948585484eSchristos 		exit(1);
958585484eSchristos 	}
968585484eSchristos 
978585484eSchristos 	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
988585484eSchristos 		if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
998585484eSchristos 			perror("socketpair");
1008585484eSchristos 			exit(1);
1018585484eSchristos 		}
1028585484eSchristos 	}
1038585484eSchristos 
1048585484eSchristos 	/* measurements includes event setup */
1058585484eSchristos 	evutil_gettimeofday(&ts, NULL);
1068585484eSchristos 
1078585484eSchristos 	/* provide a default timeout for events */
1088585484eSchristos 	evutil_timerclear(&tv_timeout);
1098585484eSchristos 	tv_timeout.tv_sec = 60;
1108585484eSchristos 
1118585484eSchristos 	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
1128585484eSchristos 		evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1;
1138585484eSchristos 		event_set(&events[i], cp[0], EV_READ, read_cb,
1148585484eSchristos 		    (void *)(ev_intptr_t)fd);
1158585484eSchristos 		event_add(&events[i], &tv_timeout);
1168585484eSchristos 	}
1178585484eSchristos 
1188585484eSchristos 	fired = 0;
1198585484eSchristos 
1208585484eSchristos 	/* kick everything off with a single write */
1218585484eSchristos 	if (send(pipes[1], "e", 1, 0) < 0)
1228585484eSchristos 		perror("send");
1238585484eSchristos 
1248585484eSchristos 	event_dispatch();
1258585484eSchristos 
1268585484eSchristos 	evutil_gettimeofday(&te, NULL);
1278585484eSchristos 	evutil_timersub(&te, &ts, &te);
1288585484eSchristos 
1298585484eSchristos 	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
1308585484eSchristos 		event_del(&events[i]);
131b8ecfcfeSchristos 		evutil_closesocket(cp[0]);
132b8ecfcfeSchristos 		evutil_closesocket(cp[1]);
1338585484eSchristos 	}
1348585484eSchristos 
1358585484eSchristos 	free(pipes);
1368585484eSchristos 	free(events);
1378585484eSchristos 
1388585484eSchristos 	return (&te);
1398585484eSchristos }
1408585484eSchristos 
1418585484eSchristos int
1428585484eSchristos main(int argc, char **argv)
1438585484eSchristos {
144*eabc0478Schristos #ifdef EVENT__HAVE_SETRLIMIT
1458585484eSchristos 	struct rlimit rl;
1468585484eSchristos #endif
1478585484eSchristos 	int i, c;
1488585484eSchristos 	struct timeval *tv;
1498585484eSchristos 
1508585484eSchristos 	int num_pipes = 100;
151b8ecfcfeSchristos #ifdef _WIN32
152b8ecfcfeSchristos 	WSADATA WSAData;
153b8ecfcfeSchristos 	WSAStartup(0x101, &WSAData);
154b8ecfcfeSchristos #endif
155b8ecfcfeSchristos 
1568585484eSchristos 	while ((c = getopt(argc, argv, "n:")) != -1) {
1578585484eSchristos 		switch (c) {
1588585484eSchristos 		case 'n':
1598585484eSchristos 			num_pipes = atoi(optarg);
1608585484eSchristos 			break;
1618585484eSchristos 		default:
1628585484eSchristos 			fprintf(stderr, "Illegal argument \"%c\"\n", c);
1638585484eSchristos 			exit(1);
1648585484eSchristos 		}
1658585484eSchristos 	}
1668585484eSchristos 
167*eabc0478Schristos #ifdef EVENT__HAVE_SETRLIMIT
1688585484eSchristos 	rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
1698585484eSchristos 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
1708585484eSchristos 		perror("setrlimit");
1718585484eSchristos 		exit(1);
1728585484eSchristos 	}
1738585484eSchristos #endif
1748585484eSchristos 
1758585484eSchristos 	event_init();
1768585484eSchristos 
1778585484eSchristos 	for (i = 0; i < 25; i++) {
1788585484eSchristos 		tv = run_once(num_pipes);
1798585484eSchristos 		if (tv == NULL)
1808585484eSchristos 			exit(1);
1818585484eSchristos 		fprintf(stdout, "%ld\n",
1828585484eSchristos 			tv->tv_sec * 1000000L + tv->tv_usec);
1838585484eSchristos 	}
1848585484eSchristos 
185b8ecfcfeSchristos #ifdef _WIN32
186b8ecfcfeSchristos 	WSACleanup();
187b8ecfcfeSchristos #endif
188b8ecfcfeSchristos 
1898585484eSchristos 	exit(0);
1908585484eSchristos }
191