aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pgbench/pgbench.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pgbench/pgbench.c')
-rw-r--r--src/bin/pgbench/pgbench.c122
1 files changed, 46 insertions, 76 deletions
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index c12b6f06159..ea9639984cf 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -59,6 +59,7 @@
#include "common/int.h"
#include "common/logging.h"
+#include "common/pg_prng.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
@@ -350,16 +351,8 @@ typedef struct StatsData
*/
pg_time_usec_t epoch_shift;
-/*
- * Struct to keep random state.
- */
-typedef struct RandomState
-{
- unsigned short xseed[3];
-} RandomState;
-
/* Various random sequences are initialized from this one. */
-static RandomState base_random_sequence;
+static pg_prng_state base_random_sequence;
/* Synchronization barrier for start and connection */
static THREAD_BARRIER_T barrier;
@@ -461,7 +454,7 @@ typedef struct
* Separate randomness for each client. This is used for random functions
* PGBENCH_RANDOM_* during the execution of the script.
*/
- RandomState cs_func_rs;
+ pg_prng_state cs_func_rs;
int use_file; /* index in sql_script for this client */
int command; /* command number in script */
@@ -498,9 +491,9 @@ typedef struct
* random state to make all of them independent of each other and
* therefore deterministic at the thread level.
*/
- RandomState ts_choose_rs; /* random state for selecting a script */
- RandomState ts_throttle_rs; /* random state for transaction throttling */
- RandomState ts_sample_rs; /* random state for log sampling */
+ pg_prng_state ts_choose_rs; /* random state for selecting a script */
+ pg_prng_state ts_throttle_rs; /* random state for transaction throttling */
+ pg_prng_state ts_sample_rs; /* random state for log sampling */
int64 throttle_trigger; /* previous/next throttling (us) */
FILE *logfile; /* where to log, or NULL */
@@ -898,42 +891,28 @@ strtodouble(const char *str, bool errorOK, double *dv)
}
/*
- * Initialize a random state struct.
+ * Initialize a prng state struct.
*
* We derive the seed from base_random_sequence, which must be set up already.
*/
static void
-initRandomState(RandomState *random_state)
-{
- random_state->xseed[0] = (unsigned short)
- (pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
- random_state->xseed[1] = (unsigned short)
- (pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
- random_state->xseed[2] = (unsigned short)
- (pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
+initRandomState(pg_prng_state *state)
+{
+ pg_prng_seed(state, pg_prng_uint64(&base_random_sequence));
}
+
/*
- * Random number generator: uniform distribution from min to max inclusive.
+ * random number generator: uniform distribution from min to max inclusive.
*
* Although the limits are expressed as int64, you can't generate the full
* int64 range in one call, because the difference of the limits mustn't
- * overflow int64. In practice it's unwise to ask for more than an int32
- * range, because of the limited precision of pg_erand48().
+ * overflow int64. This is not checked.
*/
static int64
-getrand(RandomState *random_state, int64 min, int64 max)
+getrand(pg_prng_state *state, int64 min, int64 max)
{
- /*
- * Odd coding is so that min and max have approximately the same chance of
- * being selected as do numbers between them.
- *
- * pg_erand48() is thread-safe and concurrent, which is why we use it
- * rather than random(), which in glibc is non-reentrant, and therefore
- * protected by a mutex, and therefore a bottleneck on machines with many
- * CPUs.
- */
- return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
+ return min + (int64) pg_prng_uint64_range(state, 0, max - min);
}
/*
@@ -942,7 +921,7 @@ getrand(RandomState *random_state, int64 min, int64 max)
* value is exp(-parameter).
*/
static int64
-getExponentialRand(RandomState *random_state, int64 min, int64 max,
+getExponentialRand(pg_prng_state *state, int64 min, int64 max,
double parameter)
{
double cut,
@@ -952,8 +931,8 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
/* abort if wrong parameter, but must really be checked beforehand */
Assert(parameter > 0.0);
cut = exp(-parameter);
- /* erand in [0, 1), uniform in (0, 1] */
- uniform = 1.0 - pg_erand48(random_state->xseed);
+ /* pg_prng_double value in [0, 1), uniform in (0, 1] */
+ uniform = 1.0 - pg_prng_double(state);
/*
* inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
@@ -966,7 +945,7 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
/* random number generator: gaussian distribution from min to max inclusive */
static int64
-getGaussianRand(RandomState *random_state, int64 min, int64 max,
+getGaussianRand(pg_prng_state *state, int64 min, int64 max,
double parameter)
{
double stdev;
@@ -990,13 +969,13 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
do
{
/*
- * pg_erand48 generates [0,1), but for the basic version of the
+ * pg_prng_double generates [0, 1), but for the basic version of the
* Box-Muller transform the two uniformly distributed random numbers
- * are expected in (0, 1] (see
+ * are expected to be in (0, 1] (see
* https://en.wikipedia.org/wiki/Box-Muller_transform)
*/
- double rand1 = 1.0 - pg_erand48(random_state->xseed);
- double rand2 = 1.0 - pg_erand48(random_state->xseed);
+ double rand1 = 1.0 - pg_prng_double(state);
+ double rand2 = 1.0 - pg_prng_double(state);
/* Box-Muller basic form transform */
double var_sqrt = sqrt(-2.0 * log(rand1));
@@ -1026,7 +1005,7 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
* not be one.
*/
static int64
-getPoissonRand(RandomState *random_state, double center)
+getPoissonRand(pg_prng_state *state, double center)
{
/*
* Use inverse transform sampling to generate a value > 0, such that the
@@ -1034,8 +1013,8 @@ getPoissonRand(RandomState *random_state, double center)
*/
double uniform;
- /* erand in [0, 1), uniform in (0, 1] */
- uniform = 1.0 - pg_erand48(random_state->xseed);
+ /* pg_prng_double value in [0, 1), uniform in (0, 1] */
+ uniform = 1.0 - pg_prng_double(state);
return (int64) (-log(uniform) * center + 0.5);
}
@@ -1048,7 +1027,7 @@ getPoissonRand(RandomState *random_state, double center)
* This works for s > 1.0, but may perform badly for s very close to 1.0.
*/
static int64
-computeIterativeZipfian(RandomState *random_state, int64 n, double s)
+computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
{
double b = pow(2.0, s - 1.0);
double x,
@@ -1063,8 +1042,8 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
while (true)
{
/* random variates */
- u = pg_erand48(random_state->xseed);
- v = pg_erand48(random_state->xseed);
+ u = pg_prng_double(state);
+ v = pg_prng_double(state);
x = floor(pow(u, -1.0 / (s - 1.0)));
@@ -1078,14 +1057,14 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
/* random number generator: zipfian distribution from min to max inclusive */
static int64
-getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
+getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
{
int64 n = max - min + 1;
/* abort if parameter is invalid */
Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
- return min - 1 + computeIterativeZipfian(random_state, n, s);
+ return min - 1 + computeIterativeZipfian(state, n, s);
}
/*
@@ -1142,7 +1121,7 @@ getHashMurmur2(int64 val, uint64 seed)
* For small sizes, this generates each of the (size!) possible permutations
* of integers in the range [0, size) with roughly equal probability. Once
* the size is larger than 20, the number of possible permutations exceeds the
- * number of distinct states of the internal pseudorandom number generators,
+ * number of distinct states of the internal pseudorandom number generator,
* and so not all possible permutations can be generated, but the permutations
* chosen should continue to give the appearance of being random.
*
@@ -1152,8 +1131,8 @@ getHashMurmur2(int64 val, uint64 seed)
static int64
permute(const int64 val, const int64 isize, const int64 seed)
{
- RandomState random_state1;
- RandomState random_state2;
+ /* using a high-end PRNG is probably overkill */
+ pg_prng_state state;
uint64 size;
uint64 v;
int masklen;
@@ -1163,14 +1142,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
if (isize < 2)
return 0; /* nothing to permute */
- /* Initialize a pair of random states using the seed */
- random_state1.xseed[0] = seed & 0xFFFF;
- random_state1.xseed[1] = (seed >> 16) & 0xFFFF;
- random_state1.xseed[2] = (seed >> 32) & 0xFFFF;
-
- random_state2.xseed[0] = (((uint64) seed) >> 48) & 0xFFFF;
- random_state2.xseed[1] = seed & 0xFFFF;
- random_state2.xseed[2] = (seed >> 16) & 0xFFFF;
+ /* Initialize prng state using the seed */
+ pg_prng_seed(&state, (uint64) seed);
/* Computations are performed on unsigned values */
size = (uint64) isize;
@@ -1216,8 +1189,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
t;
/* Random multiply (by an odd number), XOR and rotate of lower half */
- m = (uint64) getrand(&random_state1, 0, mask) | 1;
- r = (uint64) getrand(&random_state2, 0, mask);
+ m = (pg_prng_uint64(&state) & mask) | 1;
+ r = pg_prng_uint64(&state) & mask;
if (v <= mask)
{
v = ((v * m) ^ r) & mask;
@@ -1225,8 +1198,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
}
/* Random multiply (by an odd number), XOR and rotate of upper half */
- m = (uint64) getrand(&random_state1, 0, mask) | 1;
- r = (uint64) getrand(&random_state2, 0, mask);
+ m = (pg_prng_uint64(&state) & mask) | 1;
+ r = pg_prng_uint64(&state) & mask;
t = size - 1 - v;
if (t <= mask)
{
@@ -1236,7 +1209,7 @@ permute(const int64 val, const int64 isize, const int64 seed)
}
/* Random offset */
- r = (uint64) getrand(&random_state2, 0, size - 1);
+ r = pg_prng_uint64_range(&state, 0, size - 1);
v = (v + r) % size;
}
@@ -3831,7 +3804,7 @@ doLog(TState *thread, CState *st,
* to the random sample.
*/
if (sample_rate != 0.0 &&
- pg_erand48(thread->ts_sample_rs.xseed) > sample_rate)
+ pg_prng_double(&thread->ts_sample_rs) > sample_rate)
return;
/* should we aggregate the results or not? */
@@ -5770,12 +5743,11 @@ set_random_seed(const char *seed)
if (seed != NULL)
pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
+
random_seed = iseed;
- /* Fill base_random_sequence with low-order bits of seed */
- base_random_sequence.xseed[0] = iseed & 0xFFFF;
- base_random_sequence.xseed[1] = (iseed >> 16) & 0xFFFF;
- base_random_sequence.xseed[2] = (iseed >> 32) & 0xFFFF;
+ /* Initialize base_random_sequence using seed */
+ pg_prng_seed(&base_random_sequence, (uint64) iseed);
return true;
}
@@ -6449,9 +6421,7 @@ main(int argc, char **argv)
/* set default seed for hash functions */
if (lookupVariable(&state[0], "default_seed") == NULL)
{
- uint64 seed =
- ((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) |
- (((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) << 32);
+ uint64 seed = pg_prng_uint64(&base_random_sequence);
for (i = 0; i < nclients; i++)
if (!putVariableInt(&state[i], "startup", "default_seed", (int64) seed))