vmm: refactor userspace's emsr_fakewrite()
[akaros.git] / tests / ttcp.c
1 /*
2  * ttcp. Modelled after the unix ttcp
3  *
4  * Copyright (c) 2012, Bakul Shah <bakul@bitblocks.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The author's name may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * This software is provided by the author AS IS.  The author DISCLAIMS
19  * any and all warranties of merchantability and fitness for a particular
20  * purpose.  In NO event shall the author be LIABLE for any damages
21  * whatsoever arising in any way out of the use of this software.
22  */
23
24 /*
25  * Options not supported (may be supported in future):
26  * +    -u      Use UDP instead of TCP
27  *      -D      don't want for TCP send (TCP_NODELAY)
28  *      -A num  align buffers on this boundary (default 16384)
29  *      -O off  start buffers at this offset (default 0)
30  * Misc:
31  *      - print calls, msec/call calls/sec
32  *      - print user/sys/real times
33  * May be:
34  *      - multicast support
35  *      - isochronous transfer
36  */
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <assert.h>
44 #include <parlib/net.h>
45 #include <sys/time.h>
46 #include <iplib/iplib.h>
47 #include <parlib/timing.h>
48
49 long ncalls;
50 char scale;
51
52 static void sysfatal(char *msg)
53 {
54         perror(msg);
55         exit(-1);
56 }
57
58 long nread(int fd, char *buf, long len)
59 {
60         int cnt, rlen = 0;
61         char *b = buf;
62
63         for (;;) {
64                 cnt = read(fd, b, len);
65                 ncalls++;
66                 if (cnt <= 0)
67                         break;
68                 rlen += cnt;
69                 len -= cnt;
70                 if (len == 0)
71                         break;
72                 b += cnt;
73         }
74         return rlen;
75 }
76
77 long nwrite(int fd, char *buf, long len)
78 {
79         int cnt, rlen = 0;
80         char *b = buf;
81
82         for (;;) {
83                 cnt = write(fd, b, len);
84                 ncalls++;
85                 if (cnt <= 0)
86                         break;
87                 rlen += cnt;
88                 len -= cnt;
89                 if (len == 0)
90                         break;
91                 b += cnt;
92         }
93         return rlen;
94 }
95
96 void pattern(char *buf, int buflen)
97 {
98         int i;
99         char ch = ' ';
100         char *b = buf;
101
102         for (i = 0; i < buflen; i++) {
103                 *b++ = ch++;
104                 if (ch == 127)
105                         ch = ' ';
106         }
107 }
108
109 char fmt = 'K';
110 char *unit;
111
112 double rate(long nbytes, double time)
113 {
114         switch (fmt) {
115         case 'k':
116                 unit = "Kbit";
117                 return nbytes * 8 / time / (1 << 10);
118         case 'K':
119                 unit = "KB";
120                 return nbytes / time / (1 << 10);
121         case 'm':
122                 unit = "Mbit";
123                 return nbytes * 8 / time / (1 << 20);
124         case 'M':
125                 unit = "MB";
126                 return nbytes / time / (1 << 20);
127         case 'g':
128                 unit = "Gbit";
129                 return nbytes * 8 / time / (1 << 30);
130         case 'G':
131                 unit = "GB";
132                 return nbytes / time / (1 << 30);
133         }
134         return 0.0;
135 }
136
137 void reader(int udp, char *addr, char *port, int buflen, int nbuf, int sink)
138 {
139         char *buf, adir[40], ldir[40];
140         char *ds, ds_store[256];
141         int fd, cnt, acfd, lcfd;
142         long nbytes = 0;
143         long now;
144         double elapsed;
145         int pd;
146         char peer[100];
147         double tput;
148
149         fprintf(stderr, "ttcp-r: buflen=%d, nbuf=%d, port=%s %s\n",
150                 buflen, nbuf, port, udp ? "udp" : "tcp");
151
152         ds = netmkaddr(addr, udp ? "udp" : "tcp", port, ds_store,
153                        sizeof(ds_store));
154         acfd = announce9(ds, adir, 0);
155         if (acfd < 0)
156                 sysfatal("announce: %r");
157         buf = malloc(buflen);
158
159         lcfd = listen9(adir, ldir, 0);
160         if (lcfd < 0)
161                 sysfatal("listen: %r");
162
163         fd = accept9(lcfd, ldir);
164         if (fd < 0)
165                 return;
166
167         sprintf(peer, "%s/remote", ldir);
168         pd = open(peer, O_READ);
169         cnt = read(pd, peer, 100);
170         close(pd);
171
172         fprintf(stderr, "ttcp-r: accept from %*.*s", cnt, cnt, peer);
173         now = nsec();
174         if (sink) {
175                 while ((cnt = nread(fd, buf, buflen)) > 0)
176                         nbytes += cnt;
177         } else {
178                 while ((cnt = nread(fd, buf, buflen)) > 0
179                        && write(1, buf, cnt) == cnt)
180                         nbytes += cnt;
181         }
182         elapsed = (nsec() - now) / 1E9;
183
184         tput = rate(nbytes, elapsed);   /* also sets 'unit' */
185         fprintf(stderr,
186                 "ttcp-r: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
187                 nbytes, elapsed, tput, unit);
188 }
189
190 void writer(int udp, char *addr, char *port, int buflen, int nbuf, int src)
191 {
192         char *buf;
193         int fd, cnt;
194         long nbytes = 0;
195         long now;
196         double elapsed;
197         char netaddr[128];
198         double tput;
199
200         fprintf(stderr, "ttcp-t: buflen=%d, nbuf=%d, port=%s %s -> %s\n",
201                     buflen, nbuf, port, udp ? "udp" : "tcp", addr);
202
203         buf = malloc(buflen);
204         snprintf(netaddr, sizeof(netaddr), "%s!%s!%s",
205                  udp ? "udp" : "tcp", addr, port);
206         fprintf(stderr, "dialing %s\n", netaddr);
207         fd = dial9(netaddr, 0, 0, 0, 0);
208         if (fd < 0)
209                 sysfatal("dial: %r");
210
211         fprintf(stderr, "ttcp-t: connect\n");
212
213         now = nsec();
214         if (src) {
215                 pattern(buf, buflen);
216                 while (nbuf-- && nwrite(fd, buf, buflen) == buflen)
217                         nbytes += buflen;
218         } else {
219                 while ((cnt = read(0, buf, buflen)) > 0
220                        && nwrite(fd, buf, cnt) == cnt)
221                         nbytes += cnt;
222         }
223         elapsed = (nsec() - now) / 1E9;
224
225         tput = rate(nbytes, elapsed);   /* also sets 'unit' */
226         fprintf(stderr,
227                 "ttcp-t: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
228                 nbytes, elapsed, tput, unit);
229 }
230
231 void usage(void)
232 {
233         fprintf(stderr, "usage:\tttcp -t [options] host\n"
234               "\t\tttcp -r [options]\n"
235               " options:\n"
236               "  -f fmt\trate format: k,m,g,K,M,G = {kilo,mega,giga}{bit,byte}\n"
237               "  -l\t\tlength of buf (default 8192)\n"
238               "  -p port\tport number (default 5001)\n"
239               "  -n num\tnumber of bufs written (default 2048)\n"
240               "  -s\t\t-t: source a pattern to network\n"
241               "\t\t-r: sink (discard) all data from network\n"
242               );
243         exit(0);
244 }
245
246 void main(int argc, char *argv[])
247 {
248         int buflen = 8192;
249         int nbuf = 2048;
250         int srcsink = 0;
251         char *port = "5001";
252         int udp = 0;
253         enum { none, recv, xmit } mode = none;
254         char c;
255
256         while ((c = getopt(argc, argv, "rstuf:l:n:p:")) != -1) {
257                 switch (c) {
258                 case 'f':
259                         fmt = *optarg;
260                         break;
261                 case 'l':
262                         buflen = atoi(optarg);
263                         break;
264                 case 'n':
265                         nbuf = atoi(optarg);
266                         break;
267                 case 'p':
268                         port = optarg;
269                         break;
270                 case 'r':
271                         mode = recv;
272                         break;
273                 case 's':
274                         srcsink = 1;
275                         break;
276                 case 't':
277                         mode = xmit;
278                         break;
279                 case 'u':
280                         udp = 1;
281                         break;
282                 default:
283                         usage();
284                 }
285         }
286         switch (mode) {
287         case none:
288                 usage();
289                 break;
290         case xmit:
291                 if (optind == argc)
292                         usage();
293                 writer(udp, argv[optind], port, buflen, nbuf, srcsink);
294                 break;
295         case recv:
296                 reader(udp, "*", port, buflen, nbuf, srcsink);
297                 break;
298         }
299         exit(0);
300 }