michael@0: /* michael@0: * Copyright 2007-2012 Niels Provos and Nick Mathewson michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * 4. The name of the author may not be used to endorse or promote products michael@0: * derived from this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR michael@0: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES michael@0: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. michael@0: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, michael@0: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT michael@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF michael@0: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: * michael@0: */ michael@0: michael@0: #include "event2/event-config.h" michael@0: michael@0: #include michael@0: #include michael@0: #ifdef _EVENT_HAVE_SYS_TIME_H michael@0: #include michael@0: #endif michael@0: #ifdef WIN32 michael@0: #define WIN32_LEAN_AND_MEAN michael@0: #include michael@0: #else michael@0: #include michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #ifdef _EVENT_HAVE_UNISTD_H michael@0: #include michael@0: #endif michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: /* michael@0: * This benchmark tests how quickly we can propagate a write down a chain michael@0: * of socket pairs. We start by writing to the first socket pair and all michael@0: * events will fire subsequently until the last socket pair has been reached michael@0: * and the benchmark terminates. michael@0: */ michael@0: michael@0: static int fired; michael@0: static evutil_socket_t *pipes; michael@0: static struct event *events; michael@0: michael@0: static void michael@0: read_cb(evutil_socket_t fd, short which, void *arg) michael@0: { michael@0: char ch; michael@0: evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg; michael@0: michael@0: recv(fd, &ch, sizeof(ch), 0); michael@0: if (sock >= 0) { michael@0: if (send(sock, "e", 1, 0) < 0) michael@0: perror("send"); michael@0: } michael@0: fired++; michael@0: } michael@0: michael@0: static struct timeval * michael@0: run_once(int num_pipes) michael@0: { michael@0: int i; michael@0: evutil_socket_t *cp; michael@0: static struct timeval ts, te, tv_timeout; michael@0: michael@0: events = calloc(num_pipes, sizeof(struct event)); michael@0: pipes = calloc(num_pipes * 2, sizeof(evutil_socket_t)); michael@0: michael@0: if (events == NULL || pipes == NULL) { michael@0: perror("malloc"); michael@0: exit(1); michael@0: } michael@0: michael@0: for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { michael@0: if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { michael@0: perror("socketpair"); michael@0: exit(1); michael@0: } michael@0: } michael@0: michael@0: /* measurements includes event setup */ michael@0: evutil_gettimeofday(&ts, NULL); michael@0: michael@0: /* provide a default timeout for events */ michael@0: evutil_timerclear(&tv_timeout); michael@0: tv_timeout.tv_sec = 60; michael@0: michael@0: for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { michael@0: evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1; michael@0: event_set(&events[i], cp[0], EV_READ, read_cb, michael@0: (void *)(ev_intptr_t)fd); michael@0: event_add(&events[i], &tv_timeout); michael@0: } michael@0: michael@0: fired = 0; michael@0: michael@0: /* kick everything off with a single write */ michael@0: if (send(pipes[1], "e", 1, 0) < 0) michael@0: perror("send"); michael@0: michael@0: event_dispatch(); michael@0: michael@0: evutil_gettimeofday(&te, NULL); michael@0: evutil_timersub(&te, &ts, &te); michael@0: michael@0: for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { michael@0: event_del(&events[i]); michael@0: close(cp[0]); michael@0: close(cp[1]); michael@0: } michael@0: michael@0: free(pipes); michael@0: free(events); michael@0: michael@0: return (&te); michael@0: } michael@0: michael@0: int michael@0: main(int argc, char **argv) michael@0: { michael@0: #ifndef WIN32 michael@0: struct rlimit rl; michael@0: #endif michael@0: int i, c; michael@0: struct timeval *tv; michael@0: michael@0: int num_pipes = 100; michael@0: while ((c = getopt(argc, argv, "n:")) != -1) { michael@0: switch (c) { michael@0: case 'n': michael@0: num_pipes = atoi(optarg); michael@0: break; michael@0: default: michael@0: fprintf(stderr, "Illegal argument \"%c\"\n", c); michael@0: exit(1); michael@0: } michael@0: } michael@0: michael@0: #ifndef WIN32 michael@0: rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; michael@0: if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { michael@0: perror("setrlimit"); michael@0: exit(1); michael@0: } michael@0: #endif michael@0: michael@0: event_init(); michael@0: michael@0: for (i = 0; i < 25; i++) { michael@0: tv = run_once(num_pipes); michael@0: if (tv == NULL) michael@0: exit(1); michael@0: fprintf(stdout, "%ld\n", michael@0: tv->tv_sec * 1000000L + tv->tv_usec); michael@0: } michael@0: michael@0: exit(0); michael@0: }