rxperf: Build again
[openafs.git] / src / rx / test / rxperf.c
index de00160..f37ff9a 100644 (file)
@@ -39,8 +39,19 @@ nn * We are using getopt since we want it to be possible to link to
  * transarc libs.
  */
 
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
+
 #include <stdarg.h>
 #include <sys/types.h>
+#ifdef AFS_NT40_ENV
+#include <io.h>
+#include <winsock2.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <time.h>
+#else
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/file.h>
@@ -48,6 +59,7 @@ nn * We are using getopt since we want it to be possible to link to
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -67,14 +79,14 @@ nn * We are using getopt since we want it to be possible to link to
 #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
+#include <rx/rx.h>
+#include <rx/rx_null.h>
+#include <rx/rx_globals.h>
+#include <rx/rx_packet.h>
+
+#ifdef AFS_PTHREAD_ENV
+#include <pthread.h>
+#define MAX_THREADS 128
 #endif
 
 static const char *__progname;
@@ -149,13 +161,16 @@ err(int eval, const char *fmt, ...)
 
 #define DEFAULT_PORT 7009      /* To match tcpdump */
 #define DEFAULT_HOST "127.0.0.1"
-#define DEFAULT_BYTES 1000000
-#define RXPERF_BUFSIZE 10000
+#define DEFAULT_BYTES 1024 * 1024
+#define RXPERF_BUFSIZE 512 * 1024
 
 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 { 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 };
@@ -164,7 +179,7 @@ enum { RXPERF_MAGIC_COOKIE = 0x4711 };
  *
  */
 
-#if DEBUG
+#if RXPERF_DEBUG
 #define DBFPRINT(x) do { printf x ; } while(0)
 #else
 #define DBFPRINT(x)
@@ -261,29 +276,41 @@ get_sec(int serverp, struct rx_securityClass **sec, int *secureindex)
 
 char somebuf[RXPERF_BUFSIZE];
 
-int32_t rxwrite_size = sizeof(somebuf);
-int32_t rxread_size = sizeof(somebuf);
+afs_int32 rxwrite_size = sizeof(somebuf);
+afs_int32 rxread_size = sizeof(somebuf);
+afs_int32 use_rx_readv = 0;
 
 static int
-readbytes(struct rx_call *call, int32_t bytes)
+do_readbytes(struct rx_call *call, afs_int32 bytes)
 {
-    int32_t size;
+    struct iovec tiov[RX_MAXIOVECS];
+    afs_int32 size;
+    int tnio;
+    int code;
 
     while (bytes > 0) {
        size = rxread_size;
+
        if (size > bytes)
            size = bytes;
-       if (rx_Read(call, somebuf, size) != size)
-           return 1;
+       if (use_rx_readv) {
+            if (size > RX_MAX_PACKET_DATA_SIZE)
+                size = RX_MAX_PACKET_DATA_SIZE;
+            code = rx_Readv(call, tiov, &tnio, RX_MAXIOVECS, size);
+        } else
+            code = rx_Read(call, somebuf, size);
+        if (code != size)
+            return 1;
+
        bytes -= size;
     }
     return 0;
 }
 
 static int
-sendbytes(struct rx_call *call, int32_t bytes)
+do_sendbytes(struct rx_call *call, afs_int32 bytes)
 {
-    int32_t size;
+    afs_int32 size;
 
     while (bytes > 0) {
        size = rxwrite_size;
@@ -297,18 +324,18 @@ sendbytes(struct rx_call *call, int32_t bytes)
 }
 
 
-static int32_t
+static afs_int32
 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;
+    afs_int32 version;
+    afs_int32 command;
+    afs_int32 bytes;
+    afs_int32 recvb;
+    afs_int32 sendb;
+    afs_int32 data;
+    afs_uint32 num;
+    afs_uint32 *readwrite;
+    afs_uint32 i;
     int readp = TRUE;
 
     DBFPRINT(("got a request\n"));
@@ -360,7 +387,7 @@ rxperf_ExecuteRequest(struct rx_call *call)
        bytes = ntohl(bytes);
 
        DBFPRINT(("reading(%d) ", bytes));
-       readbytes(call, bytes);
+       do_readbytes(call, bytes);
 
        data = htonl(RXPERF_MAGIC_COOKIE);
        if (rx_Write32(call, &data) != 4) {
@@ -385,12 +412,12 @@ rxperf_ExecuteRequest(struct rx_call *call)
        sendb = ntohl(sendb);
 
        DBFPRINT(("read(%d) ", recvb));
-       if (readbytes(call, recvb)) {
-           warnx("readbytes failed");
+       if (do_readbytes(call, recvb)) {
+           warnx("do_readbytes failed");
            return -1;
        }
        DBFPRINT(("send(%d) ", sendb));
-       if (sendbytes(call, sendb)) {
+       if (do_sendbytes(call, sendb)) {
            warnx("sendbytes failed");
            return -1;
        }
@@ -409,12 +436,12 @@ rxperf_ExecuteRequest(struct rx_call *call)
            errx(1, "failed to read num from client");
        num = ntohl(data);
 
-       readwrite = malloc(num * sizeof(u_int32_t));
+       readwrite = malloc(num * sizeof(afs_uint32));
        if (readwrite == NULL)
            err(1, "malloc");
 
-       if (rx_Read(call, readwrite, num * sizeof(u_int32_t)) !=
-           num * sizeof(u_int32_t))
+       if (rx_Read(call, (char*)readwrite, num * sizeof(afs_uint32)) !=
+           num * sizeof(afs_uint32))
            errx(1, "failed to read recvlist from client");
 
        for (i = 0; i < num; i++) {
@@ -423,13 +450,13 @@ rxperf_ExecuteRequest(struct rx_call *call)
                readp = !readp;
            }
 
-           bytes = ntohl(readwrite[i]) * sizeof(u_int32_t);
+           bytes = ntohl(readwrite[i]) * sizeof(afs_uint32);
 
            if (readp) {
                DBFPRINT(("read\n"));
-               readbytes(call, bytes);
+               do_readbytes(call, bytes);
            } else {
-               sendbytes(call, bytes);
+               do_sendbytes(call, bytes);
                DBFPRINT(("send\n"));
            }
        }
@@ -445,7 +472,7 @@ rxperf_ExecuteRequest(struct rx_call *call)
        bytes = ntohl(bytes);
 
        DBFPRINT(("sending(%d) ", bytes));
-       sendbytes(call, bytes);
+       do_sendbytes(call, bytes);
 
        data = htonl(RXPERF_MAGIC_COOKIE);
        if (rx_Write32(call, &data) != 4) {
@@ -469,21 +496,49 @@ rxperf_ExecuteRequest(struct rx_call *call)
  */
 
 static void
-do_server(int port, int nojumbo, int maxmtu)
+do_server(short port, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
+          int udpbufsz, int nostats, int hotthread,
+          int minprocs, int maxprocs)
 {
     struct rx_service *service;
     struct rx_securityClass *secureobj;
     int secureindex;
     int ret;
 
-    ret = rx_Init(port);
+#ifdef AFS_NT40_ENV
+    if (afs_winsockInit() < 0) {
+       printf("Can't initialize winsock.\n");
+       exit(1);
+    }
+#endif
+
+    if (hotthread)
+        rx_EnableHotThread();
+
+    if (nostats)
+        rx_enable_stats = 0;
+
+    rx_SetUdpBufSize(udpbufsz);
+
+    ret = rx_Init(htons(port));
     if (ret)
        errx(1, "rx_Init failed");
 
     if (nojumbo)
       rx_SetNoJumbo();
+
     if (maxmtu)
       rx_SetMaxMTU(maxmtu);
+
+    if (maxwsize) {
+        rx_SetMaxReceiveWindow(maxwsize);
+        rx_SetMaxSendWindow(maxwsize);
+    }
+
+    if (minpeertimeout)
+        rx_SetMinPeerTimeout(minpeertimeout);
+
+
     get_sec(1, &secureobj, &secureindex);
 
     service =
@@ -492,7 +547,13 @@ do_server(int port, int nojumbo, int maxmtu)
     if (service == NULL)
        errx(1, "Cant create server");
 
+    rx_SetMinProcs(service, minprocs);
+    rx_SetMaxProcs(service, maxprocs);
+
+    rx_SetCheckReach(service, 1);
+
     rx_StartServer(1);
+
     abort();
 }
 
@@ -501,16 +562,17 @@ do_server(int port, int nojumbo, int maxmtu)
  */
 
 static void
-readfile(const char *filename, u_int32_t ** readwrite, u_int32_t * size)
+readfile(const char *filename, afs_uint32 ** readwrite, afs_uint32 * size)
 {
     FILE *f;
-    u_int32_t len = 16;
-    u_int32_t num = 0;
-    u_int32_t data;
+    afs_uint32 len = 16;
+    afs_uint32 num = 0;
+    afs_uint32 data;
     char *ptr;
-    char buf[RXPERF_BUFSIZE];
+    char *buf;
 
-    *readwrite = malloc(sizeof(u_int32_t) * len);
+    *readwrite = malloc(sizeof(afs_uint32) * len);
+    buf = malloc(RXPERF_BUFSIZE);
 
     if (*readwrite == NULL)
        err(1, "malloc");
@@ -522,7 +584,7 @@ readfile(const char *filename, u_int32_t ** readwrite, u_int32_t * size)
     while (fgets(buf, sizeof(buf), f) != NULL) {
        if (num >= len) {
            len = len * 2;
-           *readwrite = realloc(*readwrite, len * sizeof(u_int32_t));
+           *readwrite = realloc(*readwrite, len * sizeof(afs_uint32));
            if (*readwrite == NULL)
                err(1, "realloc");
        }
@@ -544,56 +606,36 @@ readfile(const char *filename, u_int32_t ** readwrite, u_int32_t * size)
 
     if (fclose(f) == -1)
        err(1, "fclose");
+    free(buf);
 }
 
+struct client_data {
+    struct rx_connection *conn;
+    char *filename;
+    int command;
+    afs_int32 times;
+    afs_int32 bytes;
+    afs_int32 sendbytes;
+    afs_int32 readbytes;
+};
 
-/*
- *
- */
-
-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,
-          int dumpstats, int nojumbo, int maxmtu)
+static void *
+client_thread( void *vparams)
 {
-    struct rx_connection *conn;
+    struct client_data *params = (struct client_data *)vparams;
     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;
+    afs_int32 data;
+    int i, j;
+    afs_uint32 *readwrite;
     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");
+    afs_uint32 size;
+    afs_uint32 num;
 
-    if (nojumbo)
-      rx_SetNoJumbo();
-    if (maxmtu)
-      rx_SetMaxMTU(maxmtu);
-    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++) {
+    for (i = 0; i < params->times; i++) {
 
        DBFPRINT(("starting command "));
 
-       call = rx_NewCall(conn);
+       call = rx_NewCall(params->conn);
        if (call == NULL)
            errx(1, "rx_NewCall failed");
 
@@ -601,7 +643,7 @@ do_client(const char *server, int port, char *filename, int32_t command,
        if (rx_Write32(call, &data) != 4)
            errx(1, "rx_Write failed to send version (err %d)", rx_Error(call));
 
-       data = htonl(command);
+       data = htonl(params->command);
        if (rx_Write32(call, &data) != 4)
            errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
 
@@ -613,16 +655,16 @@ do_client(const char *server, int port, char *filename, int32_t command,
            errx(1, "rx_Write failed to send write read (err %d)", rx_Error(call));
 
 
-       switch (command) {
+       switch (params->command) {
        case RX_PERF_RECV:
            DBFPRINT(("command "));
 
-           data = htonl(bytes);
+           data = htonl(params->bytes);
            if (rx_Write32(call, &data) != 4)
                errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
 
-           DBFPRINT(("sending(%d) ", bytes));
-           if (readbytes(call, bytes))
+           DBFPRINT(("sending(%d) ", params->bytes));
+           if (do_readbytes(call, params->bytes))
                errx(1, "sendbytes (err %d)", rx_Error(call));
 
            if (rx_Read32(call, &data) != 4)
@@ -637,12 +679,12 @@ do_client(const char *server, int port, char *filename, int32_t command,
        case RX_PERF_SEND:
            DBFPRINT(("command "));
 
-           data = htonl(bytes);
+           data = htonl(params->bytes);
            if (rx_Write32(call, &data) != 4)
                errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
 
-           DBFPRINT(("sending(%d) ", bytes));
-           if (sendbytes(call, bytes))
+           DBFPRINT(("sending(%d) ", params->bytes));
+           if (do_sendbytes(call, params->bytes))
                errx(1, "sendbytes (err %d)", rx_Error(call));
 
            if (rx_Read32(call, &data) != 4)
@@ -657,54 +699,55 @@ do_client(const char *server, int port, char *filename, int32_t command,
        case RX_PERF_RPC:
            DBFPRINT(("commands "));
 
-           data = htonl(sendtimes);
+           data = htonl(params->sendbytes);
            if (rx_Write32(call, &data) != 4)
                errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
 
-           data = htonl(recvtimes);
+           data = htonl(params->readbytes);
            if (rx_Write32(call, &data) != 4)
                errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
 
-           DBFPRINT(("send(%d) ", sendtimes));
-           if (sendbytes(call, sendtimes))
+           DBFPRINT(("send(%d) ", params->sendbytes));
+           if (do_sendbytes(call, params->sendbytes))
                errx(1, "sendbytes (err %d)", rx_Error(call));
 
-           DBFPRINT(("recv(%d) ", recvtimes));
-           if (readbytes(call, recvtimes))
+           DBFPRINT(("recv(%d) ", params->readbytes));
+           if (do_readbytes(call, params->readbytes))
                errx(1, "sendbytes (err %d)", rx_Error(call));
 
-           if (rx_Read32(call, &bytes) != 4)
+           if (rx_Read32(call, &data) != 4)
                errx(1, "failed to read result from server (err %d)", rx_Error(call));
 
-           if (bytes != htonl(RXPERF_MAGIC_COOKIE))
+           if (data != htonl(RXPERF_MAGIC_COOKIE))
                warn("server send wrong magic cookie in responce");
 
            DBFPRINT(("done\n"));
 
            break;
+
        case RX_PERF_FILE:
-           readfile(filename, &readwrite, &num);
+           readfile(params->filename, &readwrite, &num);
 
            data = htonl(num);
            if (rx_Write32(call, &data) != 4)
                errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
 
-           if (rx_Write(call, readwrite, num * sizeof(u_int32_t))
-               != num * sizeof(u_int32_t))
+           if (rx_Write(call, (char *)readwrite, num * sizeof(afs_uint32))
+               != num * sizeof(afs_uint32))
                errx(1, "rx_Write failed to send list (err %d)", rx_Error(call));
 
-           for (i = 0; i < num; i++) {
-               if (readwrite[i] == 0)
+           for (j = 0; j < num; j++) {
+               if (readwrite[j] == 0)
                    readp = !readp;
 
-               size = ntohl(readwrite[i]) * sizeof(u_int32_t);
+               size = ntohl(readwrite[j]) * sizeof(afs_uint32);
 
                if (readp) {
-                   if (readbytes(call, size))
+                   if (do_readbytes(call, size))
                        errx(1, "sendbytes (err %d)", rx_Error(call));
                    DBFPRINT(("read\n"));
                } else {
-                   if (sendbytes(call, size))
+                   if (do_sendbytes(call, size))
                        errx(1, "sendbytes (err %d)", rx_Error(call));
                    DBFPRINT(("send\n"));
                }
@@ -717,18 +760,157 @@ do_client(const char *server, int port, char *filename, int32_t command,
        rx_EndCall(call, 0);
     }
 
+#ifdef AFS_PTHREAD_ENV
+    pthread_exit(NULL);
+#endif
+
+    return NULL;
+}
+
+/*
+ *
+ */
+
+static void
+do_client(const char *server, short port, char *filename, afs_int32 command,
+         afs_int32 times, afs_int32 bytes, afs_int32 sendbytes, afs_int32 readbytes,
+          int dumpstats, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
+          int udpbufsz, int nostats, int hotthread, int threads)
+{
+    struct rx_connection *conn;
+    afs_uint32 addr;
+    struct rx_securityClass *secureobj;
+    int secureindex;
+    int ret;
+    char stamp[2048];
+    struct client_data *params;
+
+#ifdef AFS_PTHREAD_ENV
+    int i;
+    pthread_t thread[MAX_THREADS];
+    pthread_attr_t tattr;
+    void *status;
+#endif
+
+    params = malloc(sizeof(struct client_data));
+    memset(params, 0, sizeof(struct client_data));
+
+#ifdef AFS_NT40_ENV
+    if (afs_winsockInit() < 0) {
+       printf("Can't initialize winsock.\n");
+       exit(1);
+    }
+#endif
+
+    if (hotthread)
+        rx_EnableHotThread();
+
+    if (nostats)
+        rx_enable_stats = 0;
+
+    addr = str2addr(server);
+
+    rx_SetUdpBufSize(udpbufsz);
+
+    ret = rx_Init(0);
+    if (ret)
+       errx(1, "rx_Init failed");
+
+    if (nojumbo)
+      rx_SetNoJumbo();
+
+    if (maxmtu)
+      rx_SetMaxMTU(maxmtu);
+
+    if (maxwsize) {
+        rx_SetMaxReceiveWindow(maxwsize);
+        rx_SetMaxSendWindow(maxwsize);
+    }
+
+    if (minpeertimeout)
+        rx_SetMinPeerTimeout(minpeertimeout);
+
+
+    get_sec(0, &secureobj, &secureindex);
+
+    switch (command) {
+    case RX_PERF_RPC:
+        sprintf(stamp, "RPC: threads\t%d, times\t%d, write bytes\t%d, read bytes\t%d",
+                 threads, times, sendbytes, readbytes);
+        break;
+    case RX_PERF_RECV:
+        sprintf(stamp, "RECV: threads\t%d, times\t%d, bytes\t%d",
+                 threads, times, bytes);
+        break;
+    case RX_PERF_SEND:
+        sprintf(stamp, "SEND: threads\t%d, times\t%d, bytes\t%d",
+                 threads, times, bytes);
+        break;
+    case RX_PERF_FILE:
+        sprintf(stamp, "FILE %s: threads\t%d, times\t%d, bytes\t%d",
+                 filename, threads, times, bytes);
+        break;
+    }
+
+    conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
+    if (conn == NULL)
+       errx(1, "failed to contact server");
+
+#ifdef AFS_PTHREAD_ENV
+    pthread_attr_init(&tattr);
+    pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
+#endif
+
+    params->conn = conn;
+    params->filename = filename;
+    params->command = command;
+    params->times = times;
+    params->bytes = bytes;
+    params->sendbytes = sendbytes;
+    params->readbytes = readbytes;
+
+    start_timer();
+
+#ifdef AFS_PTHREAD_ENV
+    for ( i=0; i<threads; i++) {
+        pthread_create(&thread[i], &tattr, client_thread, params);
+        if ( (i + 1) % RX_MAXCALLS == 0 ) {
+            conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
+            if (conn != NULL) {
+                struct client_data *new_params = malloc(sizeof(struct client_data));
+                memcpy(new_params, params, sizeof(struct client_data));
+                new_params->conn = conn;
+                params = new_params;
+            }
+        }
+    }
+#else
+        client_thread(params);
+#endif
+
+#ifdef AFS_PTHREAD_ENV
+    for ( i=0; i<threads; i++)
+        pthread_join(thread[i], &status);
+#endif
+
     end_and_print_timer(stamp);
     DBFPRINT(("done for good\n"));
 
     if (dumpstats) {
        rx_PrintStats(stdout);
-       rx_PrintPeerStats(stdout, conn->peer);
+       rx_PrintPeerStats(stdout, rx_PeerOf(conn));
     }
     rx_Finalize();
+
+#ifdef AFS_PTHREAD_ENV
+    pthread_attr_destroy(&tattr);
+#endif
+
+    free(params);
 }
 
 static void
-usage()
+usage(void)
 {
 #define COMMON ""
 
@@ -747,6 +929,8 @@ usage()
     exit(1);
 }
 
+
+
 /*
  * do argument processing and call networking functions
  */
@@ -754,13 +938,20 @@ usage()
 static int
 rxperf_server(int argc, char **argv)
 {
-    int port = DEFAULT_PORT;
+    short port = DEFAULT_PORT;
     int nojumbo = 0;
     int maxmtu = 0;
+    int nostats = 0;
+    int udpbufsz = 64 * 1024;
+    int hotthreads = 0;
+    int minprocs = 2;
+    int maxprocs = 20;
+    int maxwsize = 0;
+    int minpeertimeout = 0;
     char *ptr;
     int ch;
 
-    while ((ch = getopt(argc, argv, "r:d:p:w:jm:4")) != -1) {
+    while ((ch = getopt(argc, argv, "r:d:p:P:w:W:HNjm:u:4:s:S:V")) != -1) {
        switch (ch) {
        case 'd':
 #ifdef RXDEBUG
@@ -776,11 +967,26 @@ rxperf_server(int argc, char **argv)
            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,
+               errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
                     sizeof(somebuf));
            break;
+       case 's':
+           minprocs = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx(1, "can't resolve minprocs");
+           break;
+       case 'S':
+           maxprocs = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx(1, "can't resolve maxprocs");
+           break;
+       case 'P':
+           minpeertimeout = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx(1, "can't resolve min peer timeout");
+           break;
        case 'p':
-           port = strtol(optarg, &ptr, 0);
+           port = (short) strtol(optarg, &ptr, 0);
            if (ptr != 0 && ptr[0] != '\0')
                errx(1, "can't resolve portname");
            break;
@@ -789,17 +995,36 @@ rxperf_server(int argc, char **argv)
            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,
+               errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
                     sizeof(somebuf));
            break;
        case 'j':
          nojumbo=1;
          break;
+       case 'N':
+         nostats=1;
+         break;
+       case 'H':
+           hotthreads = 1;
+           break;
        case 'm':
          maxmtu = strtol(optarg, &ptr, 0);
          if (ptr && *ptr != '\0')
            errx(1, "can't resolve rx maxmtu to use");
            break;
+       case 'u':
+           udpbufsz = strtol(optarg, &ptr, 0) * 1024;
+           if (ptr && *ptr != '\0')
+               errx(1, "can't resolve upd buffer size (Kbytes)");
+           break;
+       case 'V':
+           use_rx_readv = 1;
+           break;
+       case 'W':
+           maxwsize = strtol(optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx(1, "can't resolve max send/recv window size (packets)");
+           break;
        case '4':
          RX_IPUDP_SIZE = 28;
          break;
@@ -811,7 +1036,8 @@ rxperf_server(int argc, char **argv)
     if (optind != argc)
        usage();
 
-    do_server(htons(port), nojumbo, maxmtu);
+    do_server(port, nojumbo, maxmtu, maxwsize, minpeertimeout, udpbufsz,
+              nostats, hotthreads, minprocs, maxprocs);
 
     return 0;
 }
@@ -825,21 +1051,27 @@ rxperf_client(int argc, char **argv)
 {
     char *host = DEFAULT_HOST;
     int bytes = DEFAULT_BYTES;
-    int port = DEFAULT_PORT;
+    short port = DEFAULT_PORT;
     char *filename = NULL;
-    int32_t cmd;
-    int sendtimes = 3;
-    int recvtimes = 30;
+    afs_int32 cmd;
+    int sendbytes = 3;
+    int readbytes = 30;
     int times = 100;
     int dumpstats = 0;
     int nojumbo = 0;
+    int nostats = 0;
     int maxmtu = 0;
+    int hotthreads = 0;
+    int threads = 1;
+    int udpbufsz = 64 * 1024;
+    int maxwsize = 0;
+    int minpeertimeout = 0;
     char *ptr;
     int ch;
 
     cmd = RX_PERF_UNKNOWN;
 
-    while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:Djm:4")) != -1) {
+    while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:P:r:s:w:W:f:HDNjm:u:4:t:V")) != -1) {
        switch (ch) {
        case 'b':
            bytes = strtol(optarg, &ptr, 0);
@@ -867,8 +1099,13 @@ rxperf_client(int argc, char **argv)
            errx(1, "compiled without RXDEBUG");
 #endif
            break;
+       case 'P':
+           minpeertimeout = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx(1, "can't resolve min peer timeout");
+           break;
        case 'p':
-           port = strtol(optarg, &ptr, 0);
+           port = (short) strtol(optarg, &ptr, 0);
            if (ptr != 0 && ptr[0] != '\0')
                errx(1, "can't resolve portname");
            break;
@@ -877,7 +1114,7 @@ rxperf_client(int argc, char **argv)
            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,
+               errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
                     sizeof(somebuf));
            break;
        case 's':
@@ -885,38 +1122,59 @@ rxperf_client(int argc, char **argv)
            if (host == NULL)
                err(1, "strdup");
            break;
+       case 'V':
+           use_rx_readv = 1;
+           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,
+               errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
                     sizeof(somebuf));
            break;
+       case 'W':
+           maxwsize = strtol(optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx(1, "can't resolve max send/recv window size (packets)");
+           break;
        case 'T':
            times = strtol(optarg, &ptr, 0);
            if (ptr && *ptr != '\0')
-               errx(1, "can't resolve number of bytes to transfer");
+               errx(1, "can't resolve number of times to execute rpc");
            break;
        case 'S':
-           sendtimes = strtol(optarg, &ptr, 0);
+           sendbytes = strtol(optarg, &ptr, 0);
            if (ptr && *ptr != '\0')
-               errx(1, "can't resolve number of bytes to transfer");
+               errx(1, "can't resolve number of bytes to send");
            break;
        case 'R':
-           recvtimes = strtol(optarg, &ptr, 0);
+           readbytes = strtol(optarg, &ptr, 0);
            if (ptr && *ptr != '\0')
-               errx(1, "can't resolve number of bytes to transfer");
+               errx(1, "can't resolve number of bytes to receive");
+           break;
+       case 't':
+#ifdef AFS_PTHREAD_ENV
+           threads = strtol(optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx(1, "can't resolve number of threads to execute");
+            if (threads > MAX_THREADS)
+               errx(1, "too many threads");
+#else
+            errx(1, "Not built for pthreads");
+#endif
            break;
        case 'f':
            filename = optarg;
            break;
        case 'D':
-#ifdef RXDEBUG
            dumpstats = 1;
-#else
-           errx(1, "compiled without RXDEBUG");
-#endif
+           break;
+       case 'N':
+           nostats = 1;
+           break;
+       case 'H':
+           hotthreads = 1;
            break;
        case 'j':
          nojumbo=1;
@@ -926,6 +1184,11 @@ rxperf_client(int argc, char **argv)
          if (ptr && *ptr != '\0')
            errx(1, "can't resolve rx maxmtu to use");
            break;
+       case 'u':
+           udpbufsz = strtol(optarg, &ptr, 0) * 1024;
+           if (ptr && *ptr != '\0')
+               errx(1, "can't resolve upd buffer size (Kbytes)");
+           break;
        case '4':
          RX_IPUDP_SIZE = 28;
          break;
@@ -934,14 +1197,21 @@ rxperf_client(int argc, char **argv)
        }
     }
 
+    if (nostats && dumpstats)
+        errx(1, "cannot set both -N and -D");
+
+    if (threads > 1 && cmd == RX_PERF_FILE)
+        errx(1, "cannot use multiple threads with file command");
+
     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, dumpstats, nojumbo, maxmtu);
+    do_client(host, port, filename, cmd, times, bytes, sendbytes,
+             readbytes, dumpstats, nojumbo, maxmtu, maxwsize, minpeertimeout,
+              udpbufsz, nostats, hotthreads, threads);
 
     return 0;
 }
@@ -953,16 +1223,22 @@ rxperf_client(int argc, char **argv)
 int
 main(int argc, char **argv)
 {
+#ifndef AFS_PTHREAD_ENV
     PROCESS pid;
+#endif
 
     __progname = strrchr(argv[0], '/');
     if (__progname == 0)
        __progname = argv[0];
 
+#ifndef AFS_NT40_ENV
     signal(SIGUSR1, sigusr1);
     signal(SIGINT, sigint);
+#endif
 
+#ifndef AFS_PTHREAD_ENV
     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
+#endif
 
     memset(somebuf, 0, sizeof(somebuf));