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