tools/tcp_stream: Compile on Linux and add option for sockbuf size
[dragonfly.git] / tools / tools / netrate / netperf / tcp_stream / tcp_stream.c
bloba3dafc5a70729f25c06d569c17d6918d2c31c1ce
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <sys/wait.h>
5 #include <err.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <unistd.h>
12 #define NETPERF_CMD "netperf"
13 #define NETPERF_PATH "/usr/local/bin/" NETPERF_CMD
15 #ifndef __DECONST
16 #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
17 #endif
19 struct netperf_child {
20 int pipes[2];
23 static void
24 usage(const char *cmd)
26 fprintf(stderr, "%s -H host [-l len_s] [-i instances] [-m msgsz] "
27 "[-S sockbuf] [-r|-s]\n", cmd);
28 exit(1);
31 int
32 main(int argc, char *argv[])
34 struct netperf_child *instance;
35 char len_str[32];
36 char *args[32];
37 const char *host, *msgsz, *sockbuf;
38 volatile int ninst, set_minmax = 0;
39 int len, ninst_done;
40 int opt, i, null_fd;
41 volatile int reverse = 0, sfile = 0;
42 double result, res_max, res_min, jain;
44 host = NULL;
45 ninst = 2;
46 len = 10;
47 msgsz = NULL;
48 sockbuf = NULL;
50 while ((opt = getopt(argc, argv, "H:S:i:l:m:rs")) != -1) {
51 switch (opt) {
52 case 'H':
53 host = optarg;
54 break;
56 case 'S':
57 sockbuf = optarg;
58 break;
60 case 'i':
61 ninst = strtoul(optarg, NULL, 10);
62 break;
64 case 'l':
65 len = strtoul(optarg, NULL, 10);
66 break;
68 case 'm':
69 msgsz = optarg;
70 break;
72 case 'r':
73 reverse = 1;
74 sfile = 0;
75 break;
77 case 's':
78 reverse = 0;
79 sfile = 1;
80 break;
82 default:
83 usage(argv[0]);
86 if (ninst <= 0 || host == NULL || len <= 0)
87 usage(argv[0]);
89 snprintf(len_str, sizeof(len_str), "%d", len);
91 i = 0;
92 args[i++] = __DECONST(char *, NETPERF_CMD);
93 args[i++] = __DECONST(char *, "-P0");
94 args[i++] = __DECONST(char *, "-H");
95 args[i++] = __DECONST(char *, host);
96 args[i++] = __DECONST(char *, "-l");
97 args[i++] = __DECONST(char *, len_str);
98 args[i++] = __DECONST(char *, "-t");
99 if (reverse)
100 args[i++] = __DECONST(char *, "TCP_MAERTS");
101 else if (sfile)
102 args[i++] = __DECONST(char *, "TCP_SENDFILE");
103 else
104 args[i++] = __DECONST(char *, "TCP_STREAM");
105 if (msgsz != NULL || sockbuf != NULL) {
106 args[i++] = __DECONST(char *, "--");
107 if (msgsz != NULL) {
108 args[i++] = __DECONST(char *, "-m");
109 args[i++] = __DECONST(char *, msgsz);
111 if (sockbuf != NULL) {
112 char buf_str[64];
114 snprintf(buf_str, sizeof(buf_str), "%s,%s",
115 sockbuf, sockbuf);
116 args[i++] = __DECONST(char *, "-s");
117 args[i++] = __DECONST(char *, buf_str);
118 args[i++] = __DECONST(char *, "-S");
119 args[i++] = __DECONST(char *, buf_str);
122 args[i] = NULL;
124 instance = calloc(ninst, sizeof(struct netperf_child));
125 if (instance == NULL)
126 err(1, "calloc failed");
128 null_fd = open("/dev/null", O_RDWR);
129 if (null_fd < 0)
130 err(1, "open null failed");
132 for (i = 0; i < ninst; ++i) {
133 if (pipe(instance[i].pipes) < 0)
134 err(1, "pipe %dth failed", i);
137 for (i = 0; i < ninst; ++i) {
138 pid_t pid;
140 pid = vfork();
141 if (pid == 0) {
142 int ret;
144 dup2(instance[i].pipes[1], STDOUT_FILENO);
145 dup2(null_fd, STDERR_FILENO);
146 ret = execv(NETPERF_PATH, args);
147 if (ret < 0) {
148 warn("execv %d failed", i);
149 _exit(1);
151 /* Never reached */
152 abort();
153 } else if (pid < 0) {
154 err(1, "vfork %d failed", i);
156 close(instance[i].pipes[1]);
157 instance[i].pipes[1] = -1;
160 ninst_done = 0;
161 while (ninst_done < ninst) {
162 pid_t pid;
164 pid = waitpid(-1, NULL, 0);
165 if (pid < 0)
166 err(1, "waitpid failed");
167 ++ninst_done;
170 res_max = 0.0;
171 res_min = 0.0;
172 jain = 0.0;
173 result = 0.0;
174 for (i = 0; i < ninst; ++i) {
175 char line[128];
176 FILE *fp;
178 fp = fdopen(instance[i].pipes[0], "r");
179 if (fp == NULL)
180 err(1, "fdopen %dth failed", i);
182 while (fgets(line, sizeof(line), fp) != NULL) {
183 int n, arg1, arg2, arg3;
184 double res, arg4;
186 n = sscanf(line, "%d%d%d%lf%lf",
187 &arg1, &arg2, &arg3, &arg4, &res);
188 if (n == 5) {
189 if (!set_minmax) {
190 res_max = res;
191 res_min = res;
192 set_minmax = 1;
193 } else {
194 if (res > res_max)
195 res_max = res;
196 if (res < res_min)
197 res_min = res;
199 jain += (res * res);
200 result += res;
201 break;
204 fclose(fp);
207 jain *= ninst;
208 jain = (result * result) / jain;
210 printf("%s %.2f Mbps\n", reverse ? "TCP_MAERTS" : "TCP_STREAM", result);
211 printf("min/max (jain) %.2f Mbps/%.2f Mbps (%f)\n",
212 res_min, res_max, jain);
214 exit(0);