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