rx-add-performance-testing-client-20011206

add rxperf with modified license which allows us to distribute it now
pending more useful OpenAFS documentation existing at some point in the
future.
This commit is contained in:
Love Hörnquist-Åstrand 2001-12-06 23:39:08 +00:00 committed by Derrick Brashear
parent c5cd875222
commit 18f5f636dd
2 changed files with 936 additions and 0 deletions

View File

@ -69,6 +69,8 @@ ${MULTIOBJS}: rx.h rx_multi.h
${XDROBJS}: xdr.h
rxperf.o: rx.h rx_null.h rx_globals.h
rx_user.o: rx.h rx_user.h
rx_packet.o: rx_packet.c rx_packet.h
@ -89,6 +91,9 @@ xdr_rx.o: xdr.h rx.h
xdr_refernce.o: xdr_refernce.c xdr.h
rxperf: rxperf.o librx.a
${CC} -o $@ rxperf.o ${LIBS}
librx.a: ${LIBOBJS} RX_component_version_number.o
-$(RM) -f $@
$(AR) crv $@ ${LIBOBJS} RX_component_version_number.o

931
src/rx/rxperf.c Normal file
View File

@ -0,0 +1,931 @@
/*
* Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution
* at such time that OpenAFS documentation is written.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/*
nn * We are using getopt since we want it to be possible to link to
* transarc libs.
*/
#ifdef RCSID
RCSID("$Id$");
#endif
#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#ifdef HAVE_ERRX
#include <err.h> /* not stricly right, but if we have a errx() there
* is hopefully a err.h */
#endif
#include "rx.h"
#include "rx_null.h"
#include "rx_globals.h"
#if defined(u_int32)
#define u_int32_t u_int32
#elif defined(hget32)
#define u_int32_t afs_uint32
#endif
static const char *__progname;
#ifndef HAVE_WARNX
static void
warnx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s: ", __progname);
vfprintf (stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
#endif /* !HAVE_WARNX */
#ifndef HAVE_ERRX
static void
errx(int eval, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s: ", __progname);
vfprintf (stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(eval);
}
#endif /* !HAVE_ERRX */
#ifndef HAVE_WARN
static void
warn(const char *fmt, ...)
{
va_list args;
char *errstr;
va_start(args, fmt);
fprintf(stderr, "%s: ", __progname);
vfprintf (stderr, fmt, args);
errstr = strerror(errno);
fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
va_end(args);
}
#endif /* !HAVE_WARN */
#ifndef HAVE_ERR
static void
err(int eval, const char *fmt, ...)
{
va_list args;
char *errstr;
va_start(args, fmt);
fprintf(stderr, "%s: ", __progname);
vfprintf (stderr, fmt, args);
errstr = strerror(errno);
fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
va_end(args);
exit(eval);
}
#endif /* !HAVE_ERR */
#define DEFAULT_PORT 7009 /* To match tcpdump */
#define DEFAULT_HOST "127.0.0.1"
#define DEFAULT_BYTES 1000000
#define RXPERF_BUFSIZE 10000
enum { RX_PERF_VERSION = 3 };
enum { RX_SERVER_ID = 147 };
enum { RX_PERF_UNKNOWN = -1, RX_PERF_SEND = 0, RX_PERF_RECV = 1,
RX_PERF_RPC=3, RX_PERF_FILE=4 };
enum { RXPERF_MAGIC_COOKIE = 0x4711 };
/*
*
*/
#if DEBUG
#define DBFPRINT(x) do { printf x ; } while(0)
#else
#define DBFPRINT(x)
#endif
static void
sigusr1 (int foo)
{
exit (2); /* XXX profiler */
}
static void
sigint (int foo)
{
rx_Finalize();
exit (2); /* XXX profiler */
}
/*
*
*/
static struct timeval timer_start;
static struct timeval timer_stop;
static int timer_check = 0;
static void
start_timer (void)
{
timer_check++;
gettimeofday (&timer_start, NULL);
}
/*
*
*/
static void
end_and_print_timer (char *str)
{
long long start_l, stop_l;
timer_check--;
assert (timer_check == 0);
gettimeofday(&timer_stop, NULL);
start_l = timer_start.tv_sec * 1000000 + timer_start.tv_usec;
stop_l = timer_stop.tv_sec * 1000000 + timer_stop.tv_usec;
printf("%s:\t%8llu msec\n", str, (stop_l-start_l)/1000);
}
/*
*
*/
static u_long
str2addr (const char *s)
{
struct in_addr server;
struct hostent *h;
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
if (inet_addr(s) != INADDR_NONE)
return inet_addr(s);
h = gethostbyname (s);
if (h != NULL) {
memcpy (&server, h->h_addr_list[0], sizeof(server));
return server.s_addr;
}
return 0;
}
/*
*
*/
static void
get_sec(int serverp, struct rx_securityClass** sec, int *secureindex)
{
if (serverp) {
*sec = rxnull_NewServerSecurityObject();
*secureindex = 1;
} else {
*sec = rxnull_NewClientSecurityObject();
*secureindex = 0;
}
}
/*
* process the "RPC" and return the results
*/
char somebuf[RXPERF_BUFSIZE];
int32_t rxwrite_size = sizeof(somebuf);
int32_t rxread_size = sizeof(somebuf);
static int
readbytes(struct rx_call *call, int32_t bytes)
{
int32_t size;
while (bytes > 0) {
size = rxread_size;
if (size > bytes)
size = bytes;
if (rx_Read (call, somebuf, size) != size)
return 1;
bytes -= size;
}
return 0;
}
static int
sendbytes(struct rx_call *call, int32_t bytes)
{
int32_t size;
while (bytes > 0) {
size = rxwrite_size;
if (size > bytes)
size = bytes;
if (rx_Write (call, somebuf, size) != size)
return 1;
bytes -= size;
}
return 0;
}
static int32_t
rxperf_ExecuteRequest(struct rx_call *call)
{
int32_t version;
int32_t command;
u_int32_t bytes;
u_int32_t recvb;
u_int32_t sendb;
u_int32_t data;
u_int32_t num;
u_int32_t *readwrite;
int i;
int readp=TRUE;
DBFPRINT(("got a request\n"));
if (rx_Read (call, &version, 4) != 4) {
warn ("rx_Read failed to read version");
return -1;
}
if (htonl(RX_PERF_VERSION) != version) {
warnx ("client has wrong version");
return -1;
}
if (rx_Read (call, &command, 4) != 4) {
warnx ("rx_Read failed to read command");
return -1;
}
command = ntohl(command);
if (rx_Read (call, &data, 4) != 4) {
warnx ("rx_Read failed to read size");
return -1;
}
rxread_size = ntohl(data);
if (rxread_size > sizeof(somebuf)) {
warnx("rxread_size too large %d", rxread_size);
return -1;
}
if (rx_Read (call, &data, 4) != 4) {
warnx ("rx_Read failed to write size");
return -1;
}
rxwrite_size = ntohl(data);
if (rxwrite_size > sizeof(somebuf)) {
warnx("rxwrite_size too large %d", rxwrite_size);
return -1;
}
switch (command) {
case RX_PERF_SEND:
DBFPRINT(("got a send request\n"));
if (rx_Read (call, &bytes, 4) != 4) {
warnx ("rx_Read failed to read bytes");
return -1;
}
bytes = ntohl(bytes);
DBFPRINT(("reading(%d) ", bytes));
readbytes(call, bytes);
data = htonl(RXPERF_MAGIC_COOKIE);
if (rx_Write (call, &data, 4) != 4) {
warnx ("rx_Write failed when sending back result");
return -1;
}
DBFPRINT(("done\n"));
break;
case RX_PERF_RPC:
DBFPRINT(("got a rpc request, reading commands\n"));
if (rx_Read (call, &recvb, 4) != 4) {
warnx ("rx_Read failed to read recvbytes");
return -1;
}
recvb = ntohl(recvb);
if (rx_Read (call, &sendb, 4) != 4) {
warnx ("rx_Read failed to read sendbytes");
return -1;
}
sendb = ntohl(sendb);
DBFPRINT(("read(%d) ", recvb));
if (readbytes(call, recvb)) {
warnx("readbytes failed");
return -1;
}
DBFPRINT(("send(%d) ", sendb));
if (sendbytes(call, sendb)) {
warnx("sendbytes failed");
return -1;
}
DBFPRINT(("done\n"));
data = htonl(RXPERF_MAGIC_COOKIE);
if (rx_Write (call, &data, 4) != 4) {
warnx ( "rx_Write failed when sending back magic cookie");
return -1;
}
break;
case RX_PERF_FILE:
if (rx_Read (call, &data, 4) != 4)
errx (1, "failed to read num from client");
num = ntohl(data);
readwrite = malloc(num*sizeof(u_int32_t));
if(readwrite == NULL)
err(1, "malloc");
if (rx_Read (call, readwrite, num*sizeof(u_int32_t)) !=
num*sizeof(u_int32_t))
errx (1, "failed to read recvlist from client");
for(i=0; i < num; i++) {
if(readwrite[i] == 0) {
DBFPRINT(("readp %d", readwrite[i] ));
readp = !readp;
}
bytes = ntohl(readwrite[i])*sizeof(u_int32_t);
if(readp) {
DBFPRINT(("read\n"));
readbytes(call, bytes);
} else {
sendbytes(call, bytes);
DBFPRINT(("send\n"));
}
}
break;
case RX_PERF_RECV:
DBFPRINT(("got a recv request\n"));
if (rx_Read (call, &bytes, 4) != 4) {
warnx ("rx_Read failed to read bytes");
return -1;
}
bytes = ntohl(bytes);
DBFPRINT(("sending(%d) ", bytes));
sendbytes(call, bytes);
data = htonl(RXPERF_MAGIC_COOKIE);
if (rx_Write (call, &data, 4) != 4) {
warnx ("rx_Write failed when sending back result");
return -1;
}
DBFPRINT(("done\n"));
break;
default:
warnx ("client sent a unsupported command");
return -1;
}
DBFPRINT(("done with command\n"));
return 0;
}
/*
*
*/
static void
do_server (int port)
{
struct rx_service *service;
struct rx_securityClass *secureobj;
int secureindex;
int ret;
ret = rx_Init (port);
if (ret)
errx (1, "rx_Init failed");
get_sec(1, &secureobj, &secureindex);
service = rx_NewService (0,
RX_SERVER_ID,
"rxperf",
&secureobj,
secureindex,
rxperf_ExecuteRequest);
if (service == NULL)
errx(1, "Cant create server");
rx_StartServer(1) ;
abort();
}
/*
*
*/
static void
readfile(const char *filename, u_int32_t **readwrite, u_int32_t *size)
{
FILE *f;
u_int32_t len=16;
u_int32_t num=0;
u_int32_t data;
char *ptr;
char buf[RXPERF_BUFSIZE];
*readwrite = malloc(sizeof(u_int32_t)*len);
if(*readwrite == NULL)
err(1, "malloc");
f=fopen(filename, "r");
if(f==NULL)
err(1, "fopen");
while(fgets(buf, sizeof(buf), f) != NULL) {
if(num >= len) {
len=len*2;
*readwrite = realloc(*readwrite, len*sizeof(u_int32_t));
if(*readwrite == NULL)
err(1, "realloc");
}
if(*buf != '\n') {
data = htonl(strtol (buf, &ptr, 0));
if (ptr && ptr == buf)
errx (1, "can't resolve number of bytes to transfer");
} else {
data = 0;
}
(*readwrite)[num] =data;
num++;
}
*size = num;
if(fclose(f) == -1)
err(1, "fclose");
}
/*
*
*/
static void
do_client (const char *server, int port, char *filename,
int32_t command, int32_t times,
int32_t bytes, int32_t sendtimes, int32_t recvtimes)
{
struct rx_connection *conn;
struct rx_call *call;
u_int32_t addr = str2addr(server);
struct rx_securityClass *secureobj;
int secureindex;
int32_t data;
int32_t num;
int ret;
int i;
int readp = FALSE;
char stamp[1024];
u_int32_t size;
u_int32_t *readwrite;
ret = rx_Init (0);
if (ret)
errx (1, "rx_Init failed");
get_sec(0, &secureobj, &secureindex);
conn = rx_NewConnection(addr,
port,
RX_SERVER_ID,
secureobj,
secureindex);
if (conn == NULL)
errx (1, "failed to contact server");
sprintf (stamp, "send\t%d times\t%d writes\t%d reads", times, sendtimes, recvtimes);
start_timer();
for(i=0; i < times ; i++) {
DBFPRINT(("starting command "));
call = rx_NewCall (conn);
if (call == NULL)
errx (1, "rx_NewCall failed");
data = htonl(RX_PERF_VERSION);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send version");
data = htonl(command);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send command");
data = htonl(rxread_size);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send read size");
data = htonl(rxwrite_size);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send write read");
switch (command) {
case RX_PERF_RECV:
DBFPRINT(("command "));
data = htonl (bytes);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send size");
DBFPRINT(("sending(%d) ", bytes));
if (readbytes(call, bytes))
errx(1, "sendbytes");
if (rx_Read (call, &data, 4) != 4)
errx (1, "failed to read result from server");
if (data != htonl(RXPERF_MAGIC_COOKIE))
warn("server send wrong magic cookie in responce");
DBFPRINT(("done\n"));
break;
case RX_PERF_SEND:
DBFPRINT(("command "));
data = htonl (bytes);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send size");
DBFPRINT(("sending(%d) ", bytes));
if (sendbytes(call, bytes))
errx(1, "sendbytes");
if (rx_Read (call, &data, 4) != 4)
errx (1, "failed to read result from server");
if (data != htonl(RXPERF_MAGIC_COOKIE))
warn("server send wrong magic cookie in responce");
DBFPRINT(("done\n"));
break;
case RX_PERF_RPC:
DBFPRINT(("commands "));
data = htonl(sendtimes);
if (rx_Write(call, &data, 4) != 4)
errx (1, "rx_Write failed to send command");
data = htonl(recvtimes);
if (rx_Write (call, &data, 4) != 4)
errx (1, "rx_Write failed to send command");
DBFPRINT(("send(%d) ", sendtimes));
sendbytes(call, sendtimes);
DBFPRINT(("recv(%d) ", recvtimes));
readbytes(call, recvtimes);
if (rx_Read (call, &bytes, 4) != 4)
errx (1, "failed to read result from server");
if (bytes != htonl(RXPERF_MAGIC_COOKIE))
warn("server send wrong magic cookie in responce");
DBFPRINT(("done\n"));
break;
case RX_PERF_FILE:
readfile(filename, &readwrite, &num);
data = htonl(num);
if (rx_Write(call, &data, sizeof(data)) != 4)
errx (1, "rx_Write failed to send size");
if (rx_Write(call, readwrite, num*sizeof(u_int32_t))
!= num*sizeof(u_int32_t))
errx (1, "rx_Write failed to send list");
for(i=0; i < num; i++) {
if(readwrite[i] == 0)
readp = !readp;
size = ntohl(readwrite[i])*sizeof(u_int32_t);
if(readp) {
readbytes(call, size);
DBFPRINT(("read\n"));
} else {
sendbytes(call, size);
DBFPRINT(("send\n"));
}
}
break;
default:
abort();
}
rx_EndCall (call, 0);
}
end_and_print_timer (stamp);
DBFPRINT(("done for good\n"));
rx_Finalize();
}
static void
usage()
{
#define COMMON ""
fprintf(stderr, "usage: %s client -c send -b <bytes>\n",
__progname);
fprintf(stderr, "usage: %s client -c recv -b <bytes>\n",
__progname);
fprintf(stderr, "usage: %s client -c rpc -S <sendbytes> -R <recvbytes>\n",
__progname);
fprintf(stderr, "usage: %s client -c file -f filename\n",
__progname);
fprintf (stderr, "%s: usage: common option to the client "
"-w <write-bytes> -r <read-bytes> -T times -p port -s server\n",
__progname);
fprintf(stderr, "usage: %s server -p port\n", __progname);
#undef COMMMON
exit(1);
}
/*
* do argument processing and call networking functions
*/
static int
rxperf_server (int argc, char **argv)
{
int port = DEFAULT_PORT;
char *ptr;
int ch;
while ((ch = getopt(argc, argv, "r:d:p:w:")) != -1) {
switch (ch) {
case 'd':
#ifdef RXDEBUG
rx_debugFile = fopen(optarg, "w");
if (rx_debugFile == NULL)
err(1, "fopen %s", optarg);
#else
errx(1, "compiled without RXDEBUG");
#endif
break;
case 'r':
rxread_size = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve readsize");
if (rxread_size > sizeof(somebuf))
errx(1, "%d > sizeof(somebuf) (%d)",
rxread_size, sizeof(somebuf));
break;
case 'p':
port = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve portname");
break;
case 'w':
rxwrite_size = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve writesize");
if (rxwrite_size > sizeof(somebuf))
errx(1, "%d > sizeof(somebuf) (%d)",
rxwrite_size, sizeof(somebuf));
break;
default:
usage();
}
}
if (optind != argc)
usage();
do_server (htons(port));
return 0;
}
/*
* do argument processing and call networking functions
*/
static int
rxperf_client (int argc, char **argv)
{
char *host = DEFAULT_HOST;
int bytes = DEFAULT_BYTES;
int port = DEFAULT_PORT;
char *filename = NULL;
int32_t cmd;
int sendtimes = 3;
int recvtimes = 30;
int times = 100;
char *ptr;
int ch;
cmd = RX_PERF_UNKNOWN;
while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:")) != -1) {
switch (ch) {
case 'b':
bytes = strtol (optarg, &ptr, 0);
if (ptr && *ptr != '\0')
errx (1, "can't resolve number of bytes to transfer");
break;
case 'c':
if (strcasecmp(optarg, "send") == 0)
cmd = RX_PERF_SEND;
else if (strcasecmp(optarg, "recv") == 0)
cmd = RX_PERF_RECV;
else if (strcasecmp(optarg, "rpc") == 0)
cmd = RX_PERF_RPC;
else if (strcasecmp(optarg, "file") == 0)
cmd = RX_PERF_FILE;
else
errx(1, "unknown command %s", optarg);
break;
case 'd':
#ifdef RXDEBUG
rx_debugFile = fopen(optarg, "w");
if (rx_debugFile == NULL)
err(1, "fopen %s", optarg);
#else
errx(1, "compiled without RXDEBUG");
#endif
break;
case 'p':
port = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve portname");
break;
case 'r':
rxread_size = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve readsize");
if (rxread_size > sizeof(somebuf))
errx(1, "%d > sizeof(somebuf) (%d)",
rxread_size, sizeof(somebuf));
break;
case 's':
host = strdup(optarg);
if (host == NULL)
err(1, "strdup");
break;
case 'w':
rxwrite_size = strtol(optarg, &ptr, 0);
if (ptr != 0 && ptr[0] != '\0')
errx (1, "can't resolve writesize");
if (rxwrite_size > sizeof(somebuf))
errx(1, "%d > sizeof(somebuf) (%d)",
rxwrite_size, sizeof(somebuf));
break;
case 'T':
times = strtol (optarg, &ptr, 0);
if (ptr && *ptr != '\0')
errx (1, "can't resolve number of bytes to transfer");
break;
case 'S':
sendtimes = strtol (optarg, &ptr, 0);
if (ptr && *ptr != '\0')
errx (1, "can't resolve number of bytes to transfer");
break;
case 'R':
recvtimes = strtol (optarg, &ptr, 0);
if (ptr && *ptr != '\0')
errx (1, "can't resolve number of bytes to transfer");
break;
case 'f':
filename = optarg;
break;
default:
usage();
}
}
if (optind != argc)
usage();
if (cmd == RX_PERF_UNKNOWN)
errx(1, "no command given to the client");
do_client(host, htons(port), filename, cmd, times, bytes,
sendtimes, recvtimes);
return 0;
}
/*
* setup world and call cmd
*/
int
main(int argc, char **argv)
{
PROCESS pid;
__progname = strrchr(argv[0], '/');
if (__progname == 0)
__progname = argv[0];
signal (SIGUSR1, sigusr1);
signal (SIGINT, sigint);
LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY, &pid);
memset (somebuf, 0, sizeof(somebuf));
if (argc >= 2 && strcmp(argv[1], "server") == 0)
rxperf_server(argc - 1, argv + 1);
else if (argc >= 2 && strcmp(argv[1], "client") == 0)
rxperf_client(argc - 1, argv + 1);
else
usage();
return 0;
}