Home | History | Annotate | Download | only in common
      1  6212  aw148015 /*
      2  6212  aw148015  * CDDL HEADER START
      3  6212  aw148015  *
      4  6212  aw148015  * The contents of this file are subject to the terms of the
      5  6212  aw148015  * Common Development and Distribution License (the "License").
      6  6212  aw148015  * You may not use this file except in compliance with the License.
      7  6212  aw148015  *
      8  6212  aw148015  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  6212  aw148015  * or http://www.opensolaris.org/os/licensing.
     10  6212  aw148015  * See the License for the specific language governing permissions
     11  6212  aw148015  * and limitations under the License.
     12  6212  aw148015  *
     13  6212  aw148015  * When distributing Covered Code, include this CDDL HEADER in each
     14  6212  aw148015  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  6212  aw148015  * If applicable, add the following below this CDDL HEADER, with the
     16  6212  aw148015  * fields enclosed by brackets "[]" replaced with your own identifying
     17  6212  aw148015  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  6212  aw148015  *
     19  6212  aw148015  * CDDL HEADER END
     20  6212  aw148015  */
     21  6212  aw148015 /*
     22  6212  aw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  6212  aw148015  * Use is subject to license terms.
     24  6212  aw148015  */
     25  6212  aw148015 
     26  6212  aw148015 #include <stdio.h>
     27  6212  aw148015 #include <fcntl.h>
     28  6212  aw148015 #include <math.h>
     29  6212  aw148015 #include "filebench.h"
     30  6212  aw148015 #include "ipc.h"
     31  6212  aw148015 #include "gamma_dist.h"
     32  6212  aw148015 
     33  6212  aw148015 static int urandomfd;
     34  6212  aw148015 
     35  6212  aw148015 /*
     36  6212  aw148015  * Reads a 64 bit random number from the urandom "file".
     37  6212  aw148015  * Shuts down the run if the read fails. Otherwise returns
     38  6212  aw148015  * the random number after rounding it off by "round".
     39  6212  aw148015  * Returns 0 on success, -1 on failure.
     40  6212  aw148015  */
     41  6212  aw148015 int
     42  6212  aw148015 filebench_randomno64(uint64_t *randp, uint64_t max,
     43  6212  aw148015     uint64_t round, avd_t avd)
     44  6212  aw148015 {
     45  6212  aw148015 	uint64_t random;
     46  6212  aw148015 
     47  6212  aw148015 	/* check for round value too large */
     48  6212  aw148015 	if (max <= round) {
     49  6212  aw148015 		*randp = 0;
     50  6212  aw148015 
     51  6212  aw148015 		/* if it just fits, its ok, otherwise error */
     52  6212  aw148015 		if (max == round)
     53  6212  aw148015 			return (0);
     54  6212  aw148015 		else
     55  6212  aw148015 			return (-1);
     56  6212  aw148015 	}
     57  6212  aw148015 
     58  6212  aw148015 	if (avd) {
     59  6212  aw148015 
     60  6212  aw148015 		/* get it from the variable */
     61  6212  aw148015 		random = avd_get_int(avd);
     62  6212  aw148015 
     63  6212  aw148015 	} else {
     64  6212  aw148015 
     65  6212  aw148015 		/* get it from urandom */
     66  6212  aw148015 		if (read(urandomfd, &random,
     67  6212  aw148015 		    sizeof (uint64_t)) != sizeof (uint64_t)) {
     68  6212  aw148015 			filebench_log(LOG_ERROR,
     69  6212  aw148015 			    "read /dev/urandom failed: %s", strerror(errno));
     70  6212  aw148015 			filebench_shutdown(1);
     71  6212  aw148015 		}
     72  6212  aw148015 	}
     73  6212  aw148015 
     74  6212  aw148015 	/* clip with max and optionally round */
     75  6212  aw148015 	max -= round;
     76  6212  aw148015 	random = random / (FILEBENCH_RANDMAX64 / max);
     77  6212  aw148015 	if (round) {
     78  6212  aw148015 		random = random / round;
     79  6212  aw148015 		random *= round;
     80  6212  aw148015 	}
     81  6212  aw148015 	if (random > max)
     82  6212  aw148015 		random = max;
     83  6212  aw148015 
     84  6212  aw148015 	*randp = random;
     85  6212  aw148015 	return (0);
     86  6212  aw148015 }
     87  6212  aw148015 
     88  6212  aw148015 
     89  6212  aw148015 /*
     90  6212  aw148015  * Reads a 32 bit random number from the urandom "file".
     91  6212  aw148015  * Shuts down the run if the read fails. Otherwise returns
     92  6212  aw148015  * the random number after rounding it off by "round".
     93  6212  aw148015  * Returns 0 on success, -1 on failure.
     94  6212  aw148015  */
     95  6212  aw148015 int
     96  6212  aw148015 filebench_randomno32(uint32_t *randp, uint32_t max,
     97  6212  aw148015     uint32_t round, avd_t avd)
     98  6212  aw148015 {
     99  6212  aw148015 	uint32_t random;
    100  6212  aw148015 
    101  6212  aw148015 	/* check for round value too large */
    102  6212  aw148015 	if (max <= round) {
    103  6212  aw148015 		*randp = 0;
    104  6212  aw148015 
    105  6212  aw148015 		/* if it just fits, its ok, otherwise error */
    106  6212  aw148015 		if (max == round)
    107  6212  aw148015 			return (0);
    108  6212  aw148015 		else
    109  6212  aw148015 			return (-1);
    110  6212  aw148015 	}
    111  6212  aw148015 
    112  6212  aw148015 	if (avd) {
    113  6212  aw148015 
    114  6212  aw148015 		/* get it from the variable */
    115  6212  aw148015 		random = (uint32_t)avd_get_int(avd);
    116  6212  aw148015 
    117  6212  aw148015 	} else {
    118  6212  aw148015 
    119  6212  aw148015 		/* get it from urandom */
    120  6212  aw148015 		if (read(urandomfd, &random,
    121  6212  aw148015 		    sizeof (uint32_t)) != sizeof (uint32_t)) {
    122  6212  aw148015 			filebench_log(LOG_ERROR,
    123  6212  aw148015 			    "read /dev/urandom failed: %s", strerror(errno));
    124  6212  aw148015 			filebench_shutdown(1);
    125  6212  aw148015 		}
    126  6212  aw148015 	}
    127  6212  aw148015 
    128  6212  aw148015 	/* clip with max and optionally round */
    129  6212  aw148015 	max -= round;
    130  6212  aw148015 	random = random / (FILEBENCH_RANDMAX32 / max);
    131  6212  aw148015 	if (round) {
    132  6212  aw148015 		random = random / round;
    133  6212  aw148015 		random *= round;
    134  6212  aw148015 	}
    135  6212  aw148015 	if (random > max)
    136  6212  aw148015 		random = max;
    137  6212  aw148015 
    138  6212  aw148015 	*randp = random;
    139  6212  aw148015 	return (0);
    140  6212  aw148015 }
    141  6212  aw148015 
    142  6212  aw148015 /*
    143  6212  aw148015  * fetch a source random number from the pseudo random number generator:
    144  6212  aw148015  * erand48()
    145  6212  aw148015  */
    146  6212  aw148015 static double
    147  6212  aw148015 rand_src_rand48(unsigned short *xi)
    148  6212  aw148015 {
    149  6212  aw148015 	return (erand48(xi));
    150  6212  aw148015 }
    151  6212  aw148015 
    152  6212  aw148015 /*
    153  6212  aw148015  * fetch a source random number from the hardware random number device:
    154  6212  aw148015  * urandomfd. Convert it to a floating point probability.
    155  6212  aw148015  */
    156  6212  aw148015 /* ARGSUSED */
    157  6212  aw148015 static double
    158  6212  aw148015 rand_src_urandom(unsigned short *xi)
    159  6212  aw148015 {
    160  6212  aw148015 	fbint_t randnum;
    161  6212  aw148015 
    162  6212  aw148015 	if (read(urandomfd, &randnum,
    163  6212  aw148015 	    sizeof (fbint_t)) != sizeof (fbint_t)) {
    164  6212  aw148015 		filebench_log(LOG_ERROR,
    165  6212  aw148015 		    "read /dev/urandom failed: %s", strerror(errno));
    166  6212  aw148015 		filebench_shutdown(1);
    167  6212  aw148015 		return (0.0);
    168  6212  aw148015 	}
    169  6212  aw148015 
    170  6212  aw148015 	/* convert to 0-1 probability */
    171  6212  aw148015 	return ((double)randnum / (double)(FILEBENCH_RANDMAX64));
    172  6212  aw148015 }
    173  6212  aw148015 
    174  6212  aw148015 /*
    175  6212  aw148015  * fetch a uniformly distributed random number from the supplied
    176  6212  aw148015  * random object.
    177  6212  aw148015  */
    178  6212  aw148015 static double
    179  6212  aw148015 rand_uniform_get(randdist_t *rndp)
    180  6212  aw148015 {
    181  6212  aw148015 	double		dprob, dmin, dres, dround;
    182  6212  aw148015 
    183  6212  aw148015 	dmin = (double)rndp->rnd_vint_min;
    184  6212  aw148015 	dround = (double)rndp->rnd_vint_round;
    185  6212  aw148015 
    186  6212  aw148015 	dprob = (*rndp->rnd_src)(rndp->rnd_xi);
    187  6212  aw148015 
    188  6212  aw148015 	dres = (dprob * (2.0 * (rndp->rnd_dbl_mean - dmin))) + dmin;
    189  6212  aw148015 
    190  6212  aw148015 	if (dround == 0.0)
    191  6212  aw148015 		return (dres);
    192  6212  aw148015 	else
    193  6212  aw148015 		return (round(dres / dround) * dround);
    194  6212  aw148015 }
    195  6212  aw148015 
    196  6212  aw148015 /*
    197  6212  aw148015  * fetch a gamma distributed random number from the supplied
    198  6212  aw148015  * random object.
    199  6212  aw148015  */
    200  6212  aw148015 static double
    201  6212  aw148015 rand_gamma_get(randdist_t *rndp)
    202  6212  aw148015 {
    203  6212  aw148015 	double		dmult, dres, dmin, dround;
    204  6212  aw148015 
    205  6212  aw148015 	dmin = (double)rndp->rnd_vint_min;
    206  6212  aw148015 	dround = (double)rndp->rnd_vint_round;
    207  6212  aw148015 
    208  6212  aw148015 	dmult = (rndp->rnd_dbl_mean - dmin) / rndp->rnd_dbl_gamma;
    209  6212  aw148015 
    210  6212  aw148015 	dres = gamma_dist_knuth_src(rndp->rnd_dbl_gamma,
    211  6212  aw148015 	    dmult, rndp->rnd_src, rndp->rnd_xi) + dmin;
    212  6212  aw148015 
    213  6212  aw148015 	if (dround == 0.0)
    214  6212  aw148015 		return (dres);
    215  6212  aw148015 	else
    216  6212  aw148015 		return (round(dres / dround) * dround);
    217  6212  aw148015 }
    218  6212  aw148015 
    219  6212  aw148015 /*
    220  6212  aw148015  * fetch a table driven random number from the supplied
    221  6212  aw148015  * random object.
    222  6212  aw148015  */
    223  6212  aw148015 static double
    224  6212  aw148015 rand_table_get(randdist_t *rndp)
    225  6212  aw148015 {
    226  6212  aw148015 	double		dprob, dprcnt, dtabres, dsclres, dmin, dround;
    227  6212  aw148015 	int		idx;
    228  6212  aw148015 
    229  6212  aw148015 	dmin = (double)rndp->rnd_vint_min;
    230  6212  aw148015 	dround = (double)rndp->rnd_vint_round;
    231  6212  aw148015 
    232  6212  aw148015 	dprob = (*rndp->rnd_src)(rndp->rnd_xi);
    233  6212  aw148015 
    234  6212  aw148015 	dprcnt = (dprob * (double)(PF_TAB_SIZE));
    235  6212  aw148015 	idx = (int)dprcnt;
    236  6212  aw148015 
    237  6212  aw148015 	dtabres = (rndp->rnd_rft[idx].rf_base +
    238  6212  aw148015 	    (rndp->rnd_rft[idx].rf_range * (dprcnt - (double)idx)));
    239  6212  aw148015 
    240  6212  aw148015 	dsclres = (dtabres * (rndp->rnd_dbl_mean - dmin)) + dmin;
    241  6212  aw148015 
    242  6212  aw148015 	if (dround == 0.0)
    243  6212  aw148015 		return (dsclres);
    244  6212  aw148015 	else
    245  6212  aw148015 		return (round(dsclres / dround) * dround);
    246  6212  aw148015 }
    247  6212  aw148015 
    248  6212  aw148015 /*
    249  6212  aw148015  * Set the random seed in the supplied random object.
    250  6212  aw148015  */
    251  6212  aw148015 static void
    252  6212  aw148015 rand_seed_set(randdist_t *rndp)
    253  6212  aw148015 {
    254  6212  aw148015 	union {
    255  6212  aw148015 		uint64_t  ll;
    256  6212  aw148015 		uint16_t  w[4];
    257  6212  aw148015 	} temp1;
    258  6212  aw148015 	int  idx;
    259  6212  aw148015 
    260  6212  aw148015 	temp1.ll = (uint64_t)avd_get_int(rndp->rnd_seed);
    261  6212  aw148015 
    262  6212  aw148015 	for (idx = 0; idx < 3; idx++) {
    263  6212  aw148015 
    264  6212  aw148015 #ifdef _BIG_ENDIAN
    265  6212  aw148015 		rndp->rnd_xi[idx] = temp1.w[3-idx];
    266  6212  aw148015 #else
    267  6212  aw148015 		rndp->rnd_xi[idx] = temp1.w[idx];
    268  6212  aw148015 #endif
    269  6212  aw148015 	}
    270  6212  aw148015 }
    271  6212  aw148015 
    272  6212  aw148015 /*
    273  6212  aw148015  * Define a random entity which will contain the parameters of a random
    274  6212  aw148015  * distribution.
    275  6212  aw148015  */
    276  6212  aw148015 randdist_t *
    277  6212  aw148015 randdist_alloc(void)
    278  6212  aw148015 {
    279  6212  aw148015 	randdist_t *rndp;
    280  6212  aw148015 
    281  6212  aw148015 	if ((rndp = (randdist_t *)ipc_malloc(FILEBENCH_RANDDIST)) == NULL) {
    282  6212  aw148015 		filebench_log(LOG_ERROR, "Out of memory for random dist");
    283  6212  aw148015 		return (NULL);
    284  6212  aw148015 	}
    285  6212  aw148015 
    286  6212  aw148015 	/* place on global list */
    287  6212  aw148015 	rndp->rnd_next = filebench_shm->shm_rand_list;
    288  6212  aw148015 	filebench_shm->shm_rand_list = rndp;
    289  6212  aw148015 
    290  6212  aw148015 	return (rndp);
    291  6212  aw148015 }
    292  6212  aw148015 
    293  6212  aw148015 /*
    294  6212  aw148015  * Initializes a random distribution entity, converting avd_t
    295  6212  aw148015  * parameters to doubles, and converting the list of probability density
    296  6212  aw148015  * function table entries, if supplied, into a probablilty function table
    297  6212  aw148015  */
    298  6212  aw148015 static void
    299  6212  aw148015 randdist_init_one(randdist_t *rndp)
    300  6212  aw148015 {
    301  6212  aw148015 	probtabent_t	*rdte_hdp, *ptep;
    302  6212  aw148015 	double		tablemean, tablemin;
    303  6212  aw148015 	int		pteidx;
    304  6212  aw148015 
    305  6212  aw148015 	/* convert parameters to doubles */
    306  6212  aw148015 	rndp->rnd_dbl_gamma = (double)avd_get_int(rndp->rnd_gamma) / 1000.0;
    307  8404    Andrew 	if (rndp->rnd_mean != NULL)
    308  8404    Andrew 		rndp->rnd_dbl_mean  = (double)avd_get_int(rndp->rnd_mean);
    309  8404    Andrew 	else
    310  8404    Andrew 		rndp->rnd_dbl_mean = rndp->rnd_dbl_gamma;
    311  6212  aw148015 
    312  8404    Andrew 	/* de-reference min and round amounts for later use */
    313  6212  aw148015 	rndp->rnd_vint_min  = avd_get_int(rndp->rnd_min);
    314  6212  aw148015 	rndp->rnd_vint_round  = avd_get_int(rndp->rnd_round);
    315  6212  aw148015 
    316  6212  aw148015 	filebench_log(LOG_DEBUG_IMPL,
    317  6286  aw148015 	    "init random var %s: Mean = %6.0llf, Gamma = %6.3llf, Min = %llu",
    318  6212  aw148015 	    rndp->rnd_var->var_name, rndp->rnd_dbl_mean, rndp->rnd_dbl_gamma,
    319  6286  aw148015 	    (u_longlong_t)rndp->rnd_vint_min);
    320  6212  aw148015 
    321  6212  aw148015 	/* initialize distribution to apply */
    322  6212  aw148015 	switch (rndp->rnd_type & RAND_TYPE_MASK) {
    323  6212  aw148015 	case RAND_TYPE_UNIFORM:
    324  6212  aw148015 		rndp->rnd_get = rand_uniform_get;
    325  6212  aw148015 		break;
    326  6212  aw148015 
    327  6212  aw148015 	case RAND_TYPE_GAMMA:
    328  6212  aw148015 		rndp->rnd_get = rand_gamma_get;
    329  6212  aw148015 		break;
    330  6212  aw148015 
    331  6212  aw148015 	case RAND_TYPE_TABLE:
    332  6212  aw148015 		rndp->rnd_get = rand_table_get;
    333  6212  aw148015 		break;
    334  6212  aw148015 
    335  6212  aw148015 	default:
    336  6212  aw148015 		filebench_log(LOG_DEBUG_IMPL, "Random Type not Specified");
    337  6212  aw148015 		filebench_shutdown(1);
    338  6212  aw148015 		return;
    339  6212  aw148015 	}
    340  6212  aw148015 
    341  6212  aw148015 	/* initialize source of random numbers */
    342  6212  aw148015 	if (rndp->rnd_type & RAND_SRC_GENERATOR) {
    343  6212  aw148015 		rndp->rnd_src = rand_src_rand48;
    344  6212  aw148015 		rand_seed_set(rndp);
    345  6212  aw148015 	} else {
    346  6212  aw148015 		rndp->rnd_src = rand_src_urandom;
    347  6212  aw148015 	}
    348  6212  aw148015 
    349  6212  aw148015 	/* any random distribution table to convert? */
    350  6212  aw148015 	if ((rdte_hdp = rndp->rnd_probtabs) == NULL)
    351  6212  aw148015 		return;
    352  6212  aw148015 
    353  6212  aw148015 	/* determine random distribution max and mins and initialize table */
    354  6212  aw148015 	pteidx = 0;
    355  6212  aw148015 	tablemean = 0.0;
    356  6212  aw148015 	for (ptep = rdte_hdp; ptep; ptep = ptep->pte_next) {
    357  6212  aw148015 		double	dmin, dmax;
    358  6212  aw148015 		int	entcnt;
    359  6212  aw148015 
    360  6212  aw148015 		dmax = (double)avd_get_int(ptep->pte_segmax);
    361  6212  aw148015 		dmin = (double)avd_get_int(ptep->pte_segmin);
    362  6212  aw148015 
    363  6212  aw148015 		/* initialize table minimum on first pass */
    364  6212  aw148015 		if (pteidx == 0)
    365  6212  aw148015 			tablemin = dmin;
    366  6212  aw148015 
    367  6212  aw148015 		/* update table minimum */
    368  6212  aw148015 		if (tablemin > dmin)
    369  6212  aw148015 			tablemin = dmin;
    370  6212  aw148015 
    371  6212  aw148015 		entcnt = (int)avd_get_int(ptep->pte_percent);
    372  6212  aw148015 		tablemean += (((dmin + dmax)/2.0) * (double)entcnt);
    373  6212  aw148015 
    374  6212  aw148015 		/* populate the lookup table */
    375  6212  aw148015 
    376  6212  aw148015 		for (; entcnt > 0; entcnt--) {
    377  6212  aw148015 			rndp->rnd_rft[pteidx].rf_base = dmin;
    378  6212  aw148015 			rndp->rnd_rft[pteidx].rf_range = dmax - dmin;
    379  6212  aw148015 			pteidx++;
    380  6212  aw148015 		}
    381  6212  aw148015 	}
    382  6212  aw148015 
    383  6212  aw148015 	/* check to see if probability equals 100% */
    384  6212  aw148015 	if (pteidx != PF_TAB_SIZE)
    385  6212  aw148015 		filebench_log(LOG_ERROR,
    386  6212  aw148015 		    "Prob table only totals %d%%", pteidx);
    387  6212  aw148015 
    388  6212  aw148015 	/* If table is not supplied with a mean value, set it to table mean */
    389  6212  aw148015 	if (rndp->rnd_dbl_mean == 0.0)
    390  6212  aw148015 		rndp->rnd_dbl_mean = (double)tablemean / (double)PF_TAB_SIZE;
    391  6212  aw148015 
    392  6212  aw148015 	/* now normalize the entries for a min value of 0, mean of 1 */
    393  6212  aw148015 	tablemean = (tablemean / 100.0) - tablemin;
    394  6212  aw148015 
    395  6212  aw148015 	/* special case if really a constant value */
    396  6212  aw148015 	if (tablemean == 0.0) {
    397  6212  aw148015 		for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) {
    398  6212  aw148015 			rndp->rnd_rft[pteidx].rf_base = 0.0;
    399  6212  aw148015 			rndp->rnd_rft[pteidx].rf_range = 0.0;
    400  6212  aw148015 		}
    401  6212  aw148015 		return;
    402  6212  aw148015 	}
    403  6212  aw148015 
    404  6212  aw148015 	for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) {
    405  6212  aw148015 
    406  6212  aw148015 		rndp->rnd_rft[pteidx].rf_base =
    407  6212  aw148015 		    ((rndp->rnd_rft[pteidx].rf_base - tablemin) / tablemean);
    408  6212  aw148015 		rndp->rnd_rft[pteidx].rf_range =
    409  6212  aw148015 		    (rndp->rnd_rft[pteidx].rf_range / tablemean);
    410  6212  aw148015 	}
    411  6212  aw148015 }
    412  6212  aw148015 
    413  6212  aw148015 /*
    414  6212  aw148015  * initialize all the random distribution entities
    415  6212  aw148015  */
    416  6212  aw148015 void
    417  6212  aw148015 randdist_init(void)
    418  6212  aw148015 {
    419  6212  aw148015 	randdist_t *rndp;
    420  6212  aw148015 
    421  6212  aw148015 	for (rndp = filebench_shm->shm_rand_list; rndp; rndp = rndp->rnd_next)
    422  6212  aw148015 		randdist_init_one(rndp);
    423  6212  aw148015 }
    424  6212  aw148015 
    425  6212  aw148015 /*
    426  6212  aw148015  * Initialize the urandom random number source
    427  6212  aw148015  */
    428  6212  aw148015 void
    429  6212  aw148015 fb_random_init(void)
    430  6212  aw148015 {
    431  6212  aw148015 	/* open the "urandom" random number device file */
    432  6212  aw148015 	if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) {
    433  6212  aw148015 		filebench_log(LOG_ERROR, "open /dev/urandom failed: %s",
    434  6212  aw148015 		    strerror(errno));
    435  6212  aw148015 		filebench_shutdown(1);
    436  6212  aw148015 	}
    437  6212  aw148015 }
    438