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