1 /*	$NetBSD: nameibench.c,v 1.1 2009/01/29 21:24:19 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <time.h>
39 #include <pthread.h>
40 #include <inttypes.h>
41 #include <signal.h>
42 
43 #define	MAXFILES	4096
44 
45 const int primes[] = {
46 	233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
47 	293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
48 	367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
49 	433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
50 	499, 503, 509, 521, 523, 541,
51 };
52 
53 char	**sa;
54 int	sasize;
55 int	sacnt;
56 struct	timespec sts;
57 struct	timespec ets;
58 pthread_barrier_t	barrier;
59 pthread_mutex_t	lock;
60 volatile sig_atomic_t	stop;
61 double	nlookups;
62 double	ideal;
63 
64 static void
65 makelist(void)
66 {
67 	char buf[MAXPATHLEN], *p;
68 	size_t l;
69 	FILE *fp;
70 
71 	fp = popen("/usr/bin/locate x", "r");
72 	if (fp == NULL) {
73 		perror("popen");
74 		exit(EXIT_FAILURE);
75 	}
76 
77 	while (fgets(buf, sizeof(buf), fp) != NULL) {
78 		l = strlen(buf) + 1;
79 		p = malloc(l);
80 		if (p == NULL) {
81 			perror("malloc");
82 			exit(EXIT_FAILURE);
83 		}
84 		strcpy(p, buf);
85 		p[l - 2] = '\0';
86 		if (sacnt == sasize) {
87 			sasize += 256;
88 			sa = realloc(sa, sizeof(*sa) * sasize);
89 			if (sa == NULL) {
90 				perror("realloc");
91 				exit(EXIT_FAILURE);
92 			}
93 		}
94 		sa[sacnt++] = p;
95 		if (sacnt == MAXFILES) {
96 			break;
97 		}
98 	}
99 
100 	fclose(fp);
101 }
102 
103 static void
104 lookups(int idx)
105 {
106 	unsigned int p, c;
107 
108 	for (c = 0, p = 0; !stop; c++) {
109 		p += primes[idx];
110 		if (p >= sacnt) {
111 			p %= sacnt;
112 		}
113 		(void)access(sa[p], F_OK);
114 
115 	}
116 
117 	pthread_mutex_lock(&lock);
118 	nlookups += c;
119 	pthread_mutex_unlock(&lock);
120 }
121 
122 static void
123 start(void)
124 {
125 
126 	(void)pthread_barrier_wait(&barrier);
127 	if (clock_gettime(CLOCK_MONOTONIC, &sts)) {
128 		perror("clock_gettime");
129 		exit(EXIT_FAILURE);
130 	}
131 }
132 
133 static void
134 end(void)
135 {
136 
137 	if (clock_gettime(CLOCK_MONOTONIC, &ets)) {
138 		perror("clock_gettime");
139 		exit(EXIT_FAILURE);
140 	}
141 	(void)pthread_barrier_wait(&barrier);
142 }
143 
144 static void *
145 thread(void *cookie)
146 {
147 
148 	start();
149 	lookups((int)(uintptr_t)cookie);
150 	end();
151 
152 	return NULL;
153 }
154 
155 static void
156 sigalrm(int junk)
157 {
158 
159 	stop = (sig_atomic_t)1;
160 }
161 
162 static void
163 run(int nt)
164 {
165 	pthread_t pt;
166 	double c;
167 	int i;
168 	long us;
169 
170 	if (pthread_barrier_init(&barrier, NULL, nt + 1)) {
171 		fprintf(stderr, "pthread_barrier_init\n");
172 		exit(EXIT_FAILURE);
173 	}
174 
175 	nlookups = 0;
176 	stop = 0;
177 	for (i = 0; i < nt; i++) {
178 		if (pthread_create(&pt, NULL, thread, (void *)(uintptr_t)i)) {
179 			fprintf(stderr, "pthread_create\n");
180 			exit(EXIT_FAILURE);
181 		}
182 	}
183 	start();
184 	alarm(10);
185 	end();
186 	us = (long)(ets.tv_sec * (uint64_t)1000000 + ets.tv_nsec / 1000);
187 	us -= (long)(sts.tv_sec * (uint64_t)1000000 + sts.tv_nsec / 1000);
188 	c = nlookups * 1000000.0 / us;
189 	if (ideal == 0) {
190 		ideal = c;
191 	}
192 	printf("%d\t%d\t%.0f\t%.0f\n", sacnt, nt, c, ideal * nt);
193 
194 	if (pthread_barrier_destroy(&barrier)) {
195 		fprintf(stderr, "pthread_barrier_destroy\n");
196 		exit(EXIT_FAILURE);
197 	}
198 }
199 
200 int
201 main(int argc, char **argv)
202 {
203 	int i, mt;
204 
205 	(void)setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
206 	if (argc < 2) {
207 		mt = sysconf(_SC_NPROCESSORS_ONLN);
208 	} else {
209 		mt = atoi(argv[1]);
210 		if (mt < 1) {
211 			mt = 1;
212 		}
213 	}
214 	if (pthread_mutex_init(&lock, NULL)) {
215 		fprintf(stderr, "pthread_mutex_init\n");
216 		exit(EXIT_FAILURE);
217 	}
218 	makelist();
219 	(void)signal(SIGALRM, sigalrm);
220 	printf("# nname\tnthr\tpersec\tideal\n");
221 	for (i = 1; i <= mt; i++) {
222 		run(i);
223 	}
224 	exit(EXIT_SUCCESS);
225 }
226