xref: /dflybsd-src/tools/tools/netrate/netperf/tcp_stream/tcp_stream.c (revision 09b711b9eacad9a4c85bf16d1c4f8622f009d545)
1691866f9SSepherosa Ziehau #include <sys/types.h>
2691866f9SSepherosa Ziehau #include <sys/stat.h>
3691866f9SSepherosa Ziehau #include <sys/wait.h>
4691866f9SSepherosa Ziehau 
5ef2b3ec4SSepherosa Ziehau #include <err.h>
6691866f9SSepherosa Ziehau #include <fcntl.h>
7101322bdSSepherosa Ziehau #include <signal.h>
8691866f9SSepherosa Ziehau #include <stdio.h>
91ba28713SSepherosa Ziehau #include <stdint.h>
10691866f9SSepherosa Ziehau #include <stdlib.h>
1159136566SSepherosa Ziehau #include <string.h>
12691866f9SSepherosa Ziehau #include <unistd.h>
13691866f9SSepherosa Ziehau 
14691866f9SSepherosa Ziehau #define NETPERF_CMD	"netperf"
15691866f9SSepherosa Ziehau #define NETPERF_PATH	"/usr/local/bin/" NETPERF_CMD
16691866f9SSepherosa Ziehau 
171ba28713SSepherosa Ziehau #ifndef __DECONST
181ba28713SSepherosa Ziehau #define __DECONST(type, var)	((type)(uintptr_t)(const void *)(var))
197caf082dSSepherosa Ziehau #endif
207caf082dSSepherosa Ziehau 
217caf082dSSepherosa Ziehau #ifndef __unused
227caf082dSSepherosa Ziehau #define __unused		__attribute__((__unused__))
231ba28713SSepherosa Ziehau #endif
241ba28713SSepherosa Ziehau 
25691866f9SSepherosa Ziehau struct netperf_child {
2684bcee37SSepherosa Ziehau 	int		pipes[2];
27101322bdSSepherosa Ziehau 	pid_t		pid;
28691866f9SSepherosa Ziehau };
29691866f9SSepherosa Ziehau 
30101322bdSSepherosa Ziehau static struct netperf_child *instance;
31101322bdSSepherosa Ziehau static int ninstance;
32101322bdSSepherosa Ziehau 
33691866f9SSepherosa Ziehau static void
usage(const char * cmd)34691866f9SSepherosa Ziehau usage(const char *cmd)
35691866f9SSepherosa Ziehau {
3659136566SSepherosa Ziehau 	fprintf(stderr, "%s -H host [-H host1] [-l len_s] [-i instances] "
371aa9ea68SSepherosa Ziehau 	    "[-m msgsz] [-S sockbuf] [-r|-s] [-x]\n", cmd);
38691866f9SSepherosa Ziehau 	exit(1);
39691866f9SSepherosa Ziehau }
40691866f9SSepherosa Ziehau 
41101322bdSSepherosa Ziehau static void
sigint_handler(int sig __unused)42101322bdSSepherosa Ziehau sigint_handler(int sig __unused)
43101322bdSSepherosa Ziehau {
44101322bdSSepherosa Ziehau 	int i;
45101322bdSSepherosa Ziehau 
46101322bdSSepherosa Ziehau 	for (i = 0; i < ninstance; ++i) {
47101322bdSSepherosa Ziehau 		if (instance[i].pid != -1)
48101322bdSSepherosa Ziehau 			kill(instance[i].pid, SIGKILL);
49101322bdSSepherosa Ziehau 	}
50101322bdSSepherosa Ziehau 	kill(getpid(), SIGKILL);
51101322bdSSepherosa Ziehau }
52101322bdSSepherosa Ziehau 
53691866f9SSepherosa Ziehau int
main(int argc,char * argv[])54691866f9SSepherosa Ziehau main(int argc, char *argv[])
55691866f9SSepherosa Ziehau {
56e627f207SSepherosa Ziehau 	char len_str[32], sockbuf_str[64], msgsz_str[64];
57691866f9SSepherosa Ziehau 	char *args[32];
58a2a57c24SSepherosa Ziehau 	const char *msgsz, *sockbuf, *name1, *name2;
59*09b711b9SSepherosa Ziehau 	const char ** volatile host;
60101322bdSSepherosa Ziehau 	volatile int set_minmax = 0, nhost, dual;
61101322bdSSepherosa Ziehau 	int len, ninst, ninst_done, host_idx, host_arg_idx, test_arg_idx;
62713b43baSSepherosa Ziehau 	int opt, i, null_fd;
639fa4ca08SSepherosa Ziehau 	volatile int reverse = 0, sfile = 0;
64ca6ef527SSepherosa Ziehau 	double result, res_max, res_min, jain;
65101322bdSSepherosa Ziehau 	sigset_t nset, oset;
66691866f9SSepherosa Ziehau 
671aa9ea68SSepherosa Ziehau 	dual = 0;
68691866f9SSepherosa Ziehau 	ninst = 2;
69691866f9SSepherosa Ziehau 	len = 10;
70713b43baSSepherosa Ziehau 	msgsz = NULL;
711ba28713SSepherosa Ziehau 	sockbuf = NULL;
72691866f9SSepherosa Ziehau 
7359136566SSepherosa Ziehau 	host_idx = 0;
7459136566SSepherosa Ziehau 	nhost = 8;
7559136566SSepherosa Ziehau 	host = malloc(sizeof(const char *) * nhost);
7659136566SSepherosa Ziehau 	if (host == NULL)
7759136566SSepherosa Ziehau 		err(1, "malloc failed");
7859136566SSepherosa Ziehau 
791aa9ea68SSepherosa Ziehau 	while ((opt = getopt(argc, argv, "H:S:i:l:m:rsx")) != -1) {
80691866f9SSepherosa Ziehau 		switch (opt) {
81691866f9SSepherosa Ziehau 		case 'H':
8259136566SSepherosa Ziehau 			if (host_idx == nhost) {
8359136566SSepherosa Ziehau 				const char **new_host;
8459136566SSepherosa Ziehau 
8559136566SSepherosa Ziehau 				nhost *= 2;
8659136566SSepherosa Ziehau 				new_host = malloc(sizeof(const char *) * nhost);
8759136566SSepherosa Ziehau 				if (new_host == NULL)
8859136566SSepherosa Ziehau 					err(1, "malloc failed");
8959136566SSepherosa Ziehau 				memcpy(new_host, host,
9059136566SSepherosa Ziehau 				    host_idx * sizeof(const char *));
9159136566SSepherosa Ziehau 				free(host);
9259136566SSepherosa Ziehau 				host = new_host;
9359136566SSepherosa Ziehau 			}
9459136566SSepherosa Ziehau 			host[host_idx++] = optarg;
95691866f9SSepherosa Ziehau 			break;
96691866f9SSepherosa Ziehau 
971ba28713SSepherosa Ziehau 		case 'S':
981ba28713SSepherosa Ziehau 			sockbuf = optarg;
991ba28713SSepherosa Ziehau 			break;
1001ba28713SSepherosa Ziehau 
101713b43baSSepherosa Ziehau 		case 'i':
102713b43baSSepherosa Ziehau 			ninst = strtoul(optarg, NULL, 10);
103713b43baSSepherosa Ziehau 			break;
104713b43baSSepherosa Ziehau 
105691866f9SSepherosa Ziehau 		case 'l':
106691866f9SSepherosa Ziehau 			len = strtoul(optarg, NULL, 10);
107691866f9SSepherosa Ziehau 			break;
108691866f9SSepherosa Ziehau 
109713b43baSSepherosa Ziehau 		case 'm':
110713b43baSSepherosa Ziehau 			msgsz = optarg;
111713b43baSSepherosa Ziehau 			break;
112713b43baSSepherosa Ziehau 
113691866f9SSepherosa Ziehau 		case 'r':
114691866f9SSepherosa Ziehau 			reverse = 1;
1159fa4ca08SSepherosa Ziehau 			sfile = 0;
1169fa4ca08SSepherosa Ziehau 			break;
1179fa4ca08SSepherosa Ziehau 
1189fa4ca08SSepherosa Ziehau 		case 's':
1199fa4ca08SSepherosa Ziehau 			reverse = 0;
1209fa4ca08SSepherosa Ziehau 			sfile = 1;
121691866f9SSepherosa Ziehau 			break;
122691866f9SSepherosa Ziehau 
1231aa9ea68SSepherosa Ziehau 		case 'x':
1241aa9ea68SSepherosa Ziehau 			dual = 1;
1251aa9ea68SSepherosa Ziehau 			break;
1261aa9ea68SSepherosa Ziehau 
127691866f9SSepherosa Ziehau 		default:
128691866f9SSepherosa Ziehau 			usage(argv[0]);
129691866f9SSepherosa Ziehau 		}
130691866f9SSepherosa Ziehau 	}
13159136566SSepherosa Ziehau 	nhost = host_idx;
13259136566SSepherosa Ziehau 
13359136566SSepherosa Ziehau 	if (ninst <= 0 || nhost == 0 || len <= 0)
134691866f9SSepherosa Ziehau 		usage(argv[0]);
135691866f9SSepherosa Ziehau 
136691866f9SSepherosa Ziehau 	snprintf(len_str, sizeof(len_str), "%d", len);
137691866f9SSepherosa Ziehau 
138691866f9SSepherosa Ziehau 	i = 0;
139691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, NETPERF_CMD);
140691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, "-P0");
141691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, "-H");
14259136566SSepherosa Ziehau 	host_arg_idx = i;
14359136566SSepherosa Ziehau 	args[i++] = __DECONST(char *, NULL);
144691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, "-l");
145691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, len_str);
146691866f9SSepherosa Ziehau 	args[i++] = __DECONST(char *, "-t");
1471aa9ea68SSepherosa Ziehau 	test_arg_idx = i;
148691866f9SSepherosa Ziehau 	if (reverse)
149691866f9SSepherosa Ziehau 		args[i++] = __DECONST(char *, "TCP_MAERTS");
1509fa4ca08SSepherosa Ziehau 	else if (sfile)
1519fa4ca08SSepherosa Ziehau 		args[i++] = __DECONST(char *, "TCP_SENDFILE");
152691866f9SSepherosa Ziehau 	else
153691866f9SSepherosa Ziehau 		args[i++] = __DECONST(char *, "TCP_STREAM");
1541ba28713SSepherosa Ziehau 	if (msgsz != NULL || sockbuf != NULL) {
155713b43baSSepherosa Ziehau 		args[i++] = __DECONST(char *, "--");
1561ba28713SSepherosa Ziehau 		if (msgsz != NULL) {
157e627f207SSepherosa Ziehau 			snprintf(msgsz_str, sizeof(msgsz_str), "%s,%s",
158e627f207SSepherosa Ziehau 			    msgsz, msgsz);
159713b43baSSepherosa Ziehau 			args[i++] = __DECONST(char *, "-m");
160e627f207SSepherosa Ziehau 			args[i++] = __DECONST(char *, msgsz_str);
161e627f207SSepherosa Ziehau 			args[i++] = __DECONST(char *, "-M");
162e627f207SSepherosa Ziehau 			args[i++] = __DECONST(char *, msgsz_str);
163713b43baSSepherosa Ziehau 		}
1641ba28713SSepherosa Ziehau 		if (sockbuf != NULL) {
16542d117b1SSepherosa Ziehau 			snprintf(sockbuf_str, sizeof(sockbuf_str), "%s,%s",
1661ba28713SSepherosa Ziehau 			    sockbuf, sockbuf);
1671ba28713SSepherosa Ziehau 			args[i++] = __DECONST(char *, "-s");
16842d117b1SSepherosa Ziehau 			args[i++] = __DECONST(char *, sockbuf_str);
1691ba28713SSepherosa Ziehau 			args[i++] = __DECONST(char *, "-S");
17042d117b1SSepherosa Ziehau 			args[i++] = __DECONST(char *, sockbuf_str);
1711ba28713SSepherosa Ziehau 		}
1721ba28713SSepherosa Ziehau 	}
173691866f9SSepherosa Ziehau 	args[i] = NULL;
174691866f9SSepherosa Ziehau 
1751aa9ea68SSepherosa Ziehau 	ninstance = ninst * nhost * (dual + 1);
17659136566SSepherosa Ziehau 	instance = calloc(ninstance, sizeof(struct netperf_child));
177ef2b3ec4SSepherosa Ziehau 	if (instance == NULL)
178ef2b3ec4SSepherosa Ziehau 		err(1, "calloc failed");
179691866f9SSepherosa Ziehau 
180691866f9SSepherosa Ziehau 	null_fd = open("/dev/null", O_RDWR);
181ef2b3ec4SSepherosa Ziehau 	if (null_fd < 0)
182ef2b3ec4SSepherosa Ziehau 		err(1, "open null failed");
183691866f9SSepherosa Ziehau 
18459136566SSepherosa Ziehau 	for (i = 0; i < ninstance; ++i) {
185ef2b3ec4SSepherosa Ziehau 		if (pipe(instance[i].pipes) < 0)
186ef2b3ec4SSepherosa Ziehau 			err(1, "pipe %dth failed", i);
187101322bdSSepherosa Ziehau 		instance[i].pid = -1;
188691866f9SSepherosa Ziehau 	}
189691866f9SSepherosa Ziehau 
190101322bdSSepherosa Ziehau 	sigemptyset(&nset);
191101322bdSSepherosa Ziehau 	sigaddset(&nset, SIGINT);
192101322bdSSepherosa Ziehau 	sigprocmask(SIG_BLOCK, &nset, &oset);
193101322bdSSepherosa Ziehau 	signal(SIGINT, sigint_handler);
194101322bdSSepherosa Ziehau 
19559136566SSepherosa Ziehau 	for (i = 0; i < ninstance; ++i) {
196691866f9SSepherosa Ziehau 		pid_t pid;
197691866f9SSepherosa Ziehau 
198691866f9SSepherosa Ziehau 		pid = vfork();
199691866f9SSepherosa Ziehau 		if (pid == 0) {
200691866f9SSepherosa Ziehau 			int ret;
201691866f9SSepherosa Ziehau 
20284bcee37SSepherosa Ziehau 			dup2(instance[i].pipes[1], STDOUT_FILENO);
203691866f9SSepherosa Ziehau 			dup2(null_fd, STDERR_FILENO);
20459136566SSepherosa Ziehau 
20559136566SSepherosa Ziehau 			args[host_arg_idx] = __DECONST(char *,
20659136566SSepherosa Ziehau 			    host[i % nhost]);
2071aa9ea68SSepherosa Ziehau 			if (dual) {
2081aa9ea68SSepherosa Ziehau 				const char *test_type;
2091aa9ea68SSepherosa Ziehau 
2101aa9ea68SSepherosa Ziehau 				if ((i / nhost) & dual) {
2111aa9ea68SSepherosa Ziehau 					test_type = sfile ?
2121aa9ea68SSepherosa Ziehau 					    "TCP_SENDFILE" : "TCP_STREAM";
2131aa9ea68SSepherosa Ziehau 				} else {
2141aa9ea68SSepherosa Ziehau 					test_type = "TCP_MAERTS";
2151aa9ea68SSepherosa Ziehau 				}
2161aa9ea68SSepherosa Ziehau 				args[test_arg_idx] = __DECONST(char *,
2171aa9ea68SSepherosa Ziehau 				    test_type);
2181aa9ea68SSepherosa Ziehau 			}
219691866f9SSepherosa Ziehau 			ret = execv(NETPERF_PATH, args);
220691866f9SSepherosa Ziehau 			if (ret < 0) {
221ef2b3ec4SSepherosa Ziehau 				warn("execv %d failed", i);
222691866f9SSepherosa Ziehau 				_exit(1);
223691866f9SSepherosa Ziehau 			}
224691866f9SSepherosa Ziehau 			/* Never reached */
225691866f9SSepherosa Ziehau 			abort();
226691866f9SSepherosa Ziehau 		} else if (pid < 0) {
227ef2b3ec4SSepherosa Ziehau 			err(1, "vfork %d failed", i);
228691866f9SSepherosa Ziehau 		}
22984bcee37SSepherosa Ziehau 		close(instance[i].pipes[1]);
23084bcee37SSepherosa Ziehau 		instance[i].pipes[1] = -1;
231101322bdSSepherosa Ziehau 		instance[i].pid = pid;
232691866f9SSepherosa Ziehau 	}
233691866f9SSepherosa Ziehau 
234101322bdSSepherosa Ziehau 	sigprocmask(SIG_SETMASK, &oset, NULL);
235101322bdSSepherosa Ziehau 
236691866f9SSepherosa Ziehau 	ninst_done = 0;
23759136566SSepherosa Ziehau 	while (ninst_done < ninstance) {
238691866f9SSepherosa Ziehau 		pid_t pid;
239691866f9SSepherosa Ziehau 
240691866f9SSepherosa Ziehau 		pid = waitpid(-1, NULL, 0);
241ef2b3ec4SSepherosa Ziehau 		if (pid < 0)
242ef2b3ec4SSepherosa Ziehau 			err(1, "waitpid failed");
243691866f9SSepherosa Ziehau 		++ninst_done;
244691866f9SSepherosa Ziehau 	}
245691866f9SSepherosa Ziehau 
246ca6ef527SSepherosa Ziehau 	res_max = 0.0;
247ca6ef527SSepherosa Ziehau 	res_min = 0.0;
248ca6ef527SSepherosa Ziehau 	jain = 0.0;
249691866f9SSepherosa Ziehau 	result = 0.0;
25059136566SSepherosa Ziehau 	for (i = 0; i < ninstance; ++i) {
25184bcee37SSepherosa Ziehau 		char line[128];
252691866f9SSepherosa Ziehau 		FILE *fp;
253691866f9SSepherosa Ziehau 
25484bcee37SSepherosa Ziehau 		fp = fdopen(instance[i].pipes[0], "r");
255ef2b3ec4SSepherosa Ziehau 		if (fp == NULL)
256ef2b3ec4SSepherosa Ziehau 			err(1, "fdopen %dth failed", i);
257691866f9SSepherosa Ziehau 
258691866f9SSepherosa Ziehau 		while (fgets(line, sizeof(line), fp) != NULL) {
259691866f9SSepherosa Ziehau 			int n, arg1, arg2, arg3;
260691866f9SSepherosa Ziehau 			double res, arg4;
261691866f9SSepherosa Ziehau 
262691866f9SSepherosa Ziehau 			n = sscanf(line, "%d%d%d%lf%lf",
263691866f9SSepherosa Ziehau 			    &arg1, &arg2, &arg3, &arg4, &res);
264691866f9SSepherosa Ziehau 			if (n == 5) {
265ca6ef527SSepherosa Ziehau 				if (!set_minmax) {
266ca6ef527SSepherosa Ziehau 					res_max = res;
267ca6ef527SSepherosa Ziehau 					res_min = res;
268ca6ef527SSepherosa Ziehau 					set_minmax = 1;
269ca6ef527SSepherosa Ziehau 				} else {
270ca6ef527SSepherosa Ziehau 					if (res > res_max)
271ca6ef527SSepherosa Ziehau 						res_max = res;
272ca6ef527SSepherosa Ziehau 					if (res < res_min)
273ca6ef527SSepherosa Ziehau 						res_min = res;
274ca6ef527SSepherosa Ziehau 				}
275ca6ef527SSepherosa Ziehau 				jain += (res * res);
276691866f9SSepherosa Ziehau 				result += res;
277691866f9SSepherosa Ziehau 				break;
278691866f9SSepherosa Ziehau 			}
279691866f9SSepherosa Ziehau 		}
280691866f9SSepherosa Ziehau 		fclose(fp);
281691866f9SSepherosa Ziehau 	}
282ca6ef527SSepherosa Ziehau 
28359136566SSepherosa Ziehau 	jain *= ninstance;
284ca6ef527SSepherosa Ziehau 	jain = (result * result) / jain;
285ca6ef527SSepherosa Ziehau 
286a2a57c24SSepherosa Ziehau 	name1 = "TCP_STREAM";
287a2a57c24SSepherosa Ziehau 	name2 = "";
288a2a57c24SSepherosa Ziehau 	if (dual) {
289a2a57c24SSepherosa Ziehau 		name1 = "TCP_MAERTS";
290a2a57c24SSepherosa Ziehau 		if (sfile)
291a2a57c24SSepherosa Ziehau 			name2 = "/TCP_SENDFILE";
292a2a57c24SSepherosa Ziehau 		else
293a2a57c24SSepherosa Ziehau 			name2 = "/TCP_STREAM";
294a2a57c24SSepherosa Ziehau 	} else if (reverse) {
295a2a57c24SSepherosa Ziehau 		name1 = "TCP_MAERTS";
296a2a57c24SSepherosa Ziehau 	} else if (sfile) {
297a2a57c24SSepherosa Ziehau 		name1 = "TCP_SENDFILE";
298a2a57c24SSepherosa Ziehau 	}
299a2a57c24SSepherosa Ziehau 
300a2a57c24SSepherosa Ziehau 	printf("%s%s %.2f Mbps\n", name1, name2, result);
301ca6ef527SSepherosa Ziehau 	printf("min/max (jain) %.2f Mbps/%.2f Mbps (%f)\n",
302ca6ef527SSepherosa Ziehau 	    res_min, res_max, jain);
303691866f9SSepherosa Ziehau 
304691866f9SSepherosa Ziehau 	exit(0);
305691866f9SSepherosa Ziehau }
306