8 #include <mach-o/dyld.h>
14 typedef struct parsed_args_struct
{
23 typedef struct test_struct
{
24 int (*setup
)(int, long long, int, void**);
25 int (*execute
)(int, int, long long, int, void**);
26 int (*cleanup
)(int, long long);
32 int ready_thread_count
;
33 pthread_mutex_t ready_thread_count_lock
;
34 pthread_cond_t start_cvar
;
35 pthread_cond_t threads_ready_cvar
;
38 parse_args(int argc
, char** argv
, parsed_args_t
* parsed_args
)
44 parsed_args
->my_name
= argv
[0];
45 parsed_args
->test_name
= argv
[1];
46 parsed_args
->num_threads
= atoi(argv
[2]);
47 parsed_args
->length
= strtoll(argv
[3], NULL
, 10);
48 parsed_args
->test_argc
= 0;
49 parsed_args
->test_argv
= NULL
;
54 print_usage(char** argv
)
56 printf("Usage: %s test_name threads length\n", argv
[0]);
60 find_test(char* test_name
, char* test_path
)
62 char binpath
[MAXPATHLEN
];
64 uint32_t size
= sizeof(binpath
);
67 retval
= _NSGetExecutablePath(binpath
, &size
);
69 dirpath
= dirname(binpath
);
71 snprintf(test_path
, MAXPATHLEN
, "%s/perfindex-%s.dylib", dirpath
, test_name
);
72 if (access(test_path
, F_OK
) == 0) {
80 load_test(char* path
, test_t
* test
)
85 handle
= dlopen(path
, RTLD_NOW
| RTLD_LOCAL
);
91 p
= dlsym(handle
, "setup");
92 test
->setup
= (int (*)(int, long long, int, void **))p
;
94 p
= dlsym(handle
, "execute");
95 test
->execute
= (int (*)(int, int, long long, int, void **))p
;
100 p
= dlsym(handle
, "cleanup");
101 test
->cleanup
= (int (*)(int, long long))p
;
103 p
= dlsym(handle
, "error_str");
104 test
->error_str_ptr
= (char**)p
;
110 start_timer(struct timeval
*tp
)
112 gettimeofday(tp
, NULL
);
116 end_timer(struct timeval
*tp
)
119 gettimeofday(&tend
, NULL
);
120 if (tend
.tv_usec
>= tp
->tv_usec
) {
121 tp
->tv_sec
= tend
.tv_sec
- tp
->tv_sec
;
122 tp
->tv_usec
= tend
.tv_usec
- tp
->tv_usec
;
124 tp
->tv_sec
= tend
.tv_sec
- tp
->tv_sec
- 1;
125 tp
->tv_usec
= tend
.tv_usec
- tp
->tv_usec
+ 1000000;
130 print_timer(struct timeval
*tp
)
132 printf("%ld.%06d\n", tp
->tv_sec
, tp
->tv_usec
);
136 thread_setup(void *arg
)
138 int my_index
= (int)arg
;
139 long long work_size
= args
.length
/ args
.num_threads
;
140 int work_remainder
= args
.length
% args
.num_threads
;
142 if (work_remainder
> my_index
) {
146 pthread_mutex_lock(&ready_thread_count_lock
);
147 ready_thread_count
++;
148 if (ready_thread_count
== args
.num_threads
) {
149 pthread_cond_signal(&threads_ready_cvar
);
151 pthread_cond_wait(&start_cvar
, &ready_thread_count_lock
);
152 pthread_mutex_unlock(&ready_thread_count_lock
);
153 test
.execute(my_index
, args
.num_threads
, work_size
, args
.test_argc
, args
.test_argv
);
158 main(int argc
, char** argv
)
162 struct timeval timer
;
165 void* thread_retval_ptr
= &thread_retval
;
166 char test_path
[MAXPATHLEN
];
168 retval
= parse_args(argc
, argv
, &args
);
174 retval
= find_test(args
.test_name
, test_path
);
176 printf("Unable to find test %s\n", args
.test_name
);
180 load_test(test_path
, &test
);
182 printf("Unable to load test %s\n", args
.test_name
);
186 pthread_cond_init(&threads_ready_cvar
, NULL
);
187 pthread_cond_init(&start_cvar
, NULL
);
188 pthread_mutex_init(&ready_thread_count_lock
, NULL
);
189 ready_thread_count
= 0;
192 retval
= test
.setup(args
.num_threads
, args
.length
, 0, NULL
);
193 if (retval
== PERFINDEX_FAILURE
) {
194 fprintf(stderr
, "Test setup failed: %s\n", *test
.error_str_ptr
);
199 threads
= (pthread_t
*)malloc(sizeof(pthread_t
) * args
.num_threads
);
200 for (thread_index
= 0; thread_index
< args
.num_threads
; thread_index
++) {
201 retval
= pthread_create(&threads
[thread_index
], NULL
, thread_setup
, (void*)(long)thread_index
);
205 pthread_mutex_lock(&ready_thread_count_lock
);
206 if (ready_thread_count
!= args
.num_threads
) {
207 pthread_cond_wait(&threads_ready_cvar
, &ready_thread_count_lock
);
209 pthread_mutex_unlock(&ready_thread_count_lock
);
212 pthread_cond_broadcast(&start_cvar
);
213 for (thread_index
= 0; thread_index
< args
.num_threads
; thread_index
++) {
214 pthread_join(threads
[thread_index
], &thread_retval_ptr
);
215 if (**test
.error_str_ptr
) {
216 printf("Test failed: %s\n", *test
.error_str_ptr
);
222 retval
= test
.cleanup(args
.num_threads
, args
.length
);
224 if (retval
== PERFINDEX_FAILURE
) {
225 fprintf(stderr
, "Test cleanup failed: %s\n", *test
.error_str_ptr
);