16212Saw148015 /* 26212Saw148015 * CDDL HEADER START 36212Saw148015 * 46212Saw148015 * The contents of this file are subject to the terms of the 56212Saw148015 * Common Development and Distribution License (the "License"). 66212Saw148015 * You may not use this file except in compliance with the License. 76212Saw148015 * 86212Saw148015 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96212Saw148015 * or http://www.opensolaris.org/os/licensing. 106212Saw148015 * See the License for the specific language governing permissions 116212Saw148015 * and limitations under the License. 126212Saw148015 * 136212Saw148015 * When distributing Covered Code, include this CDDL HEADER in each 146212Saw148015 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156212Saw148015 * If applicable, add the following below this CDDL HEADER, with the 166212Saw148015 * fields enclosed by brackets "[]" replaced with your own identifying 176212Saw148015 * information: Portions Copyright [yyyy] [name of copyright owner] 186212Saw148015 * 196212Saw148015 * CDDL HEADER END 206212Saw148015 */ 216212Saw148015 /* 226212Saw148015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 236212Saw148015 * Use is subject to license terms. 246212Saw148015 */ 256212Saw148015 266212Saw148015 #pragma ident "%Z%%M% %I% %E% SMI" 276212Saw148015 286212Saw148015 #include <stdio.h> 296212Saw148015 #include <fcntl.h> 306212Saw148015 #include <math.h> 316212Saw148015 #include "filebench.h" 326212Saw148015 #include "ipc.h" 336212Saw148015 #include "gamma_dist.h" 346212Saw148015 356212Saw148015 static int urandomfd; 366212Saw148015 376212Saw148015 /* 386212Saw148015 * Reads a 64 bit random number from the urandom "file". 396212Saw148015 * Shuts down the run if the read fails. Otherwise returns 406212Saw148015 * the random number after rounding it off by "round". 416212Saw148015 * Returns 0 on success, -1 on failure. 426212Saw148015 */ 436212Saw148015 int 446212Saw148015 filebench_randomno64(uint64_t *randp, uint64_t max, 456212Saw148015 uint64_t round, avd_t avd) 466212Saw148015 { 476212Saw148015 uint64_t random; 486212Saw148015 496212Saw148015 /* check for round value too large */ 506212Saw148015 if (max <= round) { 516212Saw148015 *randp = 0; 526212Saw148015 536212Saw148015 /* if it just fits, its ok, otherwise error */ 546212Saw148015 if (max == round) 556212Saw148015 return (0); 566212Saw148015 else 576212Saw148015 return (-1); 586212Saw148015 } 596212Saw148015 606212Saw148015 if (avd) { 616212Saw148015 626212Saw148015 /* get it from the variable */ 636212Saw148015 random = avd_get_int(avd); 646212Saw148015 656212Saw148015 } else { 666212Saw148015 676212Saw148015 /* get it from urandom */ 686212Saw148015 if (read(urandomfd, &random, 696212Saw148015 sizeof (uint64_t)) != sizeof (uint64_t)) { 706212Saw148015 filebench_log(LOG_ERROR, 716212Saw148015 "read /dev/urandom failed: %s", strerror(errno)); 726212Saw148015 filebench_shutdown(1); 736212Saw148015 } 746212Saw148015 } 756212Saw148015 766212Saw148015 /* clip with max and optionally round */ 776212Saw148015 max -= round; 786212Saw148015 random = random / (FILEBENCH_RANDMAX64 / max); 796212Saw148015 if (round) { 806212Saw148015 random = random / round; 816212Saw148015 random *= round; 826212Saw148015 } 836212Saw148015 if (random > max) 846212Saw148015 random = max; 856212Saw148015 866212Saw148015 *randp = random; 876212Saw148015 return (0); 886212Saw148015 } 896212Saw148015 906212Saw148015 916212Saw148015 /* 926212Saw148015 * Reads a 32 bit random number from the urandom "file". 936212Saw148015 * Shuts down the run if the read fails. Otherwise returns 946212Saw148015 * the random number after rounding it off by "round". 956212Saw148015 * Returns 0 on success, -1 on failure. 966212Saw148015 */ 976212Saw148015 int 986212Saw148015 filebench_randomno32(uint32_t *randp, uint32_t max, 996212Saw148015 uint32_t round, avd_t avd) 1006212Saw148015 { 1016212Saw148015 uint32_t random; 1026212Saw148015 1036212Saw148015 /* check for round value too large */ 1046212Saw148015 if (max <= round) { 1056212Saw148015 *randp = 0; 1066212Saw148015 1076212Saw148015 /* if it just fits, its ok, otherwise error */ 1086212Saw148015 if (max == round) 1096212Saw148015 return (0); 1106212Saw148015 else 1116212Saw148015 return (-1); 1126212Saw148015 } 1136212Saw148015 1146212Saw148015 if (avd) { 1156212Saw148015 1166212Saw148015 /* get it from the variable */ 1176212Saw148015 random = (uint32_t)avd_get_int(avd); 1186212Saw148015 1196212Saw148015 } else { 1206212Saw148015 1216212Saw148015 /* get it from urandom */ 1226212Saw148015 if (read(urandomfd, &random, 1236212Saw148015 sizeof (uint32_t)) != sizeof (uint32_t)) { 1246212Saw148015 filebench_log(LOG_ERROR, 1256212Saw148015 "read /dev/urandom failed: %s", strerror(errno)); 1266212Saw148015 filebench_shutdown(1); 1276212Saw148015 } 1286212Saw148015 } 1296212Saw148015 1306212Saw148015 /* clip with max and optionally round */ 1316212Saw148015 max -= round; 1326212Saw148015 random = random / (FILEBENCH_RANDMAX32 / max); 1336212Saw148015 if (round) { 1346212Saw148015 random = random / round; 1356212Saw148015 random *= round; 1366212Saw148015 } 1376212Saw148015 if (random > max) 1386212Saw148015 random = max; 1396212Saw148015 1406212Saw148015 *randp = random; 1416212Saw148015 return (0); 1426212Saw148015 } 1436212Saw148015 1446212Saw148015 /* 1456212Saw148015 * fetch a source random number from the pseudo random number generator: 1466212Saw148015 * erand48() 1476212Saw148015 */ 1486212Saw148015 static double 1496212Saw148015 rand_src_rand48(unsigned short *xi) 1506212Saw148015 { 1516212Saw148015 return (erand48(xi)); 1526212Saw148015 } 1536212Saw148015 1546212Saw148015 /* 1556212Saw148015 * fetch a source random number from the hardware random number device: 1566212Saw148015 * urandomfd. Convert it to a floating point probability. 1576212Saw148015 */ 1586212Saw148015 /* ARGSUSED */ 1596212Saw148015 static double 1606212Saw148015 rand_src_urandom(unsigned short *xi) 1616212Saw148015 { 1626212Saw148015 fbint_t randnum; 1636212Saw148015 1646212Saw148015 if (read(urandomfd, &randnum, 1656212Saw148015 sizeof (fbint_t)) != sizeof (fbint_t)) { 1666212Saw148015 filebench_log(LOG_ERROR, 1676212Saw148015 "read /dev/urandom failed: %s", strerror(errno)); 1686212Saw148015 filebench_shutdown(1); 1696212Saw148015 return (0.0); 1706212Saw148015 } 1716212Saw148015 1726212Saw148015 /* convert to 0-1 probability */ 1736212Saw148015 return ((double)randnum / (double)(FILEBENCH_RANDMAX64)); 1746212Saw148015 } 1756212Saw148015 1766212Saw148015 /* 1776212Saw148015 * fetch a uniformly distributed random number from the supplied 1786212Saw148015 * random object. 1796212Saw148015 */ 1806212Saw148015 static double 1816212Saw148015 rand_uniform_get(randdist_t *rndp) 1826212Saw148015 { 1836212Saw148015 double dprob, dmin, dres, dround; 1846212Saw148015 1856212Saw148015 dmin = (double)rndp->rnd_vint_min; 1866212Saw148015 dround = (double)rndp->rnd_vint_round; 1876212Saw148015 1886212Saw148015 dprob = (*rndp->rnd_src)(rndp->rnd_xi); 1896212Saw148015 1906212Saw148015 dres = (dprob * (2.0 * (rndp->rnd_dbl_mean - dmin))) + dmin; 1916212Saw148015 1926212Saw148015 if (dround == 0.0) 1936212Saw148015 return (dres); 1946212Saw148015 else 1956212Saw148015 return (round(dres / dround) * dround); 1966212Saw148015 } 1976212Saw148015 1986212Saw148015 /* 1996212Saw148015 * fetch a gamma distributed random number from the supplied 2006212Saw148015 * random object. 2016212Saw148015 */ 2026212Saw148015 static double 2036212Saw148015 rand_gamma_get(randdist_t *rndp) 2046212Saw148015 { 2056212Saw148015 double dmult, dres, dmin, dround; 2066212Saw148015 2076212Saw148015 dmin = (double)rndp->rnd_vint_min; 2086212Saw148015 dround = (double)rndp->rnd_vint_round; 2096212Saw148015 2106212Saw148015 dmult = (rndp->rnd_dbl_mean - dmin) / rndp->rnd_dbl_gamma; 2116212Saw148015 2126212Saw148015 dres = gamma_dist_knuth_src(rndp->rnd_dbl_gamma, 2136212Saw148015 dmult, rndp->rnd_src, rndp->rnd_xi) + dmin; 2146212Saw148015 2156212Saw148015 if (dround == 0.0) 2166212Saw148015 return (dres); 2176212Saw148015 else 2186212Saw148015 return (round(dres / dround) * dround); 2196212Saw148015 } 2206212Saw148015 2216212Saw148015 /* 2226212Saw148015 * fetch a table driven random number from the supplied 2236212Saw148015 * random object. 2246212Saw148015 */ 2256212Saw148015 static double 2266212Saw148015 rand_table_get(randdist_t *rndp) 2276212Saw148015 { 2286212Saw148015 double dprob, dprcnt, dtabres, dsclres, dmin, dround; 2296212Saw148015 int idx; 2306212Saw148015 2316212Saw148015 dmin = (double)rndp->rnd_vint_min; 2326212Saw148015 dround = (double)rndp->rnd_vint_round; 2336212Saw148015 2346212Saw148015 dprob = (*rndp->rnd_src)(rndp->rnd_xi); 2356212Saw148015 2366212Saw148015 dprcnt = (dprob * (double)(PF_TAB_SIZE)); 2376212Saw148015 idx = (int)dprcnt; 2386212Saw148015 2396212Saw148015 dtabres = (rndp->rnd_rft[idx].rf_base + 2406212Saw148015 (rndp->rnd_rft[idx].rf_range * (dprcnt - (double)idx))); 2416212Saw148015 2426212Saw148015 dsclres = (dtabres * (rndp->rnd_dbl_mean - dmin)) + dmin; 2436212Saw148015 2446212Saw148015 if (dround == 0.0) 2456212Saw148015 return (dsclres); 2466212Saw148015 else 2476212Saw148015 return (round(dsclres / dround) * dround); 2486212Saw148015 } 2496212Saw148015 2506212Saw148015 /* 2516212Saw148015 * Set the random seed in the supplied random object. 2526212Saw148015 */ 2536212Saw148015 static void 2546212Saw148015 rand_seed_set(randdist_t *rndp) 2556212Saw148015 { 2566212Saw148015 union { 2576212Saw148015 uint64_t ll; 2586212Saw148015 uint16_t w[4]; 2596212Saw148015 } temp1; 2606212Saw148015 int idx; 2616212Saw148015 2626212Saw148015 temp1.ll = (uint64_t)avd_get_int(rndp->rnd_seed); 2636212Saw148015 2646212Saw148015 for (idx = 0; idx < 3; idx++) { 2656212Saw148015 2666212Saw148015 #ifdef _BIG_ENDIAN 2676212Saw148015 rndp->rnd_xi[idx] = temp1.w[3-idx]; 2686212Saw148015 #else 2696212Saw148015 rndp->rnd_xi[idx] = temp1.w[idx]; 2706212Saw148015 #endif 2716212Saw148015 } 2726212Saw148015 } 2736212Saw148015 2746212Saw148015 /* 2756212Saw148015 * Define a random entity which will contain the parameters of a random 2766212Saw148015 * distribution. 2776212Saw148015 */ 2786212Saw148015 randdist_t * 2796212Saw148015 randdist_alloc(void) 2806212Saw148015 { 2816212Saw148015 randdist_t *rndp; 2826212Saw148015 2836212Saw148015 if ((rndp = (randdist_t *)ipc_malloc(FILEBENCH_RANDDIST)) == NULL) { 2846212Saw148015 filebench_log(LOG_ERROR, "Out of memory for random dist"); 2856212Saw148015 return (NULL); 2866212Saw148015 } 2876212Saw148015 2886212Saw148015 /* place on global list */ 2896212Saw148015 rndp->rnd_next = filebench_shm->shm_rand_list; 2906212Saw148015 filebench_shm->shm_rand_list = rndp; 2916212Saw148015 2926212Saw148015 return (rndp); 2936212Saw148015 } 2946212Saw148015 2956212Saw148015 /* 2966212Saw148015 * Initializes a random distribution entity, converting avd_t 2976212Saw148015 * parameters to doubles, and converting the list of probability density 2986212Saw148015 * function table entries, if supplied, into a probablilty function table 2996212Saw148015 */ 3006212Saw148015 static void 3016212Saw148015 randdist_init_one(randdist_t *rndp) 3026212Saw148015 { 3036212Saw148015 probtabent_t *rdte_hdp, *ptep; 3046212Saw148015 double tablemean, tablemin; 3056212Saw148015 int pteidx; 3066212Saw148015 3076212Saw148015 /* convert parameters to doubles */ 3086212Saw148015 rndp->rnd_dbl_mean = (double)avd_get_int(rndp->rnd_mean); 3096212Saw148015 rndp->rnd_dbl_gamma = (double)avd_get_int(rndp->rnd_gamma) / 1000.0; 3106212Saw148015 3116212Saw148015 rndp->rnd_vint_min = avd_get_int(rndp->rnd_min); 3126212Saw148015 rndp->rnd_vint_round = avd_get_int(rndp->rnd_round); 3136212Saw148015 3146212Saw148015 filebench_log(LOG_DEBUG_IMPL, 315*6286Saw148015 "init random var %s: Mean = %6.0llf, Gamma = %6.3llf, Min = %llu", 3166212Saw148015 rndp->rnd_var->var_name, rndp->rnd_dbl_mean, rndp->rnd_dbl_gamma, 317*6286Saw148015 (u_longlong_t)rndp->rnd_vint_min); 3186212Saw148015 3196212Saw148015 /* initialize distribution to apply */ 3206212Saw148015 switch (rndp->rnd_type & RAND_TYPE_MASK) { 3216212Saw148015 case RAND_TYPE_UNIFORM: 3226212Saw148015 rndp->rnd_get = rand_uniform_get; 3236212Saw148015 break; 3246212Saw148015 3256212Saw148015 case RAND_TYPE_GAMMA: 3266212Saw148015 rndp->rnd_get = rand_gamma_get; 3276212Saw148015 break; 3286212Saw148015 3296212Saw148015 case RAND_TYPE_TABLE: 3306212Saw148015 rndp->rnd_get = rand_table_get; 3316212Saw148015 break; 3326212Saw148015 3336212Saw148015 default: 3346212Saw148015 filebench_log(LOG_DEBUG_IMPL, "Random Type not Specified"); 3356212Saw148015 filebench_shutdown(1); 3366212Saw148015 return; 3376212Saw148015 } 3386212Saw148015 3396212Saw148015 /* initialize source of random numbers */ 3406212Saw148015 if (rndp->rnd_type & RAND_SRC_GENERATOR) { 3416212Saw148015 rndp->rnd_src = rand_src_rand48; 3426212Saw148015 rand_seed_set(rndp); 3436212Saw148015 } else { 3446212Saw148015 rndp->rnd_src = rand_src_urandom; 3456212Saw148015 } 3466212Saw148015 3476212Saw148015 /* any random distribution table to convert? */ 3486212Saw148015 if ((rdte_hdp = rndp->rnd_probtabs) == NULL) 3496212Saw148015 return; 3506212Saw148015 3516212Saw148015 /* determine random distribution max and mins and initialize table */ 3526212Saw148015 pteidx = 0; 3536212Saw148015 tablemean = 0.0; 3546212Saw148015 for (ptep = rdte_hdp; ptep; ptep = ptep->pte_next) { 3556212Saw148015 double dmin, dmax; 3566212Saw148015 int entcnt; 3576212Saw148015 3586212Saw148015 dmax = (double)avd_get_int(ptep->pte_segmax); 3596212Saw148015 dmin = (double)avd_get_int(ptep->pte_segmin); 3606212Saw148015 3616212Saw148015 /* initialize table minimum on first pass */ 3626212Saw148015 if (pteidx == 0) 3636212Saw148015 tablemin = dmin; 3646212Saw148015 3656212Saw148015 /* update table minimum */ 3666212Saw148015 if (tablemin > dmin) 3676212Saw148015 tablemin = dmin; 3686212Saw148015 3696212Saw148015 entcnt = (int)avd_get_int(ptep->pte_percent); 3706212Saw148015 tablemean += (((dmin + dmax)/2.0) * (double)entcnt); 3716212Saw148015 3726212Saw148015 /* populate the lookup table */ 3736212Saw148015 3746212Saw148015 for (; entcnt > 0; entcnt--) { 3756212Saw148015 rndp->rnd_rft[pteidx].rf_base = dmin; 3766212Saw148015 rndp->rnd_rft[pteidx].rf_range = dmax - dmin; 3776212Saw148015 pteidx++; 3786212Saw148015 } 3796212Saw148015 } 3806212Saw148015 3816212Saw148015 /* check to see if probability equals 100% */ 3826212Saw148015 if (pteidx != PF_TAB_SIZE) 3836212Saw148015 filebench_log(LOG_ERROR, 3846212Saw148015 "Prob table only totals %d%%", pteidx); 3856212Saw148015 3866212Saw148015 /* If table is not supplied with a mean value, set it to table mean */ 3876212Saw148015 if (rndp->rnd_dbl_mean == 0.0) 3886212Saw148015 rndp->rnd_dbl_mean = (double)tablemean / (double)PF_TAB_SIZE; 3896212Saw148015 3906212Saw148015 /* now normalize the entries for a min value of 0, mean of 1 */ 3916212Saw148015 tablemean = (tablemean / 100.0) - tablemin; 3926212Saw148015 3936212Saw148015 /* special case if really a constant value */ 3946212Saw148015 if (tablemean == 0.0) { 3956212Saw148015 for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { 3966212Saw148015 rndp->rnd_rft[pteidx].rf_base = 0.0; 3976212Saw148015 rndp->rnd_rft[pteidx].rf_range = 0.0; 3986212Saw148015 } 3996212Saw148015 return; 4006212Saw148015 } 4016212Saw148015 4026212Saw148015 for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { 4036212Saw148015 4046212Saw148015 rndp->rnd_rft[pteidx].rf_base = 4056212Saw148015 ((rndp->rnd_rft[pteidx].rf_base - tablemin) / tablemean); 4066212Saw148015 rndp->rnd_rft[pteidx].rf_range = 4076212Saw148015 (rndp->rnd_rft[pteidx].rf_range / tablemean); 4086212Saw148015 } 4096212Saw148015 } 4106212Saw148015 4116212Saw148015 /* 4126212Saw148015 * initialize all the random distribution entities 4136212Saw148015 */ 4146212Saw148015 void 4156212Saw148015 randdist_init(void) 4166212Saw148015 { 4176212Saw148015 randdist_t *rndp; 4186212Saw148015 4196212Saw148015 for (rndp = filebench_shm->shm_rand_list; rndp; rndp = rndp->rnd_next) 4206212Saw148015 randdist_init_one(rndp); 4216212Saw148015 } 4226212Saw148015 4236212Saw148015 /* 4246212Saw148015 * Initialize the urandom random number source 4256212Saw148015 */ 4266212Saw148015 void 4276212Saw148015 fb_random_init(void) 4286212Saw148015 { 4296212Saw148015 /* open the "urandom" random number device file */ 4306212Saw148015 if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) { 4316212Saw148015 filebench_log(LOG_ERROR, "open /dev/urandom failed: %s", 4326212Saw148015 strerror(errno)); 4336212Saw148015 filebench_shutdown(1); 4346212Saw148015 } 4356212Saw148015 } 436