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
;
37 int parse_args(int argc
, char** argv
, parsed_args_t
* parsed_args
) {
42 parsed_args
->my_name
= argv
[0];
43 parsed_args
->test_name
= argv
[1];
44 parsed_args
->num_threads
= atoi(argv
[2]);
45 parsed_args
->length
= strtoll(argv
[3], NULL
, 10);
46 parsed_args
->test_argc
= 0;
47 parsed_args
->test_argv
= NULL
;
51 void print_usage(char** argv
) {
52 printf("Usage: %s test_name threads length\n", argv
[0]);
55 int find_test(char* test_name
, char* test_path
) {
56 char binpath
[MAXPATHLEN
];
58 uint32_t size
= sizeof(binpath
);
61 retval
= _NSGetExecutablePath(binpath
, &size
);
63 dirpath
= dirname(binpath
);
65 snprintf(test_path
, MAXPATHLEN
, "%s/perfindex-%s.dylib", dirpath
, test_name
);
66 if(access(test_path
, F_OK
) == 0)
72 int load_test(char* path
, test_t
* test
) {
76 handle
= dlopen(path
, RTLD_NOW
| RTLD_LOCAL
);
82 p
= dlsym(handle
, "setup");
83 test
->setup
= (int (*)(int, long long, int, void **))p
;
85 p
= dlsym(handle
, "execute");
86 test
->execute
= (int (*)(int, int, long long, int, void **))p
;
90 p
= dlsym(handle
, "cleanup");
91 test
->cleanup
= (int (*)(int, long long))p
;
93 p
= dlsym(handle
, "error_str");
94 test
->error_str_ptr
= (char**)p
;
99 void start_timer(struct timeval
*tp
) {
100 gettimeofday(tp
, NULL
);
103 void end_timer(struct timeval
*tp
) {
105 gettimeofday(&tend
, NULL
);
106 if(tend
.tv_usec
>= tp
->tv_usec
) {
107 tp
->tv_sec
= tend
.tv_sec
- tp
->tv_sec
;
108 tp
->tv_usec
= tend
.tv_usec
- tp
->tv_usec
;
111 tp
->tv_sec
= tend
.tv_sec
- tp
->tv_sec
- 1;
112 tp
->tv_usec
= tend
.tv_usec
- tp
->tv_usec
+ 1000000;
116 void print_timer(struct timeval
*tp
) {
117 printf("%ld.%06d\n", tp
->tv_sec
, tp
->tv_usec
);
120 static void* thread_setup(void *arg
) {
121 int my_index
= (int)arg
;
122 long long work_size
= args
.length
/ args
.num_threads
;
123 int work_remainder
= args
.length
% args
.num_threads
;
125 if(work_remainder
> my_index
) {
129 pthread_mutex_lock(&ready_thread_count_lock
);
130 ready_thread_count
++;
131 if(ready_thread_count
== args
.num_threads
)
132 pthread_cond_signal(&threads_ready_cvar
);
133 pthread_cond_wait(&start_cvar
, &ready_thread_count_lock
);
134 pthread_mutex_unlock(&ready_thread_count_lock
);
135 test
.execute(my_index
, args
.num_threads
, work_size
, args
.test_argc
, args
.test_argv
);
139 int main(int argc
, char** argv
) {
142 struct timeval timer
;
145 void* thread_retval_ptr
= &thread_retval
;
146 char test_path
[MAXPATHLEN
];
148 retval
= parse_args(argc
, argv
, &args
);
154 retval
= find_test(args
.test_name
, test_path
);
156 printf("Unable to find test %s\n", args
.test_name
);
160 load_test(test_path
, &test
);
162 printf("Unable to load test %s\n", args
.test_name
);
166 pthread_cond_init(&threads_ready_cvar
, NULL
);
167 pthread_cond_init(&start_cvar
, NULL
);
168 pthread_mutex_init(&ready_thread_count_lock
, NULL
);
169 ready_thread_count
= 0;
172 retval
= test
.setup(args
.num_threads
, args
.length
, 0, NULL
);
173 if(retval
== PERFINDEX_FAILURE
) {
174 fprintf(stderr
, "Test setup failed: %s\n", *test
.error_str_ptr
);
179 threads
= (pthread_t
*)malloc(sizeof(pthread_t
)*args
.num_threads
);
180 for(thread_index
= 0; thread_index
< args
.num_threads
; thread_index
++) {
181 retval
= pthread_create(&threads
[thread_index
], NULL
, thread_setup
, (void*)(long)thread_index
);
185 pthread_mutex_lock(&ready_thread_count_lock
);
186 if(ready_thread_count
!= args
.num_threads
) {
187 pthread_cond_wait(&threads_ready_cvar
, &ready_thread_count_lock
);
189 pthread_mutex_unlock(&ready_thread_count_lock
);
192 pthread_cond_broadcast(&start_cvar
);
193 for(thread_index
= 0; thread_index
< args
.num_threads
; thread_index
++) {
194 pthread_join(threads
[thread_index
], &thread_retval_ptr
);
195 if(**test
.error_str_ptr
) {
196 printf("Test failed: %s\n", *test
.error_str_ptr
);
202 retval
= test
.cleanup(args
.num_threads
, args
.length
);
203 if(retval
== PERFINDEX_FAILURE
) {
204 fprintf(stderr
, "Test cleanup failed: %s\n", *test
.error_str_ptr
);