[PATCH] email update
[splice.git] / splice-bench.c
index c5b97291b22eeec37fcc3a6cb0899794c5680c99..9ceae5048da5eeb48a763666e61547ea56474fb2 100644 (file)
@@ -11,6 +11,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/time.h>
+#include <sys/mman.h>
 #include <signal.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -27,6 +28,10 @@ static int write_to_null;
 static int same_file;
 static int splice_size = SPLICE_SIZE;
 static char *filename = "splice-file";
+static unsigned int max_client_run = 15;
+static int run_rw = 1;
+static int run_splice = 1;
+static int run_mmap = 1;
 
 static int nr_cpus;
 
@@ -40,6 +45,8 @@ static int usage(char *name)
        fprintf(stderr, "\t[-s] (use 1 file for all)\n");
        fprintf(stderr, "\t[-a] (set CPU affinity)\n");
        fprintf(stderr, "\t[-b] (splice chunk size)\n");
+       fprintf(stderr, "\t[-t] (max client runtime in seconds)\n");
+       fprintf(stderr, "\t[-c] (clients to run (rw/mmap/splice)\n");
        return 1;
 }
 
@@ -47,7 +54,7 @@ static int parse_options(int argc, char *argv[])
 {
        int c, index = 1;
 
-       while ((c = getopt(argc, argv, "n:p:l:azsb:")) != -1) {
+       while ((c = getopt(argc, argv, "n:p:l:azsb:t:c:")) != -1) {
                switch (c) {
                case 'n':
                        nr_clients = atoi(optarg);
@@ -77,6 +84,19 @@ static int parse_options(int argc, char *argv[])
                        splice_size = atoi(optarg);
                        index++;
                        break;
+               case 't':
+                       max_client_run = atoi(optarg);
+                       index++;
+                       break;
+               case 'c':
+                       if (!strstr(optarg, "rw"))
+                               run_rw = 0;
+                       if (!strstr(optarg, "splice"))
+                               run_splice = 0;
+                       if (!strstr(optarg, "mmap"))
+                               run_mmap = 0;
+                       index++;
+                       break;
                default:
                        return -1;
                }
@@ -85,7 +105,7 @@ static int parse_options(int argc, char *argv[])
        return index;
 }
 
-int bind_to_cpu(int index)
+static int bind_to_cpu(int index)
 {
        cpu_set_t cpu_mask;
        pid_t pid;
@@ -106,9 +126,8 @@ int bind_to_cpu(int index)
        return 0;
 }
 
-int accept_loop(int listen_sk)
+static int accept_loop(int listen_sk)
 {
-       unsigned long received;
        struct sockaddr addr;
        unsigned int len = sizeof(addr);
        int sk;
@@ -119,14 +138,11 @@ again:
                return error("accept");
 
        /* read forever */
-       received = 0;
        for (;;) {
                int ret = recv(sk, NULL, 128*1024*1024, MSG_TRUNC);
-               if (ret > 0) {
-                       received += ret;
+               if (ret > 0)
                        continue;
-               }
-               if (!ret)
+               else if (!ret)
                        break;
                if (errno == EAGAIN || errno == EINTR)
                        continue;
@@ -137,12 +153,12 @@ again:
        goto again;
 }
 
-int server(int offset)
+static int server(int offset)
 {
-       struct sockaddr addr;
        struct sockaddr_in saddr_in;
+       struct sockaddr addr;
        unsigned int len;
-       int sk;
+       int sk, opt;
 
        bind_to_cpu(offset);
        nice(-20);
@@ -151,10 +167,14 @@ int server(int offset)
        if (sk < 0)
                return error("socket");
 
+       opt = 1;
+       if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
+               return error("setsockopt");
+
        saddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
        saddr_in.sin_port = htons(net_port + offset);
 
-       if (bind(sk, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) < 0)
+       if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0)
                return error("bind");
 
        if (listen(sk, 1) < 0)
@@ -192,7 +212,106 @@ static unsigned long mtime_since_now(struct timeval *s)
        return mtime_since(s, &t);
 }
 
-int client_loop(int out_fd, int fd, int *pfd, int offset)
+static int client_rw(int out_fd, int file_fd, int offset)
+{
+       int loops = client_loops;
+       struct timeval start;
+       struct stat sb;
+       char *buf;
+       unsigned long long size;
+       unsigned long msecs;
+
+       if (fstat(file_fd, &sb) < 0)
+               return error("fstat");
+
+       buf = malloc(splice_size);
+
+       gettimeofday(&start, NULL);
+again:
+       if (lseek(file_fd, 0, SEEK_SET) < 0)
+               return error("lseek");
+
+       size = sb.st_size;
+       while (size) {
+               int this_len = min(size, (unsigned long long) splice_size);
+               int ret = read(file_fd, buf, this_len);
+
+               if (ret < 0)
+                       return error("read");
+
+               size -= ret;
+               while (ret) {
+                       int written = write(out_fd, buf, ret);
+
+                       if (written < 0)
+                               return error("write");
+
+                       ret -= written;
+               }
+       }
+
+       loops--;
+
+       if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
+               goto again;
+
+       free(buf);
+       size = sb.st_size >> 10;
+       size *= (client_loops - loops);
+       msecs = mtime_since_now(&start);
+       fprintf(stdout, "Client%d (rw): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
+       return 0;
+}
+
+static int client_mmap(int out_fd, int file_fd, int offset)
+{
+       int loops = client_loops;
+       struct timeval start;
+       struct stat sb;
+       void *mmap_area, *buf;
+       unsigned long long size;
+       unsigned long msecs;
+
+       if (fstat(file_fd, &sb) < 0)
+               return error("fstat");
+
+       mmap_area = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, file_fd, 0);
+       if (mmap_area == MAP_FAILED)
+               return error("mmap");
+
+       if (madvise(mmap_area, sb.st_size, MADV_WILLNEED) < 0)
+               return error("madvise");
+
+       gettimeofday(&start, NULL);
+again:
+       buf = mmap_area;
+       size = sb.st_size;
+       while (size) {
+               int this_len = min(size, (unsigned long long) splice_size);
+               int ret = write(out_fd, buf, this_len);
+
+               if (ret < 0)
+                       return error("write");
+
+               buf += ret;
+               size -= ret;
+       }
+
+       loops--;
+
+       if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
+               goto again;
+
+       size = sb.st_size >> 10;
+       size *= (client_loops - loops);
+       msecs = mtime_since_now(&start);
+       fprintf(stdout, "Client%d (mmap): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
+       munmap(mmap_area, sb.st_size);
+       return 0;
+
+}
+
+static int client_splice_loop(int out_fd, int fd, int *pfd, int offset)
 {
        struct timeval start;
        unsigned long long size;
@@ -205,7 +324,6 @@ int client_loop(int out_fd, int fd, int *pfd, int offset)
                return error("fstat");
 
        gettimeofday(&start, NULL);
-
 again:
        size = sb.st_size;
        off = 0;
@@ -228,13 +346,50 @@ again:
                }
        } while (size);
 
-       if (--loops)
+       loops--;
+
+       if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
                goto again;
 
        size = sb.st_size >> 10;
-       size *= client_loops;
+       size *= (client_loops - loops);
        msecs = mtime_since_now(&start);
-       fprintf(stdout, "Client%d: %Lu MiB/sec\n", offset, size / (unsigned long long) msecs);
+       fprintf(stdout, "Client%d (splice): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
+       return 0;
+}
+
+static int client_splice(int out_fd, int file_fd, int offset)
+{
+       int pfd[2], ret;
+
+       if (pipe(pfd) < 0)
+               return error("pipe");
+       
+       ret = client_splice_loop(out_fd, file_fd, pfd, offset);
+       close(pfd[0]);
+       close(pfd[1]);
+       return ret;
+}
+
+static int do_client(int out_fd, int file_fd, int offset)
+{
+       int ret;
+
+       if (run_splice) {
+               ret = client_splice(out_fd, file_fd, offset);
+               if (ret)
+                       return ret;
+       }
+       if (run_mmap) {
+               ret = client_mmap(out_fd, file_fd, offset);
+               if (ret)
+                       return ret;
+       }
+       if (run_rw) {
+               ret = client_rw(out_fd, file_fd, offset);
+               if (ret)
+                       return ret;
+       }
        return 0;
 }
 
@@ -259,11 +414,10 @@ static int client_open_net(int offset)
        return sk;
 }
 
-int client(int offset)
+static int client(int offset)
 {
        int file_fd, out_fd;
        char fname[64];
-       int pfd[2];
 
        bind_to_cpu(offset);
        nice(-20);
@@ -277,14 +431,11 @@ int client(int offset)
                return error("socket");
 
        sprintf(fname, "%s%d", filename, same_file ? 0 : offset);
-       file_fd = open(filename, O_RDONLY);
+       file_fd = open(fname, O_RDONLY);
        if (file_fd < 0)
                return error("open");
 
-       if (pipe(pfd) < 0)
-               return error("pipe");
-       
-       return client_loop(out_fd, file_fd, pfd, offset);
+       return do_client(out_fd, file_fd, offset);
 }
 
 int main(int argc, char *argv[])
@@ -308,8 +459,6 @@ int main(int argc, char *argv[])
        if (nr_cpus < 0)
                return error("_SC_NPROCESSORS_ONLN");
 
-       fprintf(stdout,"Processors: %d\n", nr_cpus);
-
        /*
         * fork servers
         */