/* * CDDL HEADER START * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the "License"). You may not use this file except * in compliance with the License. * * You can obtain a copy of the license at * src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing * permissions and limitations under the License. * * When distributing Covered Code, include this CDDL * HEADER in each file and include the License file at * usr/src/OPENSOLARIS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your * own identifying information: Portions Copyright [yyyy] * [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef __sun #pragma ident "@(#)pipe.c 1.4 05/08/04 SMI" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libmicro.h" typedef struct { int ts_once; pid_t ts_child; pthread_t ts_thread; int ts_in; int ts_out; int ts_in2; int ts_out2; int ts_lsn; struct sockaddr_in ts_add; } tsd_t; #define FIRSTPORT 12345 static char *modes[] = {"st", "mt", "mp", NULL}; #define MD_SINGLE 0 #define MD_MULTITHREAD 1 #define MD_MULTIPROCESS 2 static char *xports[] = {"pipe", "fifo", "sock", "tcp", NULL}; #define XP_PIPES 0 #define XP_FIFOS 1 #define XP_SOCKETPAIR 2 #define XP_LOCALTCP 3 #define DEFM MD_SINGLE #define DEFS 1024 #define DEFX XP_PIPES static int optm = DEFM; static size_t opts = DEFS; static int optx = DEFX; static void *rbuf = NULL; static void *wbuf = NULL; int readall(int s, void *buf, size_t len); void * loopback(void *arg); int prepare_pipes(tsd_t *tsd); int prepare_fifos(tsd_t *tsd); int cleanup_fifos(tsd_t *tsd); int prepare_socketpair(tsd_t *tsd); int prepare_localtcp(tsd_t *tsd); int prepare_localtcp_once(tsd_t *tsd); char *lookupa(int x, char *names[]); int lookup(char *x, char *names[]); int benchmark_init() { lm_tsdsize = sizeof (tsd_t); (void) sprintf(lm_optstr, "m:s:x:"); (void) sprintf(lm_usage, " [-m mode (st|mt|mp, default %s)]\n" " [-s buffer-size (default %d)]\n" " [-x transport (pipe|fifo|sock|tcp, default %s)]\n" "notes: measures write()/read() across various transports\n", lookupa(DEFM, modes), DEFS, lookupa(DEFX, xports)); (void) sprintf(lm_header, "%2s %4s", "md", "xprt"); return (0); } int benchmark_optswitch(int opt, char *optarg) { int x; switch (opt) { case 'm': x = lookup(optarg, modes); if (x == -1) return (-1); optm = x; break; case 's': opts = sizetoll(optarg); break; case 'x': x = lookup(optarg, xports); if (x == -1) return (-1); optx = x; break; default: return (-1); } return (0); } int benchmark_initrun() { if (optx == XP_FIFOS) { if (geteuid() != 0) { (void) printf("sorry, must be root to create fifos\n"); exit(1); } } (void) setfdlimit(4 * lm_optT + 10); rbuf = malloc(opts); wbuf = malloc(opts); return (0); } int benchmark_initbatch(void *tsd) { tsd_t *ts = (tsd_t *)tsd; int result; pid_t pid; switch (optx) { case XP_SOCKETPAIR: result = prepare_socketpair(ts); break; case XP_LOCALTCP: result = prepare_localtcp(ts); break; case XP_FIFOS: result = prepare_fifos(ts); break; case XP_PIPES: default: result = prepare_pipes(ts); break; } if (result == -1) { return (1); } switch (optm) { case MD_MULTITHREAD: result = pthread_create(&ts->ts_thread, NULL, loopback, tsd); if (result == -1) { return (1); } break; case MD_MULTIPROCESS: pid = fork(); switch (pid) { case 0: (void) loopback(tsd); exit(0); break; case -1: return (-1); default: ts->ts_child = pid; break; } break; case MD_SINGLE: default: break; } return (0); } int benchmark(void *tsd, result_t *res) { tsd_t *ts = (tsd_t *)tsd; int i; int n; for (i = 0; i < lm_optB; i++) { if (write(ts->ts_out, wbuf, opts) != opts) { res->re_errors++; continue; } n = readall(ts->ts_in, rbuf, opts); if (n == -1) { res->re_errors++; continue; } } res->re_count = i; return (0); } int benchmark_finibatch(void *tsd) { tsd_t *ts = (tsd_t *)tsd; switch (optm) { case MD_MULTITHREAD: (void) pthread_join(ts->ts_thread, NULL); (void) close(ts->ts_in2); (void) close(ts->ts_out2); break; case MD_MULTIPROCESS: (void) kill(ts->ts_child, SIGKILL); (void) waitpid(ts->ts_child, NULL, 0); (void) close(ts->ts_in2); (void) close(ts->ts_out2); break; case MD_SINGLE: default: break; } (void) close(ts->ts_in); (void) close(ts->ts_out); if (optx == XP_FIFOS) { (void) cleanup_fifos(ts); } return (0); } char * benchmark_result() { static char result[256]; (void) sprintf(result, "%2s %4s", lookupa(optm, modes), lookupa(optx, xports)); return (result); } int readall(int s, void *buf, size_t len) { size_t n; size_t total = 0; int count = 0; for (;;) { n = read(s, (void *)((long)buf + total), len - total); if (n < 1) { return (-1); } total += n; count++; if (total == len) { return (count); } } } void * loopback(void *arg) { tsd_t *ts = (tsd_t *)arg; int i, n; for (i = 0; i < lm_optB; i++) { n = readall(ts->ts_in2, rbuf, opts); if (n == -1) { continue; } if (write(ts->ts_out2, wbuf, opts) != opts) { continue; } } return (NULL); } int prepare_localtcp_once(tsd_t *ts) { int j; int opt = 1; struct hostent *host; j = FIRSTPORT; ts->ts_lsn = socket(AF_INET, SOCK_STREAM, 0); if (ts->ts_lsn == -1) { return (-1); } if (setsockopt(ts->ts_lsn, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (int)) == -1) { return (-1); } if ((host = gethostbyname("localhost")) == NULL) { return (-1); } for (;;) { (void) memset(&ts->ts_add, 0, sizeof (struct sockaddr_in)); ts->ts_add.sin_family = AF_INET; ts->ts_add.sin_port = htons(j++); (void) memcpy(&ts->ts_add.sin_addr.s_addr, host->h_addr_list[0], sizeof (struct in_addr)); if (bind(ts->ts_lsn, (struct sockaddr *)&ts->ts_add, sizeof (struct sockaddr_in)) == 0) { break; } if (errno != EADDRINUSE) { return (-1); } } if (listen(ts->ts_lsn, 5) == -1) { return (-1); } return (0); } int prepare_localtcp(tsd_t *ts) { int result; struct sockaddr_in addr; int opt = 1; socklen_t size; if (ts->ts_once++ == 0) { if (prepare_localtcp_once(ts) == -1) { return (-1); } } ts->ts_out = socket(AF_INET, SOCK_STREAM, 0); if (ts->ts_out == -1) { return (-1); } if (fcntl(ts->ts_out, F_SETFL, O_NDELAY) == -1) { return (-1); } result = connect(ts->ts_out, (struct sockaddr *)&ts->ts_add, sizeof (struct sockaddr_in)); if ((result == -1) && (errno != EINPROGRESS)) { return (-1); } if (fcntl(ts->ts_out, F_SETFL, 0) == -1) { return (-1); } size = sizeof (struct sockaddr); result = accept(ts->ts_lsn, (struct sockaddr *)&addr, &size); if (result == -1) { return (-1); } ts->ts_out2 = result; if (setsockopt(ts->ts_out, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof (int)) == -1) { return (-1); } if (setsockopt(ts->ts_out2, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof (int)) == -1) { return (-1); } if (optm == MD_SINGLE) { ts->ts_in = ts->ts_out2; } else { ts->ts_in = ts->ts_out; ts->ts_in2 = ts->ts_out2; } return (0); } int prepare_socketpair(tsd_t *ts) { int s[2]; if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) == -1) { return (-1); } if (optm == MD_SINGLE) { ts->ts_in = s[0]; ts->ts_out = s[1]; } else { ts->ts_in = s[0]; ts->ts_out = s[0]; ts->ts_in2 = s[1]; ts->ts_out2 = s[1]; } return (0); } int prepare_fifos(tsd_t *ts) { char path[64]; (void) sprintf(path, "/tmp/pipe_%ld.%dA", getpid(), pthread_self()); if (mknod(path, 0600, S_IFIFO) == -1) { return (-1); } if (optm == MD_SINGLE) { ts->ts_in = open(path, O_RDONLY); ts->ts_out = open(path, O_WRONLY); } else { ts->ts_in = open(path, O_RDONLY); ts->ts_out2 = open(path, O_WRONLY); (void) sprintf(path, "/tmp/pipe_%ld.%dB", getpid(), pthread_self()); if (mknod(path, 0600, S_IFIFO) == -1) { return (-1); } ts->ts_in2 = open(path, O_RDONLY); ts->ts_out = open(path, O_WRONLY); } return (0); } /*ARGSUSED*/ int cleanup_fifos(tsd_t *ts) { char path[64]; (void) sprintf(path, "/tmp/pipe_%ld.%dA", getpid(), pthread_self()); (void) unlink(path); (void) sprintf(path, "/tmp/pipe_%ld.%dB", getpid(), pthread_self()); (void) unlink(path); return (0); } int prepare_pipes(tsd_t *ts) { int p[2]; if (optm == MD_SINGLE) { if (pipe(p) == -1) { return (-1); } ts->ts_in = p[0]; ts->ts_out = p[1]; } else { if (pipe(p) == -1) { return (-1); } ts->ts_in = p[0]; ts->ts_out2 = p[1]; if (pipe(p) == -1) { return (-1); } ts->ts_in2 = p[0]; ts->ts_out = p[1]; } return (0); } char * lookupa(int x, char *names[]) { int i = 0; while (names[i] != NULL) { if (x == i) { return (names[i]); } i++; } return (NULL); } int lookup(char *x, char *names[]) { int i = 0; while (names[i] != NULL) { if (strcmp(names[i], x) == 0) { return (i); } i++; } return (-1); }