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