/* * bw_udp.c - simple UDP bandwidth test * * Three programs in one - * server usage: bw_tcp -s * client usage: bw_tcp [-m ] [-P ] [-W ] [-N ] hostname [bytes] * shutdown: bw_tcp -S hostname * * Copyright (c) 2000 Carl Staelin. * Copyright (c) 1994 Larry McVoy. 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" #define MAX_MSIZE (10 * 1024 * 1024) typedef struct _state { int sock; int seq; long move; long msize; char *server; int fd; char *buf; } state_t; void server_main(); void client_main(int parallel, state_t *state); void init(iter_t iterations, void *cookie); void cleanup(iter_t iterations, void *cookie); void loop_transfer(iter_t iterations, void *cookie); int main(int ac, char **av) { int parallel = 1; int warmup = 0; int repetitions = -1; int server = 0; state_t state; char *usage = "-s\n OR [-m ] [-W ] [-N ] server [size]\n OR -S serverhost\n"; int c; uint64 usecs; state.msize = 0; state.move = 10*1024*1024; /* Rest is client argument processing */ while (( c = getopt(ac, av, "sS:m:W:N:")) != EOF) { switch(c) { case 's': /* Server */ if (fork() == 0) { server_main(); } exit(0); case 'S': /* shutdown serverhost */ { int seq, n; int sock = udp_connect(optarg, UDP_XACT, SOCKOPT_NONE); for (n = -1; n > -5; --n) { seq = htonl(n); (void) send(sock, &seq, sizeof(int), 0); } close(sock); exit (0); } case 'm': state.msize = atoi(optarg); break; case 'W': warmup = atoi(optarg); break; case 'N': repetitions = atoi(optarg); break; default: lmbench_usage(ac, av, usage); break; } } if (optind < ac - 2 || optind >= ac) { lmbench_usage(ac, av, usage); } state.server = av[optind++]; if (optind < ac) { state.move = bytes(av[optind]); } if (state.msize == 0) { state.msize = state.move; } /* make the number of bytes to move a multiple of the message size */ if (state.move % state.msize) { state.move += state.move - state.move % state.msize; } state.buf = valloc(state.msize); if (!state.buf) { perror("valloc"); exit(1); } touch(state.buf, state.msize); /* * Make one run take at least 5 seconds. * This minimizes the effect of connect & reopening TCP windows. */ benchmp(init, loop_transfer, cleanup, LONGER, parallel, warmup, repetitions, &state ); out: (void)fprintf(stderr, "socket UDP bandwidth using %s: ", state.server); mb(state.move * get_n() * parallel); } void init(iter_t iterations, void* cookie) { state_t *state = (state_t *) cookie; if (iterations) return; state->sock = udp_connect(state->server, UDP_XACT, SOCKOPT_NONE); state->seq = 0; state->buf = (char*)malloc(state->msize); } void loop_transfer(iter_t iterations, void *cookie) { state_t *state = (state_t *) cookie; char *server = state->server; int sock = state->sock; long control[2], nbytes; nbytes = state->move; control[0] = state->move; control[1] = state->msize; while (iterations-- > 0) { if (send(sock, control, 2 * sizeof(long), 0) != 2 * sizeof(long)) { perror("bw_udp client: send failed"); exit(5); } while (nbytes > 0) { if (recv(sock, state->buf, state->msize, 0) != state->msize) { perror("bw_udp client: recv failed"); exit(5); } nbytes -= state->msize; } } } void cleanup(iter_t iterations, void* cookie) { state_t *state = (state_t *) cookie; if (iterations) return; close(state->sock); free(state->buf); } void server_main() { char *buf = (char*)valloc(MAX_MSIZE); int sock, namelen, seq = 0; long nbytes, msize; struct sockaddr_in it; GO_AWAY; sock = udp_server(UDP_XACT, SOCKOPT_NONE); while (1) { namelen = sizeof(it); if (recvfrom(sock, (void*)buf, 2 * sizeof(long), 0, (struct sockaddr*)&it, &namelen) < 0) { fprintf(stderr, "bw_udp server: recvfrom: got wrong size\n"); exit(9); } nbytes = ntohl(*(long*)buf); msize = ntohl(*((long*)buf + 1)); while (nbytes > 0) { if (sendto(sock, (void*)buf, msize, 0, (struct sockaddr*)&it, sizeof(it)) < 0) { perror("bw_udp sendto"); exit(9); } nbytes -= msize; } } }