]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/perf_index/perf_index.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / tools / tests / perf_index / perf_index.c
CommitLineData
fe8ab488
A
1#include <stdlib.h>
2#include <dlfcn.h>
3#include <stdio.h>
4#include <sys/param.h>
5#include <sys/time.h>
6#include <pthread.h>
7#include <assert.h>
8#include <mach-o/dyld.h>
9#include <string.h>
10#include <libgen.h>
11#include <unistd.h>
12#include "fail.h"
13
14typedef struct parsed_args_struct {
15 char* my_name;
16 char* test_name;
17 int num_threads;
18 long long length;
19 int test_argc;
20 void** test_argv;
21} parsed_args_t;
22
23typedef 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);
27 char** error_str_ptr;
28} test_t;
29
30parsed_args_t args;
31test_t test;
32int ready_thread_count;
33pthread_mutex_t ready_thread_count_lock;
34pthread_cond_t start_cvar;
35pthread_cond_t threads_ready_cvar;
36
37int parse_args(int argc, char** argv, parsed_args_t* parsed_args) {
38 if(argc != 4) {
39 return -1;
40 }
41
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;
48 return 0;
49}
50
51void print_usage(char** argv) {
52 printf("Usage: %s test_name threads length\n", argv[0]);
53}
54
55int find_test(char* test_name, char* test_path) {
56 char binpath[MAXPATHLEN];
57 char* dirpath;
58 uint32_t size = sizeof(binpath);
59 int retval;
60
61 retval = _NSGetExecutablePath(binpath, &size);
62 assert(retval == 0);
63 dirpath = dirname(binpath);
64
65 snprintf(test_path, MAXPATHLEN, "%s/perfindex-%s.dylib", dirpath, test_name);
66 if(access(test_path, F_OK) == 0)
67 return 0;
68 else
69 return -1;
70}
71
72int load_test(char* path, test_t* test) {
73 void* handle;
74 void* p;
75
76 handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
77 if(!handle) {
78 return -1;
79 }
80
81
82 p = dlsym(handle, "setup");
83 test->setup = (int (*)(int, long long, int, void **))p;
84
85 p = dlsym(handle, "execute");
86 test->execute = (int (*)(int, int, long long, int, void **))p;
87 if(p == NULL)
88 return -1;
89
90 p = dlsym(handle, "cleanup");
91 test->cleanup = (int (*)(int, long long))p;
92
93 p = dlsym(handle, "error_str");
94 test->error_str_ptr = (char**)p;
95
96 return 0;
97}
98
99void start_timer(struct timeval *tp) {
100 gettimeofday(tp, NULL);
101}
102
103void end_timer(struct timeval *tp) {
104 struct timeval tend;
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;
109 }
110 else {
111 tp->tv_sec = tend.tv_sec - tp->tv_sec - 1;
112 tp->tv_usec = tend.tv_usec - tp->tv_usec + 1000000;
113 }
114}
115
116void print_timer(struct timeval *tp) {
117 printf("%ld.%06d\n", tp->tv_sec, tp->tv_usec);
118}
119
120static 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;
124
125 if(work_remainder > my_index) {
126 work_size++;
127 }
128
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);
136 return NULL;
137}
138
139int main(int argc, char** argv) {
140 int retval;
141 int thread_index;
142 struct timeval timer;
143 pthread_t* threads;
144 int thread_retval;
145 void* thread_retval_ptr = &thread_retval;
146 char test_path[MAXPATHLEN];
147
148 retval = parse_args(argc, argv, &args);
149 if(retval) {
150 print_usage(argv);
151 return -1;
152 }
153
154 retval = find_test(args.test_name, test_path);
155 if(retval) {
156 printf("Unable to find test %s\n", args.test_name);
157 return -1;
158 }
159
160 load_test(test_path, &test);
161 if(retval) {
162 printf("Unable to load test %s\n", args.test_name);
163 return -1;
164 }
165
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;
170
171 if(test.setup) {
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);
175 return -1;
176 }
177 }
178
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);
182 assert(retval == 0);
183 }
184
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);
188 }
189 pthread_mutex_unlock(&ready_thread_count_lock);
190
191 start_timer(&timer);
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);
197 }
198 }
199 end_timer(&timer);
200
201 if(test.cleanup)
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);
205 free(threads);
206 return -1;
207 }
208
209 print_timer(&timer);
210
211 free(threads);
212
213 return 0;
214}