/* * Copyright (c) International Business Machines Corp., 2001-2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "rand.h" #include "util.h" #define RANDSRC "/dev/urandom" static int randfd = -1; /* close the file after we're done with the benchmark */ void randcleanup(void) { if (randfd > 0) close(randfd); } /* We fill up the array with random bits from RANDSRC here and set index */ /* to 0 */ /* pre: state->size must be set and state->mt must be allocated! */ static void sgenrand(randdata_t * state) { int got = 0; got = read(randfd, state->mt, state->size); if (got != state->size) { int i; /* fall back on lrand48 */ /* printf("fallback_rand\n"); */ for (i = got; i < state->size; i += 4) { long int rand = 0; #ifdef HAVE_LRAND48 lrand48_r(&(state->data), &rand); #else rand = random(); #endif assert(rand != 0); state->mt[i] = (rand >> 24) & (512 - 1); state->mt[i + 1] = (rand >> 16) & (512 - 1); state->mt[i + 2] = (rand >> 8) & (512 - 1); state->mt[i + 3] = (rand) & (512 - 1); } } state->mti = 0; } /* returns 8 random bits */ static uint8_t genrand8(randdata_t * state) { unsigned long ret = 0; if (state->mti >= state->size) { /* sgenrand(state); */ state->mti = 0; } ret = state->mt[state->mti]; state->mti++; return ret; } /* returns 32 random bits */ static uint32_t genrand32(randdata_t * state) { uint8_t bytes[4]; uint32_t ret = 0; bytes[0] = genrand8(state); bytes[1] = genrand8(state); bytes[2] = genrand8(state); bytes[3] = genrand8(state); ret = *((uint32_t *) bytes); /* !!! hack */ return ret; } void init_random(randdata_t * state, uint32_t iter) { struct timeval time; if (iter == 0) state->size = MIN_RANDBUF_SIZE * AVG_ITR_RNDBTS; else if (iter > MAX_RANDBUF_SIZE) state->size = MAX_RANDBUF_SIZE * AVG_ITR_RNDBTS; else state->size = iter * AVG_ITR_RNDBTS; state->mt = ffsb_malloc(state->size); /* !!!! racy? add pthread_once stuff later */ if ((randfd < 0) && (randfd = open(RANDSRC, O_RDONLY)) < 0) { perror("open " RANDSRC); exit(1); } sgenrand(state); gettimeofday(&time, NULL); #ifdef HAVE_LRAND48 srand48_r(time.tv_sec, &state->data); #endif } void destroy_random(randdata_t * rd) { free(rd->mt); } /* * I've taken the liberty of slightly redesigning this stuff. * Instead of simply getting the full word of random bits * and throwing away most of it using the mod operator, * we should only get byte-sized chunks of random bits and * construct our random number that way with less wasteage - SR */ uint32_t getrandom(randdata_t * state, uint32_t mod) { uint8_t bytes[4] = { 0, 0, 0, 0 }; uint32_t ret; int num_bytes = 4; int i; if ((mod == 0) || (mod == 1)) return 0; if (!(mod >> 8)) num_bytes = 1; else if (!(mod >> 16)) num_bytes = 2; else if (!(mod >> 24)) num_bytes = 3; for (i = 0; i < num_bytes; i++) bytes[i] = genrand8(state); ret = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]; return ret % mod; } uint64_t getllrandom(randdata_t * state, uint64_t mod) { uint64_t result = 0; uint64_t high = 0; uint32_t low = 0; if (mod == 0) return 0; /* ULONG_MAX comes from limits.h */ if (mod < ULONG_MAX) return (uint64_t) getrandom(state, (uint32_t) mod); high = genrand32(state); low = genrand32(state); result = high << 32; result |= (uint64_t) low; assert(result != 0); assert(result > 0); return result % mod; }