11 #include <sys/types.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
23 static int nr_clients = 8;
24 static int net_port = 8888;
25 static int client_loops = 10;
27 static int write_to_null;
29 static int splice_size = SPLICE_SIZE;
30 static char *filename = "splice-file";
31 static unsigned int max_client_run = 15;
32 static int run_rw = 1;
33 static int run_splice = 1;
34 static int run_mmap = 1;
38 static int usage(char *name)
40 fprintf(stderr, "Usage %s [options] [filename]:\n", name);
41 fprintf(stderr, "\t[-n] (number of clients]\n");
42 fprintf(stderr, "\t[-p] (port number)\n");
43 fprintf(stderr, "\t[-l] (number of loops)\n");
44 fprintf(stderr, "\t[-z] (write to /dev/null)\n");
45 fprintf(stderr, "\t[-s] (use 1 file for all)\n");
46 fprintf(stderr, "\t[-a] (set CPU affinity)\n");
47 fprintf(stderr, "\t[-b] (splice chunk size)\n");
48 fprintf(stderr, "\t[-t] (max client runtime in seconds)\n");
49 fprintf(stderr, "\t[-c] (clients to run (rw/mmap/splice)\n");
53 static int parse_options(int argc, char *argv[])
57 while ((c = getopt(argc, argv, "n:p:l:azsb:t:c:")) != -1) {
60 nr_clients = atoi(optarg);
64 net_port = atoi(optarg);
68 client_loops = atoi(optarg);
84 splice_size = atoi(optarg);
88 max_client_run = atoi(optarg);
92 if (!strstr(optarg, "rw"))
94 if (!strstr(optarg, "splice"))
96 if (!strstr(optarg, "mmap"))
108 static int bind_to_cpu(int index)
114 if (!bind_cpu || nr_cpus == 1)
117 cpu = index % nr_cpus;
120 CPU_SET((cpu), &cpu_mask);
123 if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1)
124 return error("set affinity");
129 static int accept_loop(int listen_sk)
131 struct sockaddr addr;
132 unsigned int len = sizeof(addr);
136 sk = accept(listen_sk, &addr, &len);
138 return error("accept");
142 int ret = recv(sk, NULL, 128*1024*1024, MSG_TRUNC);
147 if (errno == EAGAIN || errno == EINTR)
156 static int server(int offset)
158 struct sockaddr_in saddr_in;
159 struct sockaddr addr;
166 sk = socket(PF_INET, SOCK_STREAM, 0);
168 return error("socket");
171 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
172 return error("setsockopt");
174 saddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
175 saddr_in.sin_port = htons(net_port + offset);
177 if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0)
178 return error("bind");
180 if (listen(sk, 1) < 0)
181 return error("listen");
184 if (getsockname(sk, &addr, &len) < 0)
185 return error("getsockname");
187 return accept_loop(sk);
190 static unsigned long mtime_since(struct timeval *s, struct timeval *e)
194 sec = e->tv_sec - s->tv_sec;
195 usec = e->tv_usec - s->tv_usec;
196 if (sec > 0 && usec < 0) {
201 sec *= (double) 1000;
202 usec /= (double) 1000;
207 static unsigned long mtime_since_now(struct timeval *s)
211 gettimeofday(&t, NULL);
212 return mtime_since(s, &t);
215 static int client_rw(int out_fd, int file_fd, int offset)
217 int loops = client_loops;
218 struct timeval start;
221 unsigned long long size;
224 if (fstat(file_fd, &sb) < 0)
225 return error("fstat");
227 buf = malloc(splice_size);
229 gettimeofday(&start, NULL);
231 if (lseek(file_fd, 0, SEEK_SET) < 0)
232 return error("lseek");
236 int this_len = min(size, (unsigned long long) splice_size);
237 int ret = read(file_fd, buf, this_len);
240 return error("read");
244 int written = write(out_fd, buf, ret);
247 return error("write");
255 if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
259 size = sb.st_size >> 10;
260 size *= (client_loops - loops);
261 msecs = mtime_since_now(&start);
262 fprintf(stdout, "Client%d (rw): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
266 static int client_mmap(int out_fd, int file_fd, int offset)
268 int loops = client_loops;
269 struct timeval start;
271 void *mmap_area, *buf;
272 unsigned long long size;
275 if (fstat(file_fd, &sb) < 0)
276 return error("fstat");
278 mmap_area = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, file_fd, 0);
279 if (mmap_area == MAP_FAILED)
280 return error("mmap");
282 if (madvise(mmap_area, sb.st_size, MADV_WILLNEED) < 0)
283 return error("madvise");
285 gettimeofday(&start, NULL);
290 int this_len = min(size, (unsigned long long) splice_size);
291 int ret = write(out_fd, buf, this_len);
294 return error("write");
302 if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
305 size = sb.st_size >> 10;
306 size *= (client_loops - loops);
307 msecs = mtime_since_now(&start);
308 fprintf(stdout, "Client%d (mmap): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
309 munmap(mmap_area, sb.st_size);
314 static int client_splice_loop(int out_fd, int fd, int *pfd, int offset)
316 struct timeval start;
317 unsigned long long size;
320 int loops = client_loops;
323 if (fstat(fd, &sb) < 0)
324 return error("fstat");
326 gettimeofday(&start, NULL);
332 int ret = ssplice(fd, &off, pfd[1], NULL, min(size, (unsigned long long) splice_size), 0);
335 return error("splice-in");
339 int flags = size ? SPLICE_F_MORE : 0;
340 int written = ssplice(pfd[0], NULL, out_fd, NULL, ret, flags);
343 return error("splice-out");
351 if ((mtime_since_now(&start) < max_client_run * 1000) && loops)
354 size = sb.st_size >> 10;
355 size *= (client_loops - loops);
356 msecs = mtime_since_now(&start);
357 fprintf(stdout, "Client%d (splice): %Lu MiB/sec (%LuMiB in %lu msecs)\n", offset, size / (unsigned long long) msecs, size >> 10, msecs);
361 static int client_splice(int out_fd, int file_fd, int offset)
366 return error("pipe");
368 ret = client_splice_loop(out_fd, file_fd, pfd, offset);
374 static int do_client(int out_fd, int file_fd, int offset)
379 ret = client_splice(out_fd, file_fd, offset);
384 ret = client_mmap(out_fd, file_fd, offset);
389 ret = client_rw(out_fd, file_fd, offset);
396 static int client_open_net(int offset)
398 int sk = socket(PF_INET, SOCK_STREAM, 0);
399 struct sockaddr_in s_to;
402 hp = gethostbyname("localhost");
404 return error("gethostbyname");
406 bzero((char *) &s_to, sizeof (s_to));
407 bcopy((char *) hp->h_addr, (char *) &(s_to.sin_addr), hp->h_length);
408 s_to.sin_family = hp->h_addrtype;
409 s_to.sin_port = htons(net_port + offset);
411 if (connect(sk, (struct sockaddr *)&s_to, sizeof(s_to)) < 0)
412 return error("connect");
417 static int client(int offset)
426 out_fd = client_open_net(offset);
428 out_fd = open("/dev/null", O_WRONLY);
431 return error("socket");
433 sprintf(fname, "%s%d", filename, same_file ? 0 : offset);
434 file_fd = open(fname, O_RDONLY);
436 return error("open");
438 return do_client(out_fd, file_fd, offset);
441 int main(int argc, char *argv[])
443 pid_t *spids, *cpids;
446 index = parse_options(argc, argv);
448 return usage(argv[0]);
451 filename = argv[index];
453 spids = malloc(nr_clients * sizeof(pid_t));
454 cpids = malloc(nr_clients * sizeof(pid_t));
455 memset(spids, 0, nr_clients * sizeof(pid_t));
456 memset(cpids, 0, nr_clients * sizeof(pid_t));
458 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
460 return error("_SC_NPROCESSORS_ONLN");
465 if (!write_to_null) {
466 for (i = 0; i < nr_clients; i++) {
477 sleep(1); /* should have servers started now */
483 for (i = 0; i < nr_clients; i++) {
496 * wait for clients to exit
498 fprintf(stdout, "Waiting for clients\n");
499 for (i = 0; i < nr_clients; i++) {
501 waitpid(cpids[i], NULL, 0);
509 for (i = 0; i < nr_clients; i++) {
511 kill(spids[i], SIGKILL);
512 waitpid(spids[i], NULL, 0);