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