]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/perf_index/perf_index.c
xnu-7195.101.1.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 {
0a7de745
A
15 char* my_name;
16 char* test_name;
17 int num_threads;
18 long long length;
19 int test_argc;
20 void** test_argv;
fe8ab488
A
21} parsed_args_t;
22
23typedef struct test_struct {
0a7de745
A
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;
fe8ab488
A
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
0a7de745
A
37int
38parse_args(int argc, char** argv, parsed_args_t* parsed_args)
39{
40 if (argc != 4) {
41 return -1;
42 }
43
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;
50 return 0;
fe8ab488
A
51}
52
0a7de745
A
53void
54print_usage(char** argv)
55{
56 printf("Usage: %s test_name threads length\n", argv[0]);
fe8ab488
A
57}
58
0a7de745
A
59int
60find_test(char* test_name, char* test_path)
61{
62 char binpath[MAXPATHLEN];
63 char* dirpath;
64 uint32_t size = sizeof(binpath);
65 int retval;
66
67 retval = _NSGetExecutablePath(binpath, &size);
68 assert(retval == 0);
69 dirpath = dirname(binpath);
70
71 snprintf(test_path, MAXPATHLEN, "%s/perfindex-%s.dylib", dirpath, test_name);
72 if (access(test_path, F_OK) == 0) {
73 return 0;
74 } else {
75 return -1;
76 }
fe8ab488
A
77}
78
0a7de745
A
79int
80load_test(char* path, test_t* test)
81{
82 void* handle;
83 void* p;
fe8ab488 84
0a7de745
A
85 handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
86 if (!handle) {
87 return -1;
88 }
fe8ab488
A
89
90
0a7de745
A
91 p = dlsym(handle, "setup");
92 test->setup = (int (*)(int, long long, int, void **))p;
fe8ab488 93
0a7de745
A
94 p = dlsym(handle, "execute");
95 test->execute = (int (*)(int, int, long long, int, void **))p;
96 if (p == NULL) {
97 return -1;
98 }
fe8ab488 99
0a7de745
A
100 p = dlsym(handle, "cleanup");
101 test->cleanup = (int (*)(int, long long))p;
fe8ab488 102
0a7de745
A
103 p = dlsym(handle, "error_str");
104 test->error_str_ptr = (char**)p;
fe8ab488 105
0a7de745 106 return 0;
fe8ab488
A
107}
108
0a7de745
A
109void
110start_timer(struct timeval *tp)
111{
112 gettimeofday(tp, NULL);
fe8ab488
A
113}
114
0a7de745
A
115void
116end_timer(struct timeval *tp)
117{
118 struct timeval tend;
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;
123 } else {
124 tp->tv_sec = tend.tv_sec - tp->tv_sec - 1;
125 tp->tv_usec = tend.tv_usec - tp->tv_usec + 1000000;
126 }
fe8ab488
A
127}
128
0a7de745
A
129void
130print_timer(struct timeval *tp)
131{
132 printf("%ld.%06d\n", tp->tv_sec, tp->tv_usec);
fe8ab488
A
133}
134
0a7de745
A
135static void*
136thread_setup(void *arg)
137{
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;
141
142 if (work_remainder > my_index) {
143 work_size++;
144 }
145
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);
150 }
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);
154 return NULL;
fe8ab488
A
155}
156
0a7de745
A
157int
158main(int argc, char** argv)
159{
160 int retval;
161 int thread_index;
162 struct timeval timer;
163 pthread_t* threads;
164 int thread_retval;
165 void* thread_retval_ptr = &thread_retval;
166 char test_path[MAXPATHLEN];
167
168 retval = parse_args(argc, argv, &args);
169 if (retval) {
170 print_usage(argv);
171 return -1;
172 }
173
174 retval = find_test(args.test_name, test_path);
175 if (retval) {
176 printf("Unable to find test %s\n", args.test_name);
177 return -1;
178 }
179
180 load_test(test_path, &test);
181 if (retval) {
182 printf("Unable to load test %s\n", args.test_name);
183 return -1;
184 }
185
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;
190
191 if (test.setup) {
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);
195 return -1;
196 }
197 }
198
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);
202 assert(retval == 0);
203 }
204
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);
208 }
209 pthread_mutex_unlock(&ready_thread_count_lock);
210
211 start_timer(&timer);
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);
217 }
218 }
219 end_timer(&timer);
220
221 if (test.cleanup) {
222 retval = test.cleanup(args.num_threads, args.length);
223 }
224 if (retval == PERFINDEX_FAILURE) {
225 fprintf(stderr, "Test cleanup failed: %s\n", *test.error_str_ptr);
226 free(threads);
227 return -1;
228 }
229
230 print_timer(&timer);
231
232 free(threads);
233
234 return 0;
fe8ab488 235}