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 struct netperf_child { 15 int pipes[2]; 16 }; 17 18 static void 19 usage(const char *cmd) 20 { 21 fprintf(stderr, "%s -H host [-l len_s] [-i instances]\n", cmd); 22 exit(1); 23 } 24 25 int 26 main(int argc, char *argv[]) 27 { 28 struct netperf_child *instance; 29 char len_str[32]; 30 char *args[32]; 31 const char *host; 32 volatile int ninst; 33 int len, ninst_done; 34 int opt, i, null_fd; 35 double result; 36 37 host = NULL; 38 ninst = 2; 39 len = 10; 40 41 while ((opt = getopt(argc, argv, "i:H:l:")) != -1) { 42 switch (opt) { 43 case 'i': 44 ninst = strtoul(optarg, NULL, 10); 45 break; 46 47 case 'H': 48 host = optarg; 49 break; 50 51 case 'l': 52 len = strtoul(optarg, NULL, 10); 53 break; 54 55 default: 56 usage(argv[0]); 57 } 58 } 59 if (ninst <= 0 || host == NULL || len <= 0) 60 usage(argv[0]); 61 62 snprintf(len_str, sizeof(len_str), "%d", len); 63 64 i = 0; 65 args[i++] = __DECONST(char *, NETPERF_CMD); 66 args[i++] = __DECONST(char *, "-P0"); 67 args[i++] = __DECONST(char *, "-H"); 68 args[i++] = __DECONST(char *, host); 69 args[i++] = __DECONST(char *, "-l"); 70 args[i++] = __DECONST(char *, len_str); 71 args[i++] = __DECONST(char *, "-t"); 72 args[i++] = __DECONST(char *, "TCP_CC"); 73 args[i] = NULL; 74 75 instance = calloc(ninst, sizeof(struct netperf_child)); 76 if (instance == NULL) { 77 fprintf(stderr, "calloc failed\n"); 78 exit(1); 79 } 80 81 null_fd = open("/dev/null", O_RDWR); 82 if (null_fd < 0) { 83 fprintf(stderr, "open null failed: %d\n", errno); 84 exit(1); 85 } 86 87 for (i = 0; i < ninst; ++i) { 88 if (pipe(instance[i].pipes) < 0) { 89 fprintf(stderr, "pipe %dth failed: %d\n", i, errno); 90 exit(1); 91 } 92 } 93 94 for (i = 0; i < ninst; ++i) { 95 pid_t pid; 96 97 pid = vfork(); 98 if (pid == 0) { 99 int ret; 100 101 dup2(instance[i].pipes[1], STDOUT_FILENO); 102 dup2(null_fd, STDERR_FILENO); 103 ret = execv(NETPERF_PATH, args); 104 if (ret < 0) { 105 fprintf(stderr, "execv %d failed: %d\n", 106 i, errno); 107 _exit(1); 108 } 109 /* Never reached */ 110 abort(); 111 } else if (pid < 0) { 112 fprintf(stderr, "vfork %d failed: %d\n", i, errno); 113 exit(1); 114 } 115 close(instance[i].pipes[1]); 116 instance[i].pipes[1] = -1; 117 } 118 119 ninst_done = 0; 120 while (ninst_done < ninst) { 121 pid_t pid; 122 123 pid = waitpid(-1, NULL, 0); 124 if (pid < 0) { 125 fprintf(stderr, "waitpid failed: %d\n", errno); 126 exit(1); 127 } 128 ++ninst_done; 129 } 130 131 result = 0.0; 132 for (i = 0; i < ninst; ++i) { 133 char line[128]; 134 FILE *fp; 135 136 fp = fdopen(instance[i].pipes[0], "r"); 137 if (fp == NULL) { 138 fprintf(stderr, "fdopen %dth failed\n", i); 139 exit(1); 140 } 141 142 while (fgets(line, sizeof(line), fp) != NULL) { 143 int n, arg1, arg2, arg3, arg4; 144 double res, arg5; 145 146 n = sscanf(line, "%d%d%d%d%lf%lf", 147 &arg1, &arg2, &arg3, &arg4, &arg5, &res); 148 if (n == 6) { 149 result += res; 150 break; 151 } 152 } 153 fclose(fp); 154 } 155 printf("TCP_CC %.2f conns/s\n", result); 156 157 exit(0); 158 } 159