#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>
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;
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;
}
{
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);
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;
}
return index;
}
-int bind_to_cpu(int index)
+static int bind_to_cpu(int index)
{
cpu_set_t cpu_mask;
pid_t pid;
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;
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;
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);
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)
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;
return error("fstat");
gettimeofday(&start, NULL);
-
again:
size = sb.st_size;
off = 0;
}
} 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 / 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;
}
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);
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[])
if (nr_cpus < 0)
return error("_SC_NPROCESSORS_ONLN");
- fprintf(stdout,"Processors: %d\n", nr_cpus);
-
/*
* fork servers
*/