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