1275970Scy/* 2275970Scy * Copyright 2007-2012 Niels Provos and Nick Mathewson 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 4. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy * 26275970Scy */ 27275970Scy 28275970Scy#include "event2/event-config.h" 29275970Scy 30275970Scy#include <sys/types.h> 31275970Scy#include <sys/stat.h> 32275970Scy#ifdef EVENT__HAVE_SYS_TIME_H 33275970Scy#include <sys/time.h> 34275970Scy#endif 35275970Scy#ifdef _WIN32 36275970Scy#define WIN32_LEAN_AND_MEAN 37275970Scy#include <windows.h> 38275970Scy#else 39275970Scy#include <sys/socket.h> 40275970Scy#include <sys/resource.h> 41275970Scy#endif 42275970Scy#include <signal.h> 43275970Scy#include <fcntl.h> 44275970Scy#include <stdlib.h> 45275970Scy#include <stdio.h> 46275970Scy#include <string.h> 47275970Scy#ifdef EVENT__HAVE_UNISTD_H 48275970Scy#include <unistd.h> 49275970Scy#endif 50275970Scy#include <errno.h> 51275970Scy#include <getopt.h> 52275970Scy#include <event.h> 53275970Scy#include <evutil.h> 54275970Scy 55275970Scy/* 56275970Scy * This benchmark tests how quickly we can propagate a write down a chain 57275970Scy * of socket pairs. We start by writing to the first socket pair and all 58275970Scy * events will fire subsequently until the last socket pair has been reached 59275970Scy * and the benchmark terminates. 60275970Scy */ 61275970Scy 62275970Scystatic int fired; 63275970Scystatic evutil_socket_t *pipes; 64275970Scystatic struct event *events; 65275970Scy 66275970Scystatic void 67275970Scyread_cb(evutil_socket_t fd, short which, void *arg) 68275970Scy{ 69275970Scy char ch; 70275970Scy evutil_socket_t sock = (evutil_socket_t)(ev_intptr_t)arg; 71275970Scy 72275970Scy (void) recv(fd, &ch, sizeof(ch), 0); 73275970Scy if (sock >= 0) { 74275970Scy if (send(sock, "e", 1, 0) < 0) 75275970Scy perror("send"); 76275970Scy } 77275970Scy fired++; 78275970Scy} 79275970Scy 80275970Scystatic struct timeval * 81275970Scyrun_once(int num_pipes) 82275970Scy{ 83275970Scy int i; 84275970Scy evutil_socket_t *cp; 85275970Scy static struct timeval ts, te, tv_timeout; 86275970Scy 87275970Scy events = (struct event *)calloc(num_pipes, sizeof(struct event)); 88275970Scy pipes = (evutil_socket_t *)calloc(num_pipes * 2, sizeof(evutil_socket_t)); 89275970Scy 90275970Scy if (events == NULL || pipes == NULL) { 91275970Scy perror("malloc"); 92275970Scy exit(1); 93275970Scy } 94275970Scy 95275970Scy for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 96275970Scy if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { 97275970Scy perror("socketpair"); 98275970Scy exit(1); 99275970Scy } 100275970Scy } 101275970Scy 102275970Scy /* measurements includes event setup */ 103275970Scy evutil_gettimeofday(&ts, NULL); 104275970Scy 105275970Scy /* provide a default timeout for events */ 106275970Scy evutil_timerclear(&tv_timeout); 107275970Scy tv_timeout.tv_sec = 60; 108275970Scy 109275970Scy for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 110275970Scy evutil_socket_t fd = i < num_pipes - 1 ? cp[3] : -1; 111275970Scy event_set(&events[i], cp[0], EV_READ, read_cb, 112275970Scy (void *)(ev_intptr_t)fd); 113275970Scy event_add(&events[i], &tv_timeout); 114275970Scy } 115275970Scy 116275970Scy fired = 0; 117275970Scy 118275970Scy /* kick everything off with a single write */ 119275970Scy if (send(pipes[1], "e", 1, 0) < 0) 120275970Scy perror("send"); 121275970Scy 122275970Scy event_dispatch(); 123275970Scy 124275970Scy evutil_gettimeofday(&te, NULL); 125275970Scy evutil_timersub(&te, &ts, &te); 126275970Scy 127275970Scy for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 128275970Scy event_del(&events[i]); 129275970Scy evutil_closesocket(cp[0]); 130275970Scy evutil_closesocket(cp[1]); 131275970Scy } 132275970Scy 133275970Scy free(pipes); 134275970Scy free(events); 135275970Scy 136275970Scy return (&te); 137275970Scy} 138275970Scy 139275970Scyint 140275970Scymain(int argc, char **argv) 141275970Scy{ 142275970Scy#ifdef HAVE_SETRLIMIT 143275970Scy struct rlimit rl; 144275970Scy#endif 145275970Scy int i, c; 146275970Scy struct timeval *tv; 147275970Scy 148275970Scy int num_pipes = 100; 149275970Scy#ifdef _WIN32 150275970Scy WSADATA WSAData; 151275970Scy WSAStartup(0x101, &WSAData); 152275970Scy#endif 153275970Scy 154275970Scy while ((c = getopt(argc, argv, "n:")) != -1) { 155275970Scy switch (c) { 156275970Scy case 'n': 157275970Scy num_pipes = atoi(optarg); 158275970Scy break; 159275970Scy default: 160275970Scy fprintf(stderr, "Illegal argument \"%c\"\n", c); 161275970Scy exit(1); 162275970Scy } 163275970Scy } 164275970Scy 165275970Scy#ifdef HAVE_SETRLIMIT 166275970Scy rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; 167275970Scy if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 168275970Scy perror("setrlimit"); 169275970Scy exit(1); 170275970Scy } 171275970Scy#endif 172275970Scy 173275970Scy event_init(); 174275970Scy 175275970Scy for (i = 0; i < 25; i++) { 176275970Scy tv = run_once(num_pipes); 177275970Scy if (tv == NULL) 178275970Scy exit(1); 179275970Scy fprintf(stdout, "%ld\n", 180275970Scy tv->tv_sec * 1000000L + tv->tv_usec); 181275970Scy } 182275970Scy 183275970Scy#ifdef _WIN32 184275970Scy WSACleanup(); 185275970Scy#endif 186275970Scy 187275970Scy exit(0); 188275970Scy} 189