Home | History | Annotate | Download | only in ffsb-6.0-rc2
      1 /*
      2  *   Copyright (c) International Business Machines Corp., 2001-2004
      3  *
      4  *   This program is free software;  you can redistribute it and/or modify
      5  *   it under the terms of the GNU General Public License as published by
      6  *   the Free Software Foundation; either version 2 of the License, or
      7  *   (at your option) any later version.
      8  *
      9  *   This program is distributed in the hope that it will be useful,
     10  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  *   the GNU General Public License for more details.
     13  *
     14  *   You should have received a copy of the GNU General Public License
     15  *   along with this program;  if not, write to the Free Software
     16  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17  */
     18 #include <stdlib.h>
     19 #include <stdio.h>
     20 #include <sys/types.h>
     21 #include <sys/stat.h>
     22 #include <sys/time.h>
     23 #include <fcntl.h>
     24 #include <unistd.h>
     25 #include <limits.h>
     26 #include <inttypes.h>
     27 #include <assert.h>
     28 
     29 #include "config.h"
     30 #include "rand.h"
     31 #include "util.h"
     32 
     33 #define RANDSRC "/dev/urandom"
     34 
     35 static int randfd = -1;
     36 
     37 /* close the file after we're done with the benchmark */
     38 void randcleanup(void)
     39 {
     40 	if (randfd > 0)
     41 		close(randfd);
     42 }
     43 
     44 /* We fill up the array with random bits from RANDSRC here and set index */
     45 /* to 0 */
     46 /* pre: state->size must be set and state->mt must be allocated! */
     47 static void sgenrand(randdata_t * state)
     48 {
     49 	int got = 0;
     50 	got = read(randfd, state->mt, state->size);
     51 	if (got != state->size) {
     52 		int i;
     53 		/* fall back on lrand48 */
     54 		/* printf("fallback_rand\n"); */
     55 
     56 		for (i = got; i < state->size; i += 4) {
     57 			long int rand = 0;
     58 #ifdef HAVE_LRAND48
     59 			lrand48_r(&(state->data), &rand);
     60 #else
     61 			rand = random();
     62 #endif
     63 			assert(rand != 0);
     64 			state->mt[i] = (rand >> 24) & (512 - 1);
     65 			state->mt[i + 1] = (rand >> 16) & (512 - 1);
     66 			state->mt[i + 2] = (rand >> 8) & (512 - 1);
     67 			state->mt[i + 3] = (rand) & (512 - 1);
     68 		}
     69 
     70 	}
     71 	state->mti = 0;
     72 }
     73 
     74 /* returns 8 random bits */
     75 static uint8_t genrand8(randdata_t * state)
     76 {
     77 	unsigned long ret = 0;
     78 	if (state->mti >= state->size) {
     79 /*		sgenrand(state); */
     80 		state->mti = 0;
     81 	}
     82 	ret = state->mt[state->mti];
     83 	state->mti++;
     84 	return ret;
     85 }
     86 
     87 /* returns 32 random bits */
     88 static uint32_t genrand32(randdata_t * state)
     89 {
     90 	uint8_t bytes[4];
     91 	uint32_t ret = 0;
     92 
     93 	bytes[0] = genrand8(state);
     94 	bytes[1] = genrand8(state);
     95 	bytes[2] = genrand8(state);
     96 	bytes[3] = genrand8(state);
     97 
     98 	ret = *((uint32_t *) bytes);	/* !!! hack */
     99 	return ret;
    100 }
    101 
    102 void init_random(randdata_t * state, uint32_t iter)
    103 {
    104 	struct timeval time;
    105 	if (iter == 0)
    106 		state->size = MIN_RANDBUF_SIZE * AVG_ITR_RNDBTS;
    107 	else if (iter > MAX_RANDBUF_SIZE)
    108 		state->size = MAX_RANDBUF_SIZE * AVG_ITR_RNDBTS;
    109 	else
    110 		state->size = iter * AVG_ITR_RNDBTS;
    111 
    112 	state->mt = ffsb_malloc(state->size);
    113 
    114 	/* !!!! racy? add pthread_once stuff later  */
    115 	if ((randfd < 0) && (randfd = open(RANDSRC, O_RDONLY)) < 0) {
    116 		perror("open " RANDSRC);
    117 		exit(1);
    118 	}
    119 	sgenrand(state);
    120 	gettimeofday(&time, NULL);
    121 #ifdef HAVE_LRAND48
    122 	srand48_r(time.tv_sec, &state->data);
    123 #endif
    124 }
    125 
    126 void destroy_random(randdata_t * rd)
    127 {
    128 	free(rd->mt);
    129 }
    130 
    131 /*
    132  * I've taken the liberty of slightly redesigning this stuff.
    133  * Instead of simply getting the full word of random bits
    134  * and throwing away most of it using the mod operator,
    135  * we should only get byte-sized chunks of random bits and
    136  * construct our random number that way with less wasteage - SR
    137  */
    138 uint32_t getrandom(randdata_t * state, uint32_t mod)
    139 {
    140 
    141 	uint8_t bytes[4] = { 0, 0, 0, 0 };
    142 	uint32_t ret;
    143 	int num_bytes = 4;
    144 	int i;
    145 
    146 	if ((mod == 0) || (mod == 1))
    147 		return 0;
    148 
    149 	if (!(mod >> 8))
    150 		num_bytes = 1;
    151 	else if (!(mod >> 16))
    152 		num_bytes = 2;
    153 	else if (!(mod >> 24))
    154 		num_bytes = 3;
    155 
    156 	for (i = 0; i < num_bytes; i++)
    157 		bytes[i] = genrand8(state);
    158 
    159 	ret = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
    160 
    161 	return ret % mod;
    162 }
    163 
    164 uint64_t getllrandom(randdata_t * state, uint64_t mod)
    165 {
    166 	uint64_t result = 0;
    167 	uint64_t high = 0;
    168 	uint32_t low = 0;
    169 
    170 	if (mod == 0)
    171 		return 0;
    172 
    173 	/* ULONG_MAX comes from limits.h */
    174 	if (mod < ULONG_MAX)
    175 		return (uint64_t) getrandom(state, (uint32_t) mod);
    176 
    177 	high = genrand32(state);
    178 
    179 	low = genrand32(state);
    180 
    181 	result = high << 32;
    182 	result |= (uint64_t) low;
    183 
    184 	assert(result != 0);
    185 	assert(result > 0);
    186 
    187 	return result % mod;
    188 }
    189