1/*	$NetBSD: nameibench.c,v 1.3 2019/11/23 20:37:49 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
45const 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
53char	**sa;
54u_int	sasize;
55u_int	sacnt;
56struct	timespec sts;
57struct	timespec ets;
58pthread_barrier_t	barrier;
59pthread_mutex_t	lock;
60volatile sig_atomic_t	stop;
61double	nlookups;
62double	ideal;
63
64static void
65makelist(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
103static void
104lookups(int idx)
105{
106	u_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
122static void
123start(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
133static void
134end(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
144static void *
145thread(void *cookie)
146{
147
148	start();
149	lookups((int)(uintptr_t)cookie);
150	end();
151
152	return NULL;
153}
154
155static void
156sigalrm(int junk)
157{
158
159	stop = (sig_atomic_t)1;
160}
161
162static void
163run(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
200int
201main(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