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