1290001Sglebius/* 2290001Sglebius * Copyright 2003-2007 Niels Provos <provos@citi.umich.edu> 3290001Sglebius * Copyright 2007-2012 Niels Provos and Nick Mathewson 4290001Sglebius * 5290001Sglebius * Redistribution and use in source and binary forms, with or without 6290001Sglebius * modification, are permitted provided that the following conditions 7290001Sglebius * are met: 8290001Sglebius * 1. Redistributions of source code must retain the above copyright 9290001Sglebius * notice, this list of conditions and the following disclaimer. 10290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 11290001Sglebius * notice, this list of conditions and the following disclaimer in the 12290001Sglebius * documentation and/or other materials provided with the distribution. 13290001Sglebius * 4. The name of the author may not be used to endorse or promote products 14290001Sglebius * derived from this software without specific prior written permission. 15290001Sglebius * 16290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26290001Sglebius * 27290001Sglebius * 28290001Sglebius * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org> 29290001Sglebius * 30290001Sglebius * Added chain event propagation to improve the sensitivity of 31290001Sglebius * the measure respect to the event loop efficency. 32290001Sglebius * 33290001Sglebius * 34290001Sglebius */ 35290001Sglebius 36290001Sglebius#include "event2/event-config.h" 37290001Sglebius 38290001Sglebius#include <sys/types.h> 39290001Sglebius#include <sys/stat.h> 40290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H 41290001Sglebius#include <sys/time.h> 42290001Sglebius#endif 43290001Sglebius#ifdef _WIN32 44290001Sglebius#define WIN32_LEAN_AND_MEAN 45290001Sglebius#include <windows.h> 46290001Sglebius#else 47290001Sglebius#include <sys/socket.h> 48290001Sglebius#include <signal.h> 49290001Sglebius#include <sys/resource.h> 50290001Sglebius#endif 51290001Sglebius#include <fcntl.h> 52290001Sglebius#include <stdlib.h> 53290001Sglebius#include <stdio.h> 54290001Sglebius#include <string.h> 55290001Sglebius#ifdef EVENT__HAVE_UNISTD_H 56290001Sglebius#include <unistd.h> 57290001Sglebius#endif 58290001Sglebius#include <errno.h> 59290001Sglebius 60290001Sglebius#ifdef _WIN32 61290001Sglebius#include <getopt.h> 62290001Sglebius#endif 63290001Sglebius 64290001Sglebius#include <event.h> 65290001Sglebius#include <evutil.h> 66290001Sglebius 67290001Sglebiusstatic int count, writes, fired, failures; 68290001Sglebiusstatic evutil_socket_t *pipes; 69290001Sglebiusstatic int num_pipes, num_active, num_writes; 70290001Sglebiusstatic struct event *events; 71290001Sglebius 72290001Sglebius 73290001Sglebiusstatic void 74290001Sglebiusread_cb(evutil_socket_t fd, short which, void *arg) 75290001Sglebius{ 76290001Sglebius ev_intptr_t idx = (ev_intptr_t) arg, widx = idx + 1; 77290001Sglebius u_char ch; 78290001Sglebius ev_ssize_t n; 79290001Sglebius 80290001Sglebius n = recv(fd, (char*)&ch, sizeof(ch), 0); 81290001Sglebius if (n >= 0) 82290001Sglebius count += n; 83290001Sglebius else 84290001Sglebius failures++; 85290001Sglebius if (writes) { 86290001Sglebius if (widx >= num_pipes) 87290001Sglebius widx -= num_pipes; 88290001Sglebius n = send(pipes[2 * widx + 1], "e", 1, 0); 89290001Sglebius if (n != 1) 90290001Sglebius failures++; 91290001Sglebius writes--; 92290001Sglebius fired++; 93290001Sglebius } 94290001Sglebius} 95290001Sglebius 96290001Sglebiusstatic struct timeval * 97290001Sglebiusrun_once(void) 98290001Sglebius{ 99290001Sglebius evutil_socket_t *cp, space; 100290001Sglebius long i; 101290001Sglebius static struct timeval ts, te; 102290001Sglebius 103290001Sglebius for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 104290001Sglebius if (event_initialized(&events[i])) 105290001Sglebius event_del(&events[i]); 106290001Sglebius event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *)(ev_intptr_t) i); 107290001Sglebius event_add(&events[i], NULL); 108290001Sglebius } 109290001Sglebius 110290001Sglebius event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); 111290001Sglebius 112290001Sglebius fired = 0; 113290001Sglebius space = num_pipes / num_active; 114290001Sglebius space = space * 2; 115290001Sglebius for (i = 0; i < num_active; i++, fired++) 116290001Sglebius (void) send(pipes[i * space + 1], "e", 1, 0); 117290001Sglebius 118290001Sglebius count = 0; 119290001Sglebius writes = num_writes; 120290001Sglebius { int xcount = 0; 121290001Sglebius evutil_gettimeofday(&ts, NULL); 122290001Sglebius do { 123290001Sglebius event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); 124290001Sglebius xcount++; 125290001Sglebius } while (count != fired); 126290001Sglebius evutil_gettimeofday(&te, NULL); 127290001Sglebius 128290001Sglebius if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); 129290001Sglebius } 130290001Sglebius 131290001Sglebius evutil_timersub(&te, &ts, &te); 132290001Sglebius 133290001Sglebius return (&te); 134290001Sglebius} 135290001Sglebius 136290001Sglebiusint 137290001Sglebiusmain(int argc, char **argv) 138290001Sglebius{ 139290001Sglebius#ifdef HAVE_SETRLIMIT 140290001Sglebius struct rlimit rl; 141290001Sglebius#endif 142290001Sglebius int i, c; 143290001Sglebius struct timeval *tv; 144290001Sglebius evutil_socket_t *cp; 145290001Sglebius 146290001Sglebius#ifdef _WIN32 147290001Sglebius WSADATA WSAData; 148290001Sglebius WSAStartup(0x101, &WSAData); 149290001Sglebius#endif 150290001Sglebius num_pipes = 100; 151290001Sglebius num_active = 1; 152290001Sglebius num_writes = num_pipes; 153290001Sglebius while ((c = getopt(argc, argv, "n:a:w:")) != -1) { 154290001Sglebius switch (c) { 155290001Sglebius case 'n': 156290001Sglebius num_pipes = atoi(optarg); 157290001Sglebius break; 158290001Sglebius case 'a': 159290001Sglebius num_active = atoi(optarg); 160290001Sglebius break; 161290001Sglebius case 'w': 162290001Sglebius num_writes = atoi(optarg); 163290001Sglebius break; 164290001Sglebius default: 165290001Sglebius fprintf(stderr, "Illegal argument \"%c\"\n", c); 166290001Sglebius exit(1); 167290001Sglebius } 168290001Sglebius } 169290001Sglebius 170290001Sglebius#ifdef HAVE_SETRLIMIT 171290001Sglebius rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; 172290001Sglebius if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 173290001Sglebius perror("setrlimit"); 174290001Sglebius exit(1); 175290001Sglebius } 176290001Sglebius#endif 177290001Sglebius 178290001Sglebius events = calloc(num_pipes, sizeof(struct event)); 179290001Sglebius pipes = calloc(num_pipes * 2, sizeof(evutil_socket_t)); 180290001Sglebius if (events == NULL || pipes == NULL) { 181290001Sglebius perror("malloc"); 182290001Sglebius exit(1); 183290001Sglebius } 184290001Sglebius 185290001Sglebius event_init(); 186290001Sglebius 187290001Sglebius for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { 188290001Sglebius#ifdef USE_PIPES 189290001Sglebius if (pipe(cp) == -1) { 190290001Sglebius#else 191290001Sglebius if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { 192290001Sglebius#endif 193290001Sglebius perror("pipe"); 194290001Sglebius exit(1); 195290001Sglebius } 196290001Sglebius } 197290001Sglebius 198290001Sglebius for (i = 0; i < 25; i++) { 199290001Sglebius tv = run_once(); 200290001Sglebius if (tv == NULL) 201290001Sglebius exit(1); 202290001Sglebius fprintf(stdout, "%ld\n", 203290001Sglebius tv->tv_sec * 1000000L + tv->tv_usec); 204290001Sglebius } 205290001Sglebius 206290001Sglebius exit(0); 207290001Sglebius} 208