9ns: Implement fsync with chan_ctl
[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         for (;;) {
63                 cnt = read(fd, b, len);
64                 ncalls++;
65                 if (cnt <= 0)
66                         break;
67                 rlen += cnt;
68                 len -= cnt;
69                 if (len == 0)
70                         break;
71                 b += cnt;
72         }
73         return rlen;
74 }
75
76 long nwrite(int fd, char *buf, long len)
77 {
78         int cnt, rlen = 0;
79         char *b = buf;
80         for (;;) {
81                 cnt = write(fd, b, len);
82                 ncalls++;
83                 if (cnt <= 0)
84                         break;
85                 rlen += cnt;
86                 len -= cnt;
87                 if (len == 0)
88                         break;
89                 b += cnt;
90         }
91         return rlen;
92 }
93
94 void pattern(char *buf, int buflen)
95 {
96         int i;
97         char ch = ' ';
98         char *b = buf;
99         for (i = 0; i < buflen; i++) {
100                 *b++ = ch++;
101                 if (ch == 127)
102                         ch = ' ';
103         }
104 }
105
106 char fmt = 'K';
107 char *unit;
108
109 double rate(long nbytes, double time)
110 {
111         switch (fmt) {
112         case 'k':
113                 unit = "Kbit";
114                 return nbytes * 8 / time / (1 << 10);
115         case 'K':
116                 unit = "KB";
117                 return nbytes / time / (1 << 10);
118         case 'm':
119                 unit = "Mbit";
120                 return nbytes * 8 / time / (1 << 20);
121         case 'M':
122                 unit = "MB";
123                 return nbytes / time / (1 << 20);
124         case 'g':
125                 unit = "Gbit";
126                 return nbytes * 8 / time / (1 << 30);
127         case 'G':
128                 unit = "GB";
129                 return nbytes / time / (1 << 30);
130         }
131         return 0.0;
132 }
133
134 void reader(int udp, char *addr, char *port, int buflen, int nbuf, int sink)
135 {
136         char *buf, adir[40], ldir[40];
137         char *ds, ds_store[256];
138         int fd, cnt, acfd, lcfd;
139         long nbytes = 0;
140         long now;
141         double elapsed;
142         int pd;
143         char peer[100];
144         double tput;
145
146         fprintf(stderr, "ttcp-r: buflen=%d, nbuf=%d, port=%s %s\n",
147                 buflen, nbuf, port, udp ? "udp" : "tcp");
148
149         ds = netmkaddr(addr, udp ? "udp" : "tcp", port, ds_store, sizeof(ds_store));
150         acfd = announce9(ds, adir, 0);
151         if (acfd < 0)
152                 sysfatal("announce: %r");
153         buf = malloc(buflen);
154
155         lcfd = listen9(adir, ldir, 0);
156         if (lcfd < 0)
157                 sysfatal("listen: %r");
158
159         fd = accept9(lcfd, ldir);
160         if (fd < 0)
161                 return;
162
163         sprintf(peer, "%s/remote", ldir);
164         pd = open(peer, O_READ);
165         cnt = read(pd, peer, 100);
166         close(pd);
167
168         fprintf(stderr, "ttcp-r: accept from %*.*s", cnt, cnt, peer);
169         now = nsec();
170         if (sink) {
171                 while ((cnt = nread(fd, buf, buflen)) > 0)
172                         nbytes += cnt;
173         } else {
174                 while ((cnt = nread(fd, buf, buflen)) > 0 && write(1, buf, cnt) == cnt)
175                         nbytes += cnt;
176         }
177         elapsed = (nsec() - now) / 1E9;
178
179         tput = rate(nbytes, elapsed);   /* also sets 'unit' */
180         fprintf(stderr, "ttcp-r: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
181                 nbytes, elapsed, tput, unit);
182 }
183
184 void writer(int udp, char *addr, char *port, int buflen, int nbuf, int src)
185 {
186         char *buf;
187         int fd, cnt;
188         long nbytes = 0;
189         long now;
190         double elapsed;
191         char netaddr[128];
192         double tput;
193
194         fprintf(stderr, "ttcp-t: buflen=%d, nbuf=%d, port=%s %s -> %s\n",
195                     buflen, nbuf, port, udp ? "udp" : "tcp", addr);
196
197         buf = malloc(buflen);
198         snprintf(netaddr, sizeof(netaddr), "%s!%s!%s",
199                  udp ? "udp" : "tcp", addr, port);
200         fprintf(stderr, "dialing %s\n", netaddr);
201         fd = dial9(netaddr, 0, 0, 0, 0);
202         if (fd < 0)
203                 sysfatal("dial: %r");
204
205         fprintf(stderr, "ttcp-t: connect\n");
206
207         now = nsec();
208         if (src) {
209                 pattern(buf, buflen);
210                 while (nbuf-- && nwrite(fd, buf, buflen) == buflen)
211                         nbytes += buflen;
212         } else {
213                 while ((cnt = read(0, buf, buflen)) > 0 && nwrite(fd, buf, cnt) == cnt)
214                         nbytes += cnt;
215         }
216         elapsed = (nsec() - now) / 1E9;
217
218         tput = rate(nbytes, elapsed);   /* also sets 'unit' */
219         fprintf(stderr, "ttcp-t: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
220                 nbytes, elapsed, tput, unit);
221 }
222
223 void usage(void)
224 {
225         fprintf(stderr, "usage:\tttcp -t [options] host\n"
226               "\t\tttcp -r [options]\n"
227               " options:\n"
228               "  -f fmt\trate format: k,m,g,K,M,G = {kilo,mega,giga}{bit,byte}\n"
229               "  -l\t\tlength of buf (default 8192)\n"
230               "  -p port\tport number (default 5001)\n"
231               "  -n num\tnumber of bufs written (default 2048)\n"
232               "  -s\t\t-t: source a pattern to network\n"
233               "\t\t-r: sink (discard) all data from network\n"
234               );
235         exit(0);
236 }
237
238 void main(int argc, char *argv[])
239 {
240         int buflen = 8192;
241         int nbuf = 2048;
242         int srcsink = 0;
243         char *port = "5001";
244         int udp = 0;
245         enum { none, recv, xmit } mode = none;
246         char c;
247
248         while ((c = getopt(argc, argv, "rstuf:l:n:p:")) != -1) {
249                 switch (c) {
250                 case 'f':
251                         fmt = *optarg;
252                         break;
253                 case 'l':
254                         buflen = atoi(optarg);
255                         break;
256                 case 'n':
257                         nbuf = atoi(optarg);
258                         break;
259                 case 'p':
260                         port = optarg;
261                         break;
262                 case 'r':
263                         mode = recv;
264                         break;
265                 case 's':
266                         srcsink = 1;
267                         break;
268                 case 't':
269                         mode = xmit;
270                         break;
271                 case 'u':
272                         udp = 1;
273                         break;
274                 default:
275                         usage();
276                 }
277         }
278         switch (mode) {
279         case none:
280                 usage();
281                 break;
282         case xmit:
283                 if (optind == argc)
284                         usage();
285                 writer(udp, argv[optind], port, buflen, nbuf, srcsink);
286                 break;
287         case recv:
288                 reader(udp, "*", port, buflen, nbuf, srcsink);
289                 break;
290         }
291         exit(0);
292 }