/*
|
* 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 <stdlib.h>
|
#include <stdio.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <sys/time.h>
|
#include <fcntl.h>
|
#include <unistd.h>
|
#include <limits.h>
|
#include <inttypes.h>
|
#include <assert.h>
|
|
#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;
|
}
|