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