1*19c3b8c2SApple OSS Distributions #include <stdlib.h>
2*19c3b8c2SApple OSS Distributions #include <dlfcn.h>
3*19c3b8c2SApple OSS Distributions #include <stdio.h>
4*19c3b8c2SApple OSS Distributions #include <sys/param.h>
5*19c3b8c2SApple OSS Distributions #include <sys/time.h>
6*19c3b8c2SApple OSS Distributions #include <pthread.h>
7*19c3b8c2SApple OSS Distributions #include <assert.h>
8*19c3b8c2SApple OSS Distributions #include <mach-o/dyld.h>
9*19c3b8c2SApple OSS Distributions #include <string.h>
10*19c3b8c2SApple OSS Distributions #include <libgen.h>
11*19c3b8c2SApple OSS Distributions #include <unistd.h>
12*19c3b8c2SApple OSS Distributions #include "fail.h"
13*19c3b8c2SApple OSS Distributions
14*19c3b8c2SApple OSS Distributions typedef struct parsed_args_struct {
15*19c3b8c2SApple OSS Distributions char* my_name;
16*19c3b8c2SApple OSS Distributions char* test_name;
17*19c3b8c2SApple OSS Distributions int num_threads;
18*19c3b8c2SApple OSS Distributions long long length;
19*19c3b8c2SApple OSS Distributions int test_argc;
20*19c3b8c2SApple OSS Distributions void** test_argv;
21*19c3b8c2SApple OSS Distributions } parsed_args_t;
22*19c3b8c2SApple OSS Distributions
23*19c3b8c2SApple OSS Distributions typedef struct test_struct {
24*19c3b8c2SApple OSS Distributions int (*setup)(int, long long, int, void**);
25*19c3b8c2SApple OSS Distributions int (*execute)(int, int, long long, int, void**);
26*19c3b8c2SApple OSS Distributions int (*cleanup)(int, long long);
27*19c3b8c2SApple OSS Distributions char** error_str_ptr;
28*19c3b8c2SApple OSS Distributions } test_t;
29*19c3b8c2SApple OSS Distributions
30*19c3b8c2SApple OSS Distributions parsed_args_t args;
31*19c3b8c2SApple OSS Distributions test_t test;
32*19c3b8c2SApple OSS Distributions int ready_thread_count;
33*19c3b8c2SApple OSS Distributions pthread_mutex_t ready_thread_count_lock;
34*19c3b8c2SApple OSS Distributions pthread_cond_t start_cvar;
35*19c3b8c2SApple OSS Distributions pthread_cond_t threads_ready_cvar;
36*19c3b8c2SApple OSS Distributions
37*19c3b8c2SApple OSS Distributions int
parse_args(int argc,char ** argv,parsed_args_t * parsed_args)38*19c3b8c2SApple OSS Distributions parse_args(int argc, char** argv, parsed_args_t* parsed_args)
39*19c3b8c2SApple OSS Distributions {
40*19c3b8c2SApple OSS Distributions if (argc != 4) {
41*19c3b8c2SApple OSS Distributions return -1;
42*19c3b8c2SApple OSS Distributions }
43*19c3b8c2SApple OSS Distributions
44*19c3b8c2SApple OSS Distributions parsed_args->my_name = argv[0];
45*19c3b8c2SApple OSS Distributions parsed_args->test_name = argv[1];
46*19c3b8c2SApple OSS Distributions parsed_args->num_threads = atoi(argv[2]);
47*19c3b8c2SApple OSS Distributions parsed_args->length = strtoll(argv[3], NULL, 10);
48*19c3b8c2SApple OSS Distributions parsed_args->test_argc = 0;
49*19c3b8c2SApple OSS Distributions parsed_args->test_argv = NULL;
50*19c3b8c2SApple OSS Distributions return 0;
51*19c3b8c2SApple OSS Distributions }
52*19c3b8c2SApple OSS Distributions
53*19c3b8c2SApple OSS Distributions void
print_usage(char ** argv)54*19c3b8c2SApple OSS Distributions print_usage(char** argv)
55*19c3b8c2SApple OSS Distributions {
56*19c3b8c2SApple OSS Distributions printf("Usage: %s test_name threads length\n", argv[0]);
57*19c3b8c2SApple OSS Distributions }
58*19c3b8c2SApple OSS Distributions
59*19c3b8c2SApple OSS Distributions int
find_test(char * test_name,char * test_path)60*19c3b8c2SApple OSS Distributions find_test(char* test_name, char* test_path)
61*19c3b8c2SApple OSS Distributions {
62*19c3b8c2SApple OSS Distributions char binpath[MAXPATHLEN];
63*19c3b8c2SApple OSS Distributions char* dirpath;
64*19c3b8c2SApple OSS Distributions uint32_t size = sizeof(binpath);
65*19c3b8c2SApple OSS Distributions int retval;
66*19c3b8c2SApple OSS Distributions
67*19c3b8c2SApple OSS Distributions retval = _NSGetExecutablePath(binpath, &size);
68*19c3b8c2SApple OSS Distributions assert(retval == 0);
69*19c3b8c2SApple OSS Distributions dirpath = dirname(binpath);
70*19c3b8c2SApple OSS Distributions
71*19c3b8c2SApple OSS Distributions snprintf(test_path, MAXPATHLEN, "%s/perfindex-%s.dylib", dirpath, test_name);
72*19c3b8c2SApple OSS Distributions if (access(test_path, F_OK) == 0) {
73*19c3b8c2SApple OSS Distributions return 0;
74*19c3b8c2SApple OSS Distributions } else {
75*19c3b8c2SApple OSS Distributions return -1;
76*19c3b8c2SApple OSS Distributions }
77*19c3b8c2SApple OSS Distributions }
78*19c3b8c2SApple OSS Distributions
79*19c3b8c2SApple OSS Distributions int
load_test(char * path,test_t * test)80*19c3b8c2SApple OSS Distributions load_test(char* path, test_t* test)
81*19c3b8c2SApple OSS Distributions {
82*19c3b8c2SApple OSS Distributions void* handle;
83*19c3b8c2SApple OSS Distributions void* p;
84*19c3b8c2SApple OSS Distributions
85*19c3b8c2SApple OSS Distributions handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
86*19c3b8c2SApple OSS Distributions if (!handle) {
87*19c3b8c2SApple OSS Distributions return -1;
88*19c3b8c2SApple OSS Distributions }
89*19c3b8c2SApple OSS Distributions
90*19c3b8c2SApple OSS Distributions
91*19c3b8c2SApple OSS Distributions p = dlsym(handle, "setup");
92*19c3b8c2SApple OSS Distributions test->setup = (int (*)(int, long long, int, void **))p;
93*19c3b8c2SApple OSS Distributions
94*19c3b8c2SApple OSS Distributions p = dlsym(handle, "execute");
95*19c3b8c2SApple OSS Distributions test->execute = (int (*)(int, int, long long, int, void **))p;
96*19c3b8c2SApple OSS Distributions if (p == NULL) {
97*19c3b8c2SApple OSS Distributions return -1;
98*19c3b8c2SApple OSS Distributions }
99*19c3b8c2SApple OSS Distributions
100*19c3b8c2SApple OSS Distributions p = dlsym(handle, "cleanup");
101*19c3b8c2SApple OSS Distributions test->cleanup = (int (*)(int, long long))p;
102*19c3b8c2SApple OSS Distributions
103*19c3b8c2SApple OSS Distributions p = dlsym(handle, "error_str");
104*19c3b8c2SApple OSS Distributions test->error_str_ptr = (char**)p;
105*19c3b8c2SApple OSS Distributions
106*19c3b8c2SApple OSS Distributions return 0;
107*19c3b8c2SApple OSS Distributions }
108*19c3b8c2SApple OSS Distributions
109*19c3b8c2SApple OSS Distributions void
start_timer(struct timeval * tp)110*19c3b8c2SApple OSS Distributions start_timer(struct timeval *tp)
111*19c3b8c2SApple OSS Distributions {
112*19c3b8c2SApple OSS Distributions gettimeofday(tp, NULL);
113*19c3b8c2SApple OSS Distributions }
114*19c3b8c2SApple OSS Distributions
115*19c3b8c2SApple OSS Distributions void
end_timer(struct timeval * tp)116*19c3b8c2SApple OSS Distributions end_timer(struct timeval *tp)
117*19c3b8c2SApple OSS Distributions {
118*19c3b8c2SApple OSS Distributions struct timeval tend;
119*19c3b8c2SApple OSS Distributions gettimeofday(&tend, NULL);
120*19c3b8c2SApple OSS Distributions if (tend.tv_usec >= tp->tv_usec) {
121*19c3b8c2SApple OSS Distributions tp->tv_sec = tend.tv_sec - tp->tv_sec;
122*19c3b8c2SApple OSS Distributions tp->tv_usec = tend.tv_usec - tp->tv_usec;
123*19c3b8c2SApple OSS Distributions } else {
124*19c3b8c2SApple OSS Distributions tp->tv_sec = tend.tv_sec - tp->tv_sec - 1;
125*19c3b8c2SApple OSS Distributions tp->tv_usec = tend.tv_usec - tp->tv_usec + 1000000;
126*19c3b8c2SApple OSS Distributions }
127*19c3b8c2SApple OSS Distributions }
128*19c3b8c2SApple OSS Distributions
129*19c3b8c2SApple OSS Distributions void
print_timer(struct timeval * tp)130*19c3b8c2SApple OSS Distributions print_timer(struct timeval *tp)
131*19c3b8c2SApple OSS Distributions {
132*19c3b8c2SApple OSS Distributions printf("%ld.%06d\n", tp->tv_sec, tp->tv_usec);
133*19c3b8c2SApple OSS Distributions }
134*19c3b8c2SApple OSS Distributions
135*19c3b8c2SApple OSS Distributions static void*
thread_setup(void * arg)136*19c3b8c2SApple OSS Distributions thread_setup(void *arg)
137*19c3b8c2SApple OSS Distributions {
138*19c3b8c2SApple OSS Distributions int my_index = (int)arg;
139*19c3b8c2SApple OSS Distributions long long work_size = args.length / args.num_threads;
140*19c3b8c2SApple OSS Distributions int work_remainder = args.length % args.num_threads;
141*19c3b8c2SApple OSS Distributions
142*19c3b8c2SApple OSS Distributions if (work_remainder > my_index) {
143*19c3b8c2SApple OSS Distributions work_size++;
144*19c3b8c2SApple OSS Distributions }
145*19c3b8c2SApple OSS Distributions
146*19c3b8c2SApple OSS Distributions pthread_mutex_lock(&ready_thread_count_lock);
147*19c3b8c2SApple OSS Distributions ready_thread_count++;
148*19c3b8c2SApple OSS Distributions if (ready_thread_count == args.num_threads) {
149*19c3b8c2SApple OSS Distributions pthread_cond_signal(&threads_ready_cvar);
150*19c3b8c2SApple OSS Distributions }
151*19c3b8c2SApple OSS Distributions pthread_cond_wait(&start_cvar, &ready_thread_count_lock);
152*19c3b8c2SApple OSS Distributions pthread_mutex_unlock(&ready_thread_count_lock);
153*19c3b8c2SApple OSS Distributions test.execute(my_index, args.num_threads, work_size, args.test_argc, args.test_argv);
154*19c3b8c2SApple OSS Distributions return NULL;
155*19c3b8c2SApple OSS Distributions }
156*19c3b8c2SApple OSS Distributions
157*19c3b8c2SApple OSS Distributions int
main(int argc,char ** argv)158*19c3b8c2SApple OSS Distributions main(int argc, char** argv)
159*19c3b8c2SApple OSS Distributions {
160*19c3b8c2SApple OSS Distributions int retval;
161*19c3b8c2SApple OSS Distributions int thread_index;
162*19c3b8c2SApple OSS Distributions struct timeval timer;
163*19c3b8c2SApple OSS Distributions pthread_t* threads;
164*19c3b8c2SApple OSS Distributions int thread_retval;
165*19c3b8c2SApple OSS Distributions void* thread_retval_ptr = &thread_retval;
166*19c3b8c2SApple OSS Distributions char test_path[MAXPATHLEN];
167*19c3b8c2SApple OSS Distributions
168*19c3b8c2SApple OSS Distributions retval = parse_args(argc, argv, &args);
169*19c3b8c2SApple OSS Distributions if (retval) {
170*19c3b8c2SApple OSS Distributions print_usage(argv);
171*19c3b8c2SApple OSS Distributions return -1;
172*19c3b8c2SApple OSS Distributions }
173*19c3b8c2SApple OSS Distributions
174*19c3b8c2SApple OSS Distributions retval = find_test(args.test_name, test_path);
175*19c3b8c2SApple OSS Distributions if (retval) {
176*19c3b8c2SApple OSS Distributions printf("Unable to find test %s\n", args.test_name);
177*19c3b8c2SApple OSS Distributions return -1;
178*19c3b8c2SApple OSS Distributions }
179*19c3b8c2SApple OSS Distributions
180*19c3b8c2SApple OSS Distributions load_test(test_path, &test);
181*19c3b8c2SApple OSS Distributions if (retval) {
182*19c3b8c2SApple OSS Distributions printf("Unable to load test %s\n", args.test_name);
183*19c3b8c2SApple OSS Distributions return -1;
184*19c3b8c2SApple OSS Distributions }
185*19c3b8c2SApple OSS Distributions
186*19c3b8c2SApple OSS Distributions pthread_cond_init(&threads_ready_cvar, NULL);
187*19c3b8c2SApple OSS Distributions pthread_cond_init(&start_cvar, NULL);
188*19c3b8c2SApple OSS Distributions pthread_mutex_init(&ready_thread_count_lock, NULL);
189*19c3b8c2SApple OSS Distributions ready_thread_count = 0;
190*19c3b8c2SApple OSS Distributions
191*19c3b8c2SApple OSS Distributions if (test.setup) {
192*19c3b8c2SApple OSS Distributions retval = test.setup(args.num_threads, args.length, 0, NULL);
193*19c3b8c2SApple OSS Distributions if (retval == PERFINDEX_FAILURE) {
194*19c3b8c2SApple OSS Distributions fprintf(stderr, "Test setup failed: %s\n", *test.error_str_ptr);
195*19c3b8c2SApple OSS Distributions return -1;
196*19c3b8c2SApple OSS Distributions }
197*19c3b8c2SApple OSS Distributions }
198*19c3b8c2SApple OSS Distributions
199*19c3b8c2SApple OSS Distributions threads = (pthread_t*)malloc(sizeof(pthread_t) * args.num_threads);
200*19c3b8c2SApple OSS Distributions for (thread_index = 0; thread_index < args.num_threads; thread_index++) {
201*19c3b8c2SApple OSS Distributions retval = pthread_create(&threads[thread_index], NULL, thread_setup, (void*)(long)thread_index);
202*19c3b8c2SApple OSS Distributions assert(retval == 0);
203*19c3b8c2SApple OSS Distributions }
204*19c3b8c2SApple OSS Distributions
205*19c3b8c2SApple OSS Distributions pthread_mutex_lock(&ready_thread_count_lock);
206*19c3b8c2SApple OSS Distributions if (ready_thread_count != args.num_threads) {
207*19c3b8c2SApple OSS Distributions pthread_cond_wait(&threads_ready_cvar, &ready_thread_count_lock);
208*19c3b8c2SApple OSS Distributions }
209*19c3b8c2SApple OSS Distributions pthread_mutex_unlock(&ready_thread_count_lock);
210*19c3b8c2SApple OSS Distributions
211*19c3b8c2SApple OSS Distributions start_timer(&timer);
212*19c3b8c2SApple OSS Distributions pthread_cond_broadcast(&start_cvar);
213*19c3b8c2SApple OSS Distributions for (thread_index = 0; thread_index < args.num_threads; thread_index++) {
214*19c3b8c2SApple OSS Distributions pthread_join(threads[thread_index], &thread_retval_ptr);
215*19c3b8c2SApple OSS Distributions if (**test.error_str_ptr) {
216*19c3b8c2SApple OSS Distributions printf("Test failed: %s\n", *test.error_str_ptr);
217*19c3b8c2SApple OSS Distributions }
218*19c3b8c2SApple OSS Distributions }
219*19c3b8c2SApple OSS Distributions end_timer(&timer);
220*19c3b8c2SApple OSS Distributions
221*19c3b8c2SApple OSS Distributions if (test.cleanup) {
222*19c3b8c2SApple OSS Distributions retval = test.cleanup(args.num_threads, args.length);
223*19c3b8c2SApple OSS Distributions }
224*19c3b8c2SApple OSS Distributions if (retval == PERFINDEX_FAILURE) {
225*19c3b8c2SApple OSS Distributions fprintf(stderr, "Test cleanup failed: %s\n", *test.error_str_ptr);
226*19c3b8c2SApple OSS Distributions free(threads);
227*19c3b8c2SApple OSS Distributions return -1;
228*19c3b8c2SApple OSS Distributions }
229*19c3b8c2SApple OSS Distributions
230*19c3b8c2SApple OSS Distributions print_timer(&timer);
231*19c3b8c2SApple OSS Distributions
232*19c3b8c2SApple OSS Distributions free(threads);
233*19c3b8c2SApple OSS Distributions
234*19c3b8c2SApple OSS Distributions return 0;
235*19c3b8c2SApple OSS Distributions }
236