Add my getaddrinfo(3) stress-tester as gaithrstress. The most obvious

regressions would be to see the program or your kernel crashing.

If you want to give it something to really test out, try a much more
reentrant version of the resolver.
<URL:http://green.homeunix.org/~green/reentrant_resolver.patch>
Any Mozilla-based browser would show you a clear difference.
This commit is contained in:
Brian Feldman 2004-02-20 16:54:01 +00:00
parent 607ee6431f
commit e858faa9bb
3 changed files with 253 additions and 0 deletions

View File

@ -27,3 +27,4 @@ fsx General filesystem exerciser
sysvmsg SysV IPC Message Queue Regression Utility sysvmsg SysV IPC Message Queue Regression Utility
sysvsem SysV IPC Semaphore Regression Utility sysvsem SysV IPC Semaphore Regression Utility
sysvshm SysV IPC Shared Memory Regression Utility sysvshm SysV IPC Shared Memory Regression Utility
gaithrstress General threaded getaddrinfo(3) exerciser

View File

@ -0,0 +1,7 @@
# $FreeBSD$
PROG= gaithrstress
LDADD+= -pthread
NOMAN= yes
.include <bsd.prog.mk>

View File

@ -0,0 +1,245 @@
/*-
* 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.
*
* $FreeBSD$
* $Id: getaddrinfo-pthreads-stresstest.c,v 1.4 2004/02/20 03:54:17 green Exp green $
*/
#include <sys/types.h>
#include <sys/socket.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 */
};
static volatile int workers_stop = 0;
static double max_random_sleep = 1.0;
static char **randwords;
static size_t nrandwords;
/*
* 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.
*/
static void *
work(void *arg)
{
struct worker *w = arg;
/* Turn off domain name list searching. */
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 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;
error = getaddrinfo(hostname, NULL, NULL, &res);
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, "s:t:w:")) != -1) {
switch (ch) {
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 [-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 %u 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]) == -1)
err(1, "creating worker %u", i);
printf("%u%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("%u%s", i, i == nworkers - 1 ? ".\n" : ", ");
fflush(stdout);
}
printf("%-10s%-20s%-20s\n", "Worker", "Successful GAI", "Failed GAI");
printf("%-10s%-20s%-20s\n", "------", "--------------", "----------");
for (i = 0; i < nworkers; i++) {
printf("%-10u%-20ju%-20ju\n", i, workers[i].w_lookup_success,
workers[i].w_lookup_failure);
}
exit(0);
}