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