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