7b7a680280
PR: 143807 Submitted by: pluknet (partly)
277 lines
7.7 KiB
C
277 lines
7.7 KiB
C
/*-
|
|
* 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$
|
|
*/
|
|
|
|
#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 %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]) != 0)
|
|
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%-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("%-10u%-20ju%-20ju%u:%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);
|
|
}
|