1 /* $NetBSD: bench_cascade.c,v 1.4 2016/01/08 21:35:41 christos Exp $ */ 2 3 /* 4 * Copyright 2007-2012 Niels Provos and Nick Mathewson 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #include "event2/event-config.h" 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #ifdef EVENT__HAVE_SYS_TIME_H 35 #include <sys/time.h> 36 #endif 37 #ifdef _WIN32 38 #define WIN32_LEAN_AND_MEAN 39 #include <windows.h> 40 #else 41 #include <sys/socket.h> 42 #include <sys/resource.h> 43 #endif 44 #include <signal.h> 45 #include <fcntl.h> 46 #include <stdlib.h> 47 #include <stdio.h> 48 #include <string.h> 49 #ifdef EVENT__HAVE_UNISTD_H 50 #include <unistd.h> 51 #endif 52 #include <errno.h> 53 #include <getopt.h> 54 #include <event.h> 55 #include <evutil.h> 56 57 /* 58 * This benchmark tests how quickly we can propagate a write down a chain 59 * of socket pairs. We start by writing to the first socket pair and all 60 * events will fire subsequently until the last socket pair has been reached 61 * and the benchmark terminates. 62 */ 63 64 static int fired; 65 static evutil_socket_t *pipes; 66 static struct event *events; 67 68 static void 69 read_cb(evutil_socket_t fd, short which, void *arg) 70 { 71 char ch; 72 evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg; 73 74 (void) recv(fd, &ch, sizeof(ch), 0); 75 if (sock >= 0) { 76 if (send(sock, "e", 1, 0) < 0) 77 perror("send"); 78 } 79 fired++; 80 } 81 82 static struct timeval * 83 run_once(int num_pipes) 84 { 85 int i; 86 evutil_socket_t *cp; 87 static struct timeval ts, te, tv_timeout; 88 89 events = (struct event *)calloc(num_pipes, sizeof(struct event)); 90 pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t)); 91 92 if (events == NULL || pipes == NULL) { 93 perror("malloc"); 94 exit(1); 95 } 96 97 for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 98 if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { 99 perror("socketpair"); 100 exit(1); 101 } 102 } 103 104 /* measurements includes event setup */ 105 evutil_gettimeofday(&ts, NULL); 106 107 /* provide a default timeout for events */ 108 evutil_timerclear(&tv_timeout); 109 tv_timeout.tv_sec = 60; 110 111 for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 112 evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1; 113 event_set(&events[i], cp[0], EV_READ, read_cb, 114 (void *)(ev_intptr_t)fd); 115 event_add(&events[i], &tv_timeout); 116 } 117 118 fired = 0; 119 120 /* kick everything off with a single write */ 121 if (send(pipes[1], "e", 1, 0) < 0) 122 perror("send"); 123 124 event_dispatch(); 125 126 evutil_gettimeofday(&te, NULL); 127 evutil_timersub(&te, &ts, &te); 128 129 for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 130 event_del(&events[i]); 131 evutil_closesocket(cp[0]); 132 evutil_closesocket(cp[1]); 133 } 134 135 free(pipes); 136 free(events); 137 138 return (&te); 139 } 140 141 int 142 main(int argc, char **argv) 143 { 144 #ifdef HAVE_SETRLIMIT 145 struct rlimit rl; 146 #endif 147 int i, c; 148 struct timeval *tv; 149 150 int num_pipes = 100; 151 #ifdef _WIN32 152 WSADATA WSAData; 153 WSAStartup(0x101, &WSAData); 154 #endif 155 156 while ((c = getopt(argc, argv, "n:")) != -1) { 157 switch (c) { 158 case 'n': 159 num_pipes = atoi(optarg); 160 break; 161 default: 162 fprintf(stderr, "Illegal argument \"%c\"\n", c); 163 exit(1); 164 } 165 } 166 167 #ifdef HAVE_SETRLIMIT 168 rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; 169 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 170 perror("setrlimit"); 171 exit(1); 172 } 173 #endif 174 175 event_init(); 176 177 for (i = 0; i < 25; i++) { 178 tv = run_once(num_pipes); 179 if (tv == NULL) 180 exit(1); 181 fprintf(stdout, "%ld\n", 182 tv->tv_sec * 1000000L + tv->tv_usec); 183 } 184 185 #ifdef _WIN32 186 WSACleanup(); 187 #endif 188 189 exit(0); 190 } 191