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_CC_FILENAME "/tmp/tcp_cc.%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]\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; 37 double result; 38 pid_t mypid; 39 40 host = NULL; 41 ninst = 2; 42 len = 10; 43 44 while ((opt = getopt(argc, argv, "i:H:l:")) != -1) { 45 switch (opt) { 46 case 'i': 47 ninst = strtoul(optarg, NULL, 10); 48 break; 49 50 case 'H': 51 host = optarg; 52 break; 53 54 case 'l': 55 len = strtoul(optarg, NULL, 10); 56 break; 57 58 default: 59 usage(argv[0]); 60 } 61 } 62 if (ninst <= 0 || host == NULL || len <= 0) 63 usage(argv[0]); 64 65 mypid = getpid(); 66 67 snprintf(len_str, sizeof(len_str), "%d", len); 68 69 i = 0; 70 args[i++] = __DECONST(char *, NETPERF_CMD); 71 args[i++] = __DECONST(char *, "-P0"); 72 args[i++] = __DECONST(char *, "-H"); 73 args[i++] = __DECONST(char *, host); 74 args[i++] = __DECONST(char *, "-l"); 75 args[i++] = __DECONST(char *, len_str); 76 args[i++] = __DECONST(char *, "-t"); 77 args[i++] = __DECONST(char *, "TCP_CC"); 78 args[i] = NULL; 79 80 instance = calloc(ninst, sizeof(struct netperf_child)); 81 if (instance == NULL) { 82 fprintf(stderr, "calloc failed\n"); 83 exit(1); 84 } 85 86 null_fd = open("/dev/null", O_RDWR); 87 if (null_fd < 0) { 88 fprintf(stderr, "open null failed: %d\n", errno); 89 exit(1); 90 } 91 92 for (i = 0; i < ninst; ++i) { 93 char filename[128]; 94 95 snprintf(filename, sizeof(filename), TCP_CC_FILENAME, 96 (int)mypid, i); 97 instance[i].fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 98 S_IWUSR | S_IRUSR); 99 if (instance[i].fd < 0) { 100 fprintf(stderr, "open %s failed: %d\n", 101 filename, errno); 102 exit(1); 103 } 104 } 105 106 for (i = 0; i < ninst; ++i) { 107 pid_t pid; 108 109 pid = vfork(); 110 if (pid == 0) { 111 int ret; 112 113 dup2(instance[i].fd, STDOUT_FILENO); 114 dup2(null_fd, STDERR_FILENO); 115 ret = execv(NETPERF_PATH, args); 116 if (ret < 0) { 117 fprintf(stderr, "execv %d failed: %d\n", 118 i, errno); 119 _exit(1); 120 } 121 /* Never reached */ 122 abort(); 123 } else if (pid < 0) { 124 fprintf(stderr, "vfork %d failed: %d\n", i, errno); 125 exit(1); 126 } 127 } 128 129 ninst_done = 0; 130 while (ninst_done < ninst) { 131 pid_t pid; 132 133 pid = waitpid(-1, NULL, 0); 134 if (pid < 0) { 135 fprintf(stderr, "waitpid failed: %d\n", errno); 136 exit(1); 137 } 138 ++ninst_done; 139 } 140 141 result = 0.0; 142 for (i = 0; i < ninst; ++i) { 143 char line[128], filename[128]; 144 FILE *fp; 145 146 close(instance[i].fd); 147 snprintf(filename, sizeof(filename), TCP_CC_FILENAME, 148 (int)mypid, i); 149 fp = fopen(filename, "r"); 150 if (fp == NULL) { 151 fprintf(stderr, "fopen %s failed\n", filename); 152 exit(1); 153 } 154 155 while (fgets(line, sizeof(line), fp) != NULL) { 156 int n, arg1, arg2, arg3, arg4; 157 double res, arg5; 158 159 n = sscanf(line, "%d%d%d%d%lf%lf", 160 &arg1, &arg2, &arg3, &arg4, &arg5, &res); 161 if (n == 6) { 162 result += res; 163 break; 164 } 165 } 166 fclose(fp); 167 unlink(filename); 168 } 169 printf("TCP_CC %.2f conns/s\n", result); 170 171 exit(0); 172 } 173