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:
parent
607ee6431f
commit
e858faa9bb
@ -27,3 +27,4 @@ fsx General filesystem exerciser
|
||||
sysvmsg SysV IPC Message Queue Regression Utility
|
||||
sysvsem SysV IPC Semaphore Regression Utility
|
||||
sysvshm SysV IPC Shared Memory Regression Utility
|
||||
gaithrstress General threaded getaddrinfo(3) exerciser
|
||||
|
7
tools/regression/gaithrstress/Makefile
Normal file
7
tools/regression/gaithrstress/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= gaithrstress
|
||||
LDADD+= -pthread
|
||||
|
||||
NOMAN= yes
|
||||
.include <bsd.prog.mk>
|
245
tools/regression/gaithrstress/gaithrstress.c
Normal file
245
tools/regression/gaithrstress/gaithrstress.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user