1#include <stdio.h> 2#include <string.h> 3#include <inttypes.h> 4#include <pthread.h> 5#include "perf_index.h" 6#include <sys/time.h> 7#include <sys/socket.h> 8#include <netdb.h> 9 10#define CONTROL_PORT 17694 11 12static const stress_test_t *stress_tests[] = 13{&cpu_test, &memory_test, &syscall_test, &fault_test, &zfod_test, 14 &file_local_create_test, &file_local_write_test, &file_local_read_test, 15 &file_ram_create_test, &file_ram_read_test, &file_ram_write_test, &iperf_test, 16 &compile_test 17}; 18 19static int num_threads; 20static long long all_len; 21static int test_type; 22static const char *control_host = NULL; 23static const char **test_argv; 24static int test_argc; 25struct in_addr control_host_addr; 26int control_sock; 27const char remote_str[] = "remote"; 28const char ready_msg[] = "Ready"; 29const char done_msg[] = "Done"; 30 31static pthread_cond_t threads_running_cvar; 32static pthread_cond_t start_cvar; 33static int thread_count; 34static pthread_mutex_t count_lock; 35 36static void usage() { 37 int i; 38 fprintf(stderr, "usage: perf_index remote server\n" 39 "or\n" 40 "usage: pref_index type threads size [args]\n\n" 41 "where type is one of:\n"); 42 for(i=0; i<sizeof(stress_tests)/sizeof(stress_test_t*); i++) { 43 fprintf(stderr, "%s ", stress_tests[i]->name); 44 } 45 fprintf(stderr, "\n"); 46 exit(1); 47} 48 49static int validate_args(int argc, const char **argv) { 50 int i; 51 int ret; 52 int found = 0; 53 54 if(argc < 3) { 55 return -1; 56 } 57 if(argc==3 && strcmp(argv[1], remote_str) == 0) 58 return 0; 59 60 61 if(argc < 4) 62 return -1; 63 64 ret = -1; 65 for(i=0; i<sizeof(stress_tests)/sizeof(stress_test_t*); i++) { 66 if(strcmp(argv[1], stress_tests[i]->name) == 0) { 67 ret = i; 68 found = 1; 69 break; 70 } 71 } 72 73 if(!found) 74 return -1; 75 76 if(stress_tests[i]->validate(argc-4, argv+4)) 77 return ret; 78 else 79 return -1; 80} 81 82int host_to_addr(const char *hostname, struct in_addr *addr) { 83 struct addrinfo *info; 84 int err; 85 if((err = getaddrinfo(hostname, NULL, NULL, &info)) != 0) { 86 return -1; 87 } 88 *addr = ((struct sockaddr_in*)info->ai_addr)->sin_addr; 89 freeaddrinfo(info); 90 return 0; 91} 92 93static void parse_args(int argc, const char **argv); 94 95static void read_params_from_server(void) { 96 struct sockaddr_in addr; 97 char readbuff[1024]; 98 int zerocount = 0; 99 ssize_t offset = 0; 100 ssize_t recv_count; 101 ssize_t i; 102 const char **newargv = malloc(sizeof(char*) * 4); 103 assert(newargv != NULL); 104 105 if(host_to_addr(control_host, &control_host_addr)<0) { 106 fprintf(stderr, "Could not resolve: %s\n", control_host); 107 exit(2); 108 } 109 110 control_sock = socket(PF_INET, SOCK_STREAM, 0); 111 assert(control_sock != -1); 112 addr.sin_family = AF_INET; 113 addr.sin_port = htons(CONTROL_PORT); 114 addr.sin_addr = control_host_addr; 115 bzero(addr.sin_zero, sizeof addr.sin_zero); 116 if(connect(control_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { 117 fprintf(stderr, "Failed to connect to host: %s\n", control_host); 118 exit(3); 119 } 120 121 while(offset<sizeof(readbuff)) { 122 recv_count = recv(control_sock, readbuff+offset, sizeof(readbuff) - offset, 0); 123 if(recv_count<0) { 124 fprintf(stderr, "Failed to receive parameters\n"); 125 exit(3); 126 } 127 128 /* Guard against bad input */ 129 readbuff[sizeof(readbuff)-1] = '\0'; 130 newargv[1] = strdup(readbuff); 131 for(i=offset; i<offset+recv_count; i++) { 132 if(readbuff[i] == '\0') { 133 zerocount++; 134 newargv[zerocount+1] = strdup(&readbuff[i+1]); 135 } 136 } 137 offset += recv_count; 138 if(offset>=2 && readbuff[offset-1] == '\0' && readbuff[offset-2] == '\0') 139 break; 140 } 141 if(zerocount < 3) { 142 fprintf(stderr, "Received invalid parameters"); 143 exit(4); 144 } 145 146 parse_args(zerocount+1, newargv); 147} 148 149static void parse_args(int argc, const char **argv) { 150 test_type = validate_args(argc, argv); 151 if(test_type < 0) 152 usage(); 153 if(strcmp(argv[1], remote_str) == 0) { 154 control_host = argv[2]; 155 read_params_from_server(); 156 } 157 else { 158 num_threads = strtoimax(argv[2], NULL, 10); 159 all_len = strtoll(argv[3], NULL, 10); 160 test_argc = argc - 4; 161 test_argv = argv + 4; 162 } 163} 164 165static void *stress_loop(void *data) { 166 int my_index = (int)data; 167 long long work_size = all_len / num_threads; 168 int work_remainder = all_len % num_threads; 169 170 if(work_remainder > my_index) { 171 work_size++; 172 } 173 174 pthread_mutex_lock(&count_lock); 175 thread_count++; 176 if(thread_count == num_threads) 177 pthread_cond_signal(&threads_running_cvar); 178 pthread_cond_wait(&start_cvar, &count_lock); 179 pthread_mutex_unlock(&count_lock); 180 stress_tests[test_type]->stress(my_index, num_threads, work_size, test_argc, test_argv); 181 return NULL; 182} 183 184void start_timer(struct timeval *tp) { 185 gettimeofday(tp, NULL); 186} 187 188void end_timer(struct timeval *tp) { 189 struct timeval tend; 190 gettimeofday(&tend, NULL); 191 if(tend.tv_usec >= tp->tv_usec) { 192 tp->tv_sec = tend.tv_sec - tp->tv_sec; 193 tp->tv_usec = tend.tv_usec - tp->tv_usec; 194 } 195 else { 196 tp->tv_sec = tend.tv_sec - tp->tv_sec - 1; 197 tp->tv_usec = tend.tv_usec - tp->tv_usec + 1000000; 198 } 199} 200 201void print_timer(struct timeval *tp) { 202 printf("%ld.%06d", tp->tv_sec, tp->tv_usec); 203} 204 205void wait_start(void) { 206 char readbuff[1024]; 207 if(control_host != NULL) { 208 send(control_sock, ready_msg, strlen(ready_msg), 0); 209 while(recv(control_sock, readbuff, sizeof(readbuff), 0)>0); 210 } 211} 212 213void done(void) { 214 send(control_sock, done_msg, strlen(done_msg), 0); 215} 216 217int main(int argc, const char **argv) { 218 int thread_index; 219 pthread_t *threads; 220 parse_args(argc, argv); 221 struct timeval timer; 222 223 stress_tests[test_type]->init(num_threads, all_len, test_argc, test_argv); 224 pthread_cond_init(&threads_running_cvar, NULL); 225 pthread_cond_init(&start_cvar, NULL); 226 pthread_mutex_init(&count_lock, NULL); 227 thread_count = 0; 228 229 threads = (pthread_t*)malloc(sizeof(pthread_t)*num_threads); 230 for(thread_index = 0; thread_index < num_threads; thread_index++) { 231 assert(pthread_create(&threads[thread_index], NULL, stress_loop, (void*)thread_index) == 0); 232 } 233 234 pthread_mutex_lock(&count_lock); 235 if(thread_count != num_threads) 236 pthread_cond_wait(&threads_running_cvar, &count_lock); 237 pthread_mutex_unlock(&count_lock); 238 239 wait_start(); 240 241 start_timer(&timer); 242 pthread_cond_broadcast(&start_cvar); 243 for(thread_index = 0; thread_index < num_threads; thread_index++) { 244 pthread_join(threads[thread_index], NULL); 245 } 246 end_timer(&timer); 247 done(); 248 249 pthread_mutex_destroy(&count_lock); 250 pthread_cond_destroy(&start_cvar); 251 pthread_cond_destroy(&threads_running_cvar); 252 253 stress_tests[test_type]->cleanup(num_threads, all_len); 254 255 print_timer(&timer); 256 printf("\n"); 257 258 return 0; 259} 260