1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <sys/wait.h> 4 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 11 #define NETPERF_CMD "netperf" 12 #define NETPERF_PATH "/usr/local/bin/" NETPERF_CMD 13 14 #define TCP_STRM_FILENAME "/tmp/tcp_strm.%d.%d" 15 16 struct netperf_child { 17 int fd; 18 }; 19 20 static void 21 usage(const char *cmd) 22 { 23 fprintf(stderr, "%s -H host [-l len_s] [-i instances] [-r]\n", cmd); 24 exit(1); 25 } 26 27 int 28 main(int argc, char *argv[]) 29 { 30 struct netperf_child *instance; 31 char len_str[32]; 32 char *args[32]; 33 const char *host; 34 volatile int ninst; 35 int len, ninst_done; 36 int opt, i, null_fd, set_minmax = 0; 37 volatile int reverse = 0; 38 double result, res_max, res_min, jain; 39 pid_t mypid; 40 41 host = NULL; 42 ninst = 2; 43 len = 10; 44 45 while ((opt = getopt(argc, argv, "i:H:l:r")) != -1) { 46 switch (opt) { 47 case 'i': 48 ninst = strtoul(optarg, NULL, 10); 49 break; 50 51 case 'H': 52 host = optarg; 53 break; 54 55 case 'l': 56 len = strtoul(optarg, NULL, 10); 57 break; 58 59 case 'r': 60 reverse = 1; 61 break; 62 63 default: 64 usage(argv[0]); 65 } 66 } 67 if (ninst <= 0 || host == NULL || len <= 0) 68 usage(argv[0]); 69 70 mypid = getpid(); 71 72 snprintf(len_str, sizeof(len_str), "%d", len); 73 74 i = 0; 75 args[i++] = __DECONST(char *, NETPERF_CMD); 76 args[i++] = __DECONST(char *, "-P0"); 77 args[i++] = __DECONST(char *, "-H"); 78 args[i++] = __DECONST(char *, host); 79 args[i++] = __DECONST(char *, "-l"); 80 args[i++] = __DECONST(char *, len_str); 81 args[i++] = __DECONST(char *, "-t"); 82 if (reverse) 83 args[i++] = __DECONST(char *, "TCP_MAERTS"); 84 else 85 args[i++] = __DECONST(char *, "TCP_STREAM"); 86 args[i] = NULL; 87 88 instance = calloc(ninst, sizeof(struct netperf_child)); 89 if (instance == NULL) { 90 fprintf(stderr, "calloc failed\n"); 91 exit(1); 92 } 93 94 null_fd = open("/dev/null", O_RDWR); 95 if (null_fd < 0) { 96 fprintf(stderr, "open null failed: %d\n", errno); 97 exit(1); 98 } 99 100 for (i = 0; i < ninst; ++i) { 101 char filename[128]; 102 103 snprintf(filename, sizeof(filename), TCP_STRM_FILENAME, 104 (int)mypid, i); 105 instance[i].fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 106 S_IWUSR | S_IRUSR); 107 if (instance[i].fd < 0) { 108 fprintf(stderr, "open %s failed: %d\n", 109 filename, errno); 110 exit(1); 111 } 112 } 113 114 for (i = 0; i < ninst; ++i) { 115 pid_t pid; 116 117 pid = vfork(); 118 if (pid == 0) { 119 int ret; 120 121 dup2(instance[i].fd, STDOUT_FILENO); 122 dup2(null_fd, STDERR_FILENO); 123 ret = execv(NETPERF_PATH, args); 124 if (ret < 0) { 125 fprintf(stderr, "execv %d failed: %d\n", 126 i, errno); 127 _exit(1); 128 } 129 /* Never reached */ 130 abort(); 131 } else if (pid < 0) { 132 fprintf(stderr, "vfork %d failed: %d\n", i, errno); 133 exit(1); 134 } 135 } 136 137 ninst_done = 0; 138 while (ninst_done < ninst) { 139 pid_t pid; 140 141 pid = waitpid(-1, NULL, 0); 142 if (pid < 0) { 143 fprintf(stderr, "waitpid failed: %d\n", errno); 144 exit(1); 145 } 146 ++ninst_done; 147 } 148 149 res_max = 0.0; 150 res_min = 0.0; 151 jain = 0.0; 152 result = 0.0; 153 for (i = 0; i < ninst; ++i) { 154 char line[128], filename[128]; 155 FILE *fp; 156 157 close(instance[i].fd); 158 snprintf(filename, sizeof(filename), TCP_STRM_FILENAME, 159 (int)mypid, i); 160 fp = fopen(filename, "r"); 161 if (fp == NULL) { 162 fprintf(stderr, "fopen %s failed\n", filename); 163 exit(1); 164 } 165 166 while (fgets(line, sizeof(line), fp) != NULL) { 167 int n, arg1, arg2, arg3; 168 double res, arg4; 169 170 n = sscanf(line, "%d%d%d%lf%lf", 171 &arg1, &arg2, &arg3, &arg4, &res); 172 if (n == 5) { 173 if (!set_minmax) { 174 res_max = res; 175 res_min = res; 176 set_minmax = 1; 177 } else { 178 if (res > res_max) 179 res_max = res; 180 if (res < res_min) 181 res_min = res; 182 } 183 jain += (res * res); 184 result += res; 185 break; 186 } 187 } 188 fclose(fp); 189 unlink(filename); 190 } 191 192 jain *= ninst; 193 jain = (result * result) / jain; 194 195 printf("%s %.2f Mbps\n", reverse ? "TCP_MAERTS" : "TCP_STREAM", result); 196 printf("min/max (jain) %.2f Mbps/%.2f Mbps (%f)\n", 197 res_min, res_max, jain); 198 199 exit(0); 200 } 201