diff options
Diffstat (limited to 'tools/regression/gaithrstress/gaithrstress.c')
| -rw-r--r-- | tools/regression/gaithrstress/gaithrstress.c | 274 | 
1 files changed, 274 insertions, 0 deletions
| diff --git a/tools/regression/gaithrstress/gaithrstress.c b/tools/regression/gaithrstress/gaithrstress.c new file mode 100644 index 000000000000..7eb92474cbf2 --- /dev/null +++ b/tools/regression/gaithrstress/gaithrstress.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 2004 Brian Fundakowski Feldman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> + +#include <err.h> +#include <netdb.h> +#include <pthread.h> +#include <resolv.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* Per-thread struct containing all important data. */ +struct worker { +	pthread_t w_thread;			     /* self */ +	uintmax_t w_lookup_success, w_lookup_failure;   /* getaddrinfo stats */ +	struct timespec w_max_lookup_time; +}; + +static volatile int workers_stop = 0; +static double max_random_sleep = 1.0; +static char **randwords; +static size_t nrandwords; +static const struct addrinfo *hints, hintipv4only = { .ai_family = AF_INET }; + +/* + * We don't have good random(3)-type functions that are thread-safe, + * unfortunately. + */ +static u_int32_t +my_arc4random_r(void) +{ +	static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; +	u_int32_t ret; + +	(void)pthread_mutex_lock(&mymutex); +	ret = arc4random(); +	(void)pthread_mutex_unlock(&mymutex); +	return (ret); +} + +static void +randomsleep(double max_sleep_sec) +{ +	struct timespec slptime = { 0, 0 }; +	double rndsleep; + +	rndsleep = (double)my_arc4random_r() / 4294967296.0 * max_sleep_sec; +	while (rndsleep >= 1.0) { +		slptime.tv_sec++; +		rndsleep -= 1.0; +	} +	slptime.tv_nsec = rndsleep * 1e9; +	(void)nanosleep(&slptime, NULL); +} + +/* + * Start looking up arbitrary hostnames and record the successes/failures. + * Between lookups, sleep a random amount of time to make sure threads + * stay well out of synchronization. + * + * Host name:	part		probability + *		----		----------- + *		www.		1/2 + *		random word	always, equal + *		random word	1/3, equal + *		.(net|com|org)	equal + */ +static void * +work(void *arg) +{ +	struct worker *w = arg; + +	/* Turn off domain name list searching as much as possible. */ +	if (_res.options & RES_INIT || res_init() == 0) +		_res.options &= ~RES_DNSRCH; +	do { +		const char *suffixes[] = { "net", "com", "org" }; +		const size_t nsuffixes = sizeof(suffixes) / sizeof(suffixes[0]); +		struct timespec ts_begintime, ts_total; +		struct addrinfo *res; +		char *hostname; +		int error; + +		randomsleep(max_random_sleep); +		if (asprintf(&hostname, "%s%s%s.%s", +		    (my_arc4random_r() % 2) == 0 ? "www." : "", +		    randwords[my_arc4random_r() % nrandwords], +		    (my_arc4random_r() % 3) == 0 ? +		    randwords[my_arc4random_r() % nrandwords] : "", +		    suffixes[my_arc4random_r() % nsuffixes]) == -1) +			continue; +		(void)clock_gettime(CLOCK_REALTIME, &ts_begintime); +		error = getaddrinfo(hostname, NULL, hints, &res); +		(void)clock_gettime(CLOCK_REALTIME, &ts_total); +		ts_total.tv_sec -= ts_begintime.tv_sec; +		ts_total.tv_nsec -= ts_begintime.tv_nsec; +		if (ts_total.tv_nsec < 0) { +			ts_total.tv_sec--; +			ts_total.tv_nsec += 1000000000; +		} +		if (ts_total.tv_sec > w->w_max_lookup_time.tv_sec || +		    (ts_total.tv_sec == w->w_max_lookup_time.tv_sec && +		    ts_total.tv_nsec > w->w_max_lookup_time.tv_sec)) +			w->w_max_lookup_time = ts_total; +		free(hostname); +		if (error == 0) { +			w->w_lookup_success++; +			freeaddrinfo(res); +		} else { +			w->w_lookup_failure++; +		} +	} while (!workers_stop); + +	pthread_exit(NULL); +} + +int +dowordfile(const char *fname) +{ +	FILE *fp; +	char newword[64]; +	size_t n; + +	fp = fopen(fname, "r"); +	if (fp == NULL) +		return (-1); +	nrandwords = 0; +	while (fgets(newword, sizeof(newword), fp) != NULL) +		nrandwords++; +	if (ferror(fp) || fseek(fp, 0, SEEK_SET) != 0) +		goto fail; +	randwords = calloc(nrandwords, sizeof(char *)); +	if (randwords == NULL) +		goto fail; +	n = nrandwords; +	nrandwords = 0; +	while (fgets(newword, sizeof(newword), fp) != NULL) { +		newword[strcspn(newword, "\r\n")] = '\0'; +		randwords[nrandwords] = strdup(newword); +		if (randwords[nrandwords] == NULL) +			err(1, "reading words file"); +		if (++nrandwords == n) +			break; +	} +	nrandwords = n; +	fclose(fp); +	return (0); +fail: +	fclose(fp); +	return (-1); +} + +int +main(int argc, char **argv) { +	unsigned long nworkers = 1; +	struct worker *workers; +	size_t i; +	char waiting[3], *send, *wordfile = "/usr/share/dict/words"; +	int ch; + +	if (getprogname() == NULL) +		setprogname(argv[0]); +	printf("%s: threaded stress-tester for getaddrinfo(3)\n", +	    getprogname()); +	printf("(c) 2004 Brian Feldman <green@FreeBSD.org>\n"); +	while ((ch = getopt(argc, argv, "4s:t:w:")) != -1) { +		switch (ch) { +		case '4': +			hints = &hintipv4only; +			break; +		case 's': +			max_random_sleep = strtod(optarg, &send); +			if (*send != '\0') +				goto usage; +			break; +		case 't': +			nworkers = strtoul(optarg, &send, 0); +			if (*send != '\0') +				goto usage; +			break; +		case 'w': +			wordfile = optarg; +			break; +		default: +usage: +			fprintf(stderr, "usage: %s [-4] [-s sleep] " +			    "[-t threads] [-w wordfile]\n", getprogname()); +			exit(2); +		} +	} +	argc -= optind; +	argv += optind; + +	if (nworkers < 1 || nworkers != (size_t)nworkers) +		goto usage; +	if (dowordfile(wordfile) == -1) +		err(1, "reading word file %s", wordfile); +	if (nrandwords < 1) +		errx(1, "word file %s did not have >0 words", wordfile); +	printf("Read %zu random words from %s.\n", nrandwords, wordfile); +	workers = calloc(nworkers, sizeof(*workers)); +	if (workers == NULL) +		err(1, "allocating workers"); +	printf("Intra-query delay time is from 0 to %g seconds (random).\n", +	    max_random_sleep); + +	printf("Starting %lu worker%.*s: ", nworkers, nworkers > 1, "s"); +	fflush(stdout); +	for (i = 0; i < nworkers; i++) { +		if (pthread_create(&workers[i].w_thread, NULL, work, +		    &workers[i]) != 0) +			err(1, "creating worker %zu", i); +		printf("%zu%s", i, i == nworkers - 1 ? ".\n" : ", "); +		fflush(stdout); +	} + +	printf("<Press enter key to end test.>\n"); +	(void)fgets(waiting, sizeof(waiting), stdin); +	workers_stop = 1; + +	printf("Stopping %lu worker%.*s: ", nworkers, nworkers > 1, "s"); +	fflush(stdout); +	for (i = 0; i < nworkers; i++) { +		pthread_join(workers[i].w_thread, NULL); +		printf("%zu%s", i, i == nworkers - 1 ? ".\n" : ", "); +		fflush(stdout); +	} + +	printf("%-10s%-20s%-20s%-29s\n", "Worker", "Successful GAI", +	    "Failed GAI", "Max resolution time (M:SS*)"); +	printf("%-10s%-20s%-20s%-29s\n", "------", "--------------", +	    "----------", "---------------------------"); +	for (i = 0; i < nworkers; i++) { +		printf("%-10zu%-20ju%-20ju%ld:%s%.2f\n", i, +		    workers[i].w_lookup_success, workers[i].w_lookup_failure, +		    workers[i].w_max_lookup_time.tv_sec / 60, +		    workers[i].w_max_lookup_time.tv_sec % 60 < 10 ? "0" : "", +		    (double)(workers[i].w_max_lookup_time.tv_sec % 60) + +		    (double)workers[i].w_max_lookup_time.tv_nsec / 1e9); +	} + +	exit(0); +} | 
