/* * bw_pipe.c - pipe bandwidth benchmark. * * Usage: bw_pipe [-m ] [-M ] \ * [-P ] [-W ] [-N ] * * Copyright (c) 1994 Larry McVoy. * Copyright (c) 2002 Carl Staelin. * Distributed under the FSF GPL with additional restriction that results * may published only if: * (1) the benchmark is unmodified, and * (2) the version in the sccsid below is included in the report. * Support for this development by Sun Microsystems is gratefully acknowledged. */ char *id = "$Id$\n"; #include "bench.h" void reader(iter_t iterations, void* cookie); void writer(int writefd, char* buf, size_t xfer); int XFER = 10*1024*1024; struct _state { int pid; size_t xfer; /* bytes to read/write per "packet" */ size_t bytes; /* bytes to read/write in one iteration */ char *buf; /* buffer memory space */ int readfd; }; void initialize(iter_t iterations, void *cookie) { int pipes[2]; struct _state* state = (struct _state*)cookie; if (iterations) return; if (pipe(pipes) == -1) { perror("pipe"); exit(1); } handle_scheduler(benchmp_childid(), 0, 1); switch (state->pid = fork()) { case 0: close(pipes[0]); handle_scheduler(benchmp_childid(), 1, 1); state->buf = valloc(state->xfer); if (state->buf == NULL) { perror("child: no memory"); exit(2); } touch(state->buf, state->xfer); writer(pipes[1], state->buf, state->xfer); return; /*NOTREACHED*/ case -1: perror("fork"); exit(3); /*NOTREACHED*/ default: break; } close(pipes[1]); state->readfd = pipes[0]; state->buf = valloc(state->xfer + getpagesize()); if (state->buf == NULL) { perror("parent: no memory"); exit(4); } touch(state->buf, state->xfer + getpagesize()); state->buf += 128; /* destroy page alignment */ } void cleanup(iter_t iterations, void * cookie) { struct _state* state = (struct _state*)cookie; if (iterations) return; close(state->readfd); if (state->pid > 0) { kill(state->pid, SIGKILL); waitpid(state->pid, NULL, 0); } state->pid = 0; } void reader(iter_t iterations, void * cookie) { size_t done; ssize_t n; struct _state* state = (struct _state*)cookie; while (iterations-- > 0) { for (done = 0; done < state->bytes; done += n) { if ((n = read(state->readfd, state->buf, state->xfer)) < 0) { perror("bw_pipe: reader: error in read"); exit(1); } } } } void writer(int writefd, char* buf, size_t xfer) { size_t done; ssize_t n; for ( ;; ) { #ifdef TOUCH touch(buf, xfer); #endif for (done = 0; done < xfer; done += n) { if ((n = write(writefd, buf, xfer - done)) < 0) { exit(0); } } } } int main(int ac, char *av[]) { struct _state state; int parallel = 1; int warmup = 0; int repetitions = -1; int c; char* usage = "[-m ] [-M ] [-P ] [-W ] [-N ]\n"; state.xfer = XFERSIZE; /* per-packet size */ state.bytes = XFER; /* total bytes per call */ while (( c = getopt(ac, av, "m:M:P:W:N:")) != EOF) { switch(c) { case 'm': state.xfer = bytes(optarg); break; case 'M': state.bytes = bytes(optarg); break; case 'P': parallel = atoi(optarg); if (parallel <= 0) lmbench_usage(ac, av, usage); break; case 'W': warmup = atoi(optarg); break; case 'N': repetitions = atoi(optarg); break; default: lmbench_usage(ac, av, usage); break; } } if (optind < ac) { lmbench_usage(ac, av, usage); } /* round up total byte count to a multiple of xfer */ if (state.bytes < state.xfer) { state.bytes = state.xfer; } else if (state.bytes % state.xfer) { state.bytes += state.bytes - state.bytes % state.xfer; } benchmp(initialize, reader, cleanup, MEDIUM, parallel, warmup, repetitions, &state); if (gettime() > 0) { fprintf(stderr, "Pipe bandwidth: "); mb(get_n() * parallel * state.bytes); } return(0); }