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 */
randcleanup(void)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! */
sgenrand(randdata_t * state)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 */
genrand8(randdata_t * state)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 */
genrand32(randdata_t * state)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
init_random(randdata_t * state,uint32_t iter)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
destroy_random(randdata_t * rd)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 */
getrandom(randdata_t * state,uint32_t mod)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
getllrandom(randdata_t * state,uint64_t mod)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