gaithrstress.c revision 126049
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2004 Brian Fundakowski Feldman
3219820Sjeff * All rights reserved.
4219820Sjeff *
5219820Sjeff * Redistribution and use in source and binary forms, with or without
6219820Sjeff * modification, are permitted provided that the following conditions
7219820Sjeff * are met:
8219820Sjeff * 1. Redistributions of source code must retain the above copyright
9219820Sjeff *    notice, this list of conditions and the following disclaimer.
10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11219820Sjeff *    notice, this list of conditions and the following disclaimer in the
12219820Sjeff *    documentation and/or other materials provided with the distribution.
13219820Sjeff *
14219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17219820Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24219820Sjeff * SUCH DAMAGE.
25219820Sjeff *
26219820Sjeff * $FreeBSD: head/tools/regression/gaithrstress/gaithrstress.c 126049 2004-02-20 16:54:01Z green $
27219820Sjeff * $Id: getaddrinfo-pthreads-stresstest.c,v 1.4 2004/02/20 03:54:17 green Exp green $
28219820Sjeff */
29219820Sjeff
30219820Sjeff#include <sys/types.h>
31219820Sjeff#include <sys/socket.h>
32219820Sjeff
33219820Sjeff#include <netinet/in.h>
34219820Sjeff
35219820Sjeff#include <err.h>
36219820Sjeff#include <netdb.h>
37219820Sjeff#include <pthread.h>
38219820Sjeff#include <resolv.h>
39219820Sjeff#include <stdio.h>
40219820Sjeff#include <stdint.h>
41219820Sjeff#include <stdlib.h>
42219820Sjeff#include <string.h>
43219820Sjeff#include <unistd.h>
44219820Sjeff
45219820Sjeff/* Per-thread struct containing all important data. */
46219820Sjeffstruct worker {
47219820Sjeff	pthread_t w_thread;			     /* self */
48219820Sjeff	uintmax_t w_lookup_success, w_lookup_failure;   /* getaddrinfo stats */
49219820Sjeff};
50219820Sjeff
51219820Sjeffstatic volatile int workers_stop = 0;
52219820Sjeffstatic double max_random_sleep = 1.0;
53219820Sjeffstatic char **randwords;
54219820Sjeffstatic size_t nrandwords;
55219820Sjeff
56219820Sjeff/*
57219820Sjeff * We don't have good random(3)-type functions that are thread-safe,
58219820Sjeff * unfortunately.
59219820Sjeff */
60219820Sjeffstatic u_int32_t
61219820Sjeffmy_arc4random_r(void)
62219820Sjeff{
63219820Sjeff	static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
64219820Sjeff	u_int32_t ret;
65219820Sjeff
66219820Sjeff	(void)pthread_mutex_lock(&mymutex);
67219820Sjeff	ret = arc4random();
68219820Sjeff	(void)pthread_mutex_unlock(&mymutex);
69219820Sjeff	return (ret);
70219820Sjeff}
71219820Sjeff
72219820Sjeffstatic void
73219820Sjeffrandomsleep(double max_sleep_sec)
74219820Sjeff{
75219820Sjeff	struct timespec slptime = { 0, 0 };
76219820Sjeff	double rndsleep;
77219820Sjeff
78219820Sjeff	rndsleep = (double)my_arc4random_r() / 4294967296.0 * max_sleep_sec;
79219820Sjeff	while (rndsleep >= 1.0) {
80219820Sjeff		slptime.tv_sec++;
81219820Sjeff		rndsleep -= 1.0;
82219820Sjeff	}
83219820Sjeff	slptime.tv_nsec = rndsleep * 1e9;
84219820Sjeff	(void)nanosleep(&slptime, NULL);
85219820Sjeff}
86219820Sjeff
87219820Sjeff/*
88219820Sjeff * Start looking up arbitrary hostnames and record the successes/failures.
89219820Sjeff * Between lookups, sleep a random amount of time to make sure threads
90219820Sjeff * stay well out of synchronization.
91219820Sjeff */
92219820Sjeffstatic void *
93219820Sjeffwork(void *arg)
94219820Sjeff{
95219820Sjeff	struct worker *w = arg;
96219820Sjeff
97219820Sjeff	/* Turn off domain name list searching. */
98219820Sjeff	if (_res.options & RES_INIT || res_init() == 0)
99219820Sjeff		_res.options &= ~RES_DNSRCH;
100219820Sjeff	do {
101219820Sjeff		const char *suffixes[] = { "net", "com", "org" };
102219820Sjeff		const size_t nsuffixes = sizeof(suffixes) / sizeof(suffixes[0]);
103219820Sjeff		struct addrinfo *res;
104219820Sjeff		char *hostname;
105219820Sjeff		int error;
106219820Sjeff
107219820Sjeff		randomsleep(max_random_sleep);
108219820Sjeff		if (asprintf(&hostname, "%s%s%s.%s",
109219820Sjeff		    (my_arc4random_r() % 2) == 0 ? "www." : "",
110219820Sjeff		    randwords[my_arc4random_r() % nrandwords],
111219820Sjeff		    (my_arc4random_r() % 3) == 0 ?
112219820Sjeff		    randwords[my_arc4random_r() % nrandwords] : "",
113219820Sjeff		    suffixes[my_arc4random_r() % nsuffixes]) == -1)
114219820Sjeff			continue;
115219820Sjeff		error = getaddrinfo(hostname, NULL, NULL, &res);
116219820Sjeff		free(hostname);
117219820Sjeff		if (error == 0) {
118219820Sjeff			w->w_lookup_success++;
119219820Sjeff			freeaddrinfo(res);
120219820Sjeff		} else {
121219820Sjeff			w->w_lookup_failure++;
122219820Sjeff		}
123219820Sjeff	} while (!workers_stop);
124219820Sjeff
125219820Sjeff	pthread_exit(NULL);
126219820Sjeff}
127219820Sjeff
128219820Sjeffint
129219820Sjeffdowordfile(const char *fname)
130219820Sjeff{
131219820Sjeff	FILE *fp;
132219820Sjeff	char newword[64];
133219820Sjeff	size_t n;
134219820Sjeff
135219820Sjeff	fp = fopen(fname, "r");
136219820Sjeff	if (fp == NULL)
137219820Sjeff		return (-1);
138219820Sjeff	nrandwords = 0;
139219820Sjeff	while (fgets(newword, sizeof(newword), fp) != NULL)
140219820Sjeff		nrandwords++;
141219820Sjeff	if (ferror(fp) || fseek(fp, 0, SEEK_SET) != 0)
142219820Sjeff		goto fail;
143219820Sjeff	randwords = calloc(nrandwords, sizeof(char *));
144219820Sjeff	if (randwords == NULL)
145219820Sjeff		goto fail;
146219820Sjeff	n = nrandwords;
147219820Sjeff	nrandwords = 0;
148219820Sjeff	while (fgets(newword, sizeof(newword), fp) != NULL) {
149219820Sjeff		newword[strcspn(newword, "\r\n")] = '\0';
150219820Sjeff		randwords[nrandwords] = strdup(newword);
151219820Sjeff		if (randwords[nrandwords] == NULL)
152219820Sjeff			err(1, "reading words file");
153219820Sjeff		if (++nrandwords == n)
154219820Sjeff			break;
155219820Sjeff	}
156219820Sjeff	nrandwords = n;
157219820Sjeff	fclose(fp);
158219820Sjeff	return (0);
159219820Sjefffail:
160219820Sjeff	fclose(fp);
161219820Sjeff	return (-1);
162219820Sjeff}
163219820Sjeff
164219820Sjeffint
165219820Sjeffmain(int argc, char **argv) {
166219820Sjeff	unsigned long nworkers = 1;
167219820Sjeff	struct worker *workers;
168219820Sjeff	size_t i;
169219820Sjeff	char waiting[3], *send, *wordfile = "/usr/share/dict/words";
170219820Sjeff	int ch;
171219820Sjeff
172219820Sjeff	if (getprogname() == NULL)
173219820Sjeff		setprogname(argv[0]);
174219820Sjeff	printf("%s: threaded stress-tester for getaddrinfo(3)\n",
175219820Sjeff	    getprogname());
176219820Sjeff	printf("(c) 2004 Brian Feldman <green@FreeBSD.org>\n");
177219820Sjeff	while ((ch = getopt(argc, argv, "s:t:w:")) != -1) {
178219820Sjeff		switch (ch) {
179219820Sjeff		case 's':
180219820Sjeff			max_random_sleep = strtod(optarg, &send);
181219820Sjeff			if (*send != '\0')
182219820Sjeff				goto usage;
183219820Sjeff			break;
184219820Sjeff		case 't':
185219820Sjeff			nworkers = strtoul(optarg, &send, 0);
186219820Sjeff			if (*send != '\0')
187219820Sjeff				goto usage;
188219820Sjeff			break;
189219820Sjeff		case 'w':
190219820Sjeff			wordfile = optarg;
191219820Sjeff			break;
192219820Sjeff		default:
193219820Sjeffusage:
194219820Sjeff			fprintf(stderr, "usage: %s [-s sleep] [-t threads] "
195219820Sjeff			    "[-w wordfile]\n", getprogname());
196219820Sjeff			exit(2);
197219820Sjeff		}
198219820Sjeff	}
199219820Sjeff	argc -= optind;
200219820Sjeff	argv += optind;
201219820Sjeff
202219820Sjeff	if (nworkers < 1 || nworkers != (size_t)nworkers)
203219820Sjeff		goto usage;
204219820Sjeff	if (dowordfile(wordfile) == -1)
205219820Sjeff		err(1, "reading word file %s", wordfile);
206219820Sjeff	if (nrandwords < 1)
207219820Sjeff		errx(1, "word file %s did not have >0 words", wordfile);
208219820Sjeff	printf("Read %u random words from %s.\n", nrandwords, wordfile);
209219820Sjeff	workers = calloc(nworkers, sizeof(*workers));
210219820Sjeff	if (workers == NULL)
211219820Sjeff		err(1, "allocating workers");
212219820Sjeff	printf("Intra-query delay time is from 0 to %g seconds (random).\n",
213219820Sjeff	    max_random_sleep);
214219820Sjeff
215219820Sjeff	printf("Starting %lu worker%.*s: ", nworkers, nworkers > 1, "s");
216219820Sjeff	fflush(stdout);
217219820Sjeff	for (i = 0; i < nworkers; i++) {
218219820Sjeff		if (pthread_create(&workers[i].w_thread, NULL, work,
219219820Sjeff		    &workers[i]) == -1)
220219820Sjeff			err(1, "creating worker %u", i);
221219820Sjeff		printf("%u%s", i, i == nworkers - 1 ? ".\n" : ", ");
222219820Sjeff		fflush(stdout);
223219820Sjeff	}
224219820Sjeff
225219820Sjeff	printf("<Press enter key to end test.>\n");
226219820Sjeff	(void)fgets(waiting, sizeof(waiting), stdin);
227219820Sjeff	workers_stop = 1;
228219820Sjeff
229219820Sjeff	printf("Stopping %lu worker%.*s: ", nworkers, nworkers > 1, "s");
230219820Sjeff	fflush(stdout);
231219820Sjeff	for (i = 0; i < nworkers; i++) {
232219820Sjeff		pthread_join(workers[i].w_thread, NULL);
233219820Sjeff		printf("%u%s", i, i == nworkers - 1 ? ".\n" : ", ");
234219820Sjeff		fflush(stdout);
235219820Sjeff	}
236219820Sjeff
237219820Sjeff	printf("%-10s%-20s%-20s\n", "Worker", "Successful GAI", "Failed GAI");
238219820Sjeff	printf("%-10s%-20s%-20s\n", "------", "--------------", "----------");
239219820Sjeff	for (i = 0; i < nworkers; i++) {
240219820Sjeff		printf("%-10u%-20ju%-20ju\n", i, workers[i].w_lookup_success,
241219820Sjeff		    workers[i].w_lookup_failure);
242219820Sjeff	}
243219820Sjeff
244219820Sjeff	exit(0);
245219820Sjeff}
246219820Sjeff