8 #include <netinet/in.h>
14 #include <sys/resource.h>
16 #include "../splice.h"
20 static void **buffers;
21 static int cur_buf, nr_bufs;
23 static unsigned int msg_size = 4096;
24 static int use_splice = 1;
25 static unsigned long packets = -1;
27 static unsigned long seed = 0x9e370001UL;
29 unsigned long mtime_since(struct timeval *s, struct timeval *e)
33 sec = e->tv_sec - s->tv_sec;
34 usec = e->tv_usec - s->tv_usec;
35 if (sec > 0 && usec < 0) {
45 * time warp bug on some kernels?
53 unsigned long mtime_since_now(struct timeval *s)
57 gettimeofday(&t, NULL);
58 return mtime_since(s, &t);
61 static int usage(char *name)
63 fprintf(stderr, "%s: [-s(ize)] [-p(ackets to send)] [-n(ormal send())] target port\n", name);
67 static int parse_options(int argc, char *argv[])
71 while ((c = getopt(argc, argv, "s:np:")) != -1) {
74 msg_size = atoi(optarg);
82 packets = atoi(optarg);
93 static void fill_buf(struct msg *m, unsigned int len)
106 if (left < sizeof(*val))
108 *val = rand() * seed;
110 left -= sizeof(*val);
113 m->crc32 = crc32(p, len);
116 static int splice_out(int sockfd, int pipefd, unsigned int len)
119 int ret = ssplice(pipefd, NULL, sockfd, NULL, len, 0);
122 return error("splice to network");
132 static int vmsplice_in(void *buf, int pipefd, unsigned int len)
140 int ret = svmsplice(pipefd, &iov, 1, 0);
143 return error("vmsplice");
158 * Keep four pipes of buffers, that should be enough to ensure that
161 static int setup_buffers(void)
165 nr_bufs = 4 * SPLICE_SIZE / msg_size;
167 buffers = malloc(sizeof(void *) * nr_bufs);
169 for (i = 0; i < nr_bufs; i++) {
170 if (posix_memalign(&buffers[i], 4096, msg_size)) {
171 printf("posix_memalign: %s\n", strerror(errno));
179 static void free_buffers(void)
183 for (i = 0; i < nr_bufs; i++)
189 static int splice_send_loop(int fd)
191 struct msg *m = NULL;
195 return error("pipe");
201 m = buffers[cur_buf];
202 if (++cur_buf == nr_bufs)
206 * fill with random data and crc sum it
208 fill_buf(m, msg_size);
211 * map data to our pipe
213 if (vmsplice_in(m, pipes[1], msg_size))
217 * then transmit pipe to network
219 if (splice_out(fd, pipes[0], msg_size))
229 static int do_send(int fd, void *buf, unsigned int len)
232 int ret = send(fd, buf, len, 0);
235 return error("send");
246 static int normal_send_loop(int fd)
250 m = malloc(msg_size);
254 * fill with random data and crc sum it
256 fill_buf(m, msg_size);
258 if (do_send(fd, m, msg_size))
266 static int send_loop(int fd)
268 struct rusage ru_s, ru_e;
269 unsigned long ut, st, rt;
270 struct timeval start;
273 gettimeofday(&start, NULL);
274 getrusage(RUSAGE_SELF, &ru_s);
277 ret = splice_send_loop(fd);
279 ret = normal_send_loop(fd);
281 getrusage(RUSAGE_SELF, &ru_e);
283 ut = mtime_since(&ru_s.ru_utime, &ru_e.ru_utime);
284 st = mtime_since(&ru_s.ru_stime, &ru_e.ru_stime);
285 rt = mtime_since_now(&start);
287 printf("usr=%lu, sys=%lu, real=%lu\n", ut, st, rt);
292 int main(int argc, char *argv[])
294 struct sockaddr_in addr;
299 return usage(argv[0]);
301 index = parse_options(argc, argv);
302 if (index == -1 || index + 1 > argc)
303 return usage(argv[0]);
305 port = atoi(argv[index + 1]);
307 memset(&addr, 0, sizeof(addr));
308 addr.sin_family = AF_INET;
309 addr.sin_port = htons(port);
311 if (inet_aton(argv[index], &addr.sin_addr) != 1) {
312 struct hostent *hent = gethostbyname(argv[index]);
315 return error("gethostbyname");
317 memcpy(&addr.sin_addr, hent->h_addr, 4);
320 printf("xmit: msg=%ukb, ", msg_size >> 10);
322 printf("vmsplice() -> splice()\n");
326 printf("Connecting to %s/%d\n", argv[index], port);
328 fd = socket(AF_INET, SOCK_STREAM, 0);
330 return error("socket");
332 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
333 return error("connect");
335 return send_loop(fd);