SimpleStats lag;
} StatsData;
+/*
+ * Struct to keep random state.
+ */
+typedef struct RandomState
+{
+ unsigned short xseed[3];
+} RandomState;
+
/*
* Connection state machine states.
*/
ConnectionStateEnum state; /* state machine's current state. */
ConditionalStack cstack; /* enclosing conditionals state */
+ /*
+ * Separate randomness for each client. This is used for random functions
+ * PGBENCH_RANDOM_* during the execution of the script.
+ */
+ RandomState cs_func_rs;
+
int use_file; /* index in sql_script for this client */
int command; /* command number in script */
pthread_t thread; /* thread handle */
CState *state; /* array of CState */
int nstate; /* length of state[] */
- unsigned short random_state[3]; /* separate randomness for each thread */
+
+ /*
+ * Separate randomness for each thread. Each thread option uses its own
+ * 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 */
+
int64 throttle_trigger; /* previous/next throttling (us) */
FILE *logfile; /* where to log, or NULL */
ZipfCache zipf_cache; /* for thread-safe zipfian random number
return true;
}
+/*
+ * Initialize a random state struct.
+ */
+static void
+initRandomState(RandomState *random_state)
+{
+ random_state->xseed[0] = random();
+ random_state->xseed[1] = random();
+ random_state->xseed[2] = random();
+}
+
/* random number generator: uniform distribution from min to max inclusive */
static int64
-getrand(TState *thread, int64 min, int64 max)
+getrand(RandomState *random_state, int64 min, int64 max)
{
/*
* Odd coding is so that min and max have approximately the same chance of
* protected by a mutex, and therefore a bottleneck on machines with many
* CPUs.
*/
- return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
+ return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
}
/*
* value is exp(-parameter).
*/
static int64
-getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
+getExponentialRand(RandomState *random_state, int64 min, int64 max,
+ double parameter)
{
double cut,
uniform,
Assert(parameter > 0.0);
cut = exp(-parameter);
/* erand in [0, 1), uniform in (0, 1] */
- uniform = 1.0 - pg_erand48(thread->random_state);
+ uniform = 1.0 - pg_erand48(random_state->xseed);
/*
* inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
/* random number generator: gaussian distribution from min to max inclusive */
static int64
-getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
+getGaussianRand(RandomState *random_state, int64 min, int64 max,
+ double parameter)
{
double stdev;
double rand;
* are expected in (0, 1] (see
* https://en.wikipedia.org/wiki/Box-Muller_transform)
*/
- double rand1 = 1.0 - pg_erand48(thread->random_state);
- double rand2 = 1.0 - pg_erand48(thread->random_state);
+ double rand1 = 1.0 - pg_erand48(random_state->xseed);
+ double rand2 = 1.0 - pg_erand48(random_state->xseed);
/* Box-Muller basic form transform */
double var_sqrt = sqrt(-2.0 * log(rand1));
* not be one.
*/
static int64
-getPoissonRand(TState *thread, double center)
+getPoissonRand(RandomState *random_state, double center)
{
/*
* Use inverse transform sampling to generate a value > 0, such that the
double uniform;
/* erand in [0, 1), uniform in (0, 1] */
- uniform = 1.0 - pg_erand48(thread->random_state);
+ uniform = 1.0 - pg_erand48(random_state->xseed);
return (int64) (-log(uniform) * center + 0.5);
}
* Luc Devroye, p. 550-551, Springer 1986.
*/
static int64
-computeIterativeZipfian(TState *thread, int64 n, double s)
+computeIterativeZipfian(RandomState *random_state, int64 n, double s)
{
double b = pow(2.0, s - 1.0);
double x,
while (true)
{
/* random variates */
- u = pg_erand48(thread->random_state);
- v = pg_erand48(thread->random_state);
+ u = pg_erand48(random_state->xseed);
+ v = pg_erand48(random_state->xseed);
x = floor(pow(u, -1.0 / (s - 1.0)));
* Jim Gray et al, SIGMOD 1994
*/
static int64
-computeHarmonicZipfian(TState *thread, int64 n, double s)
+computeHarmonicZipfian(ZipfCache *zipf_cache, RandomState *random_state,
+ int64 n, double s)
{
- ZipfCell *cell = zipfFindOrCreateCacheCell(&thread->zipf_cache, n, s);
- double uniform = pg_erand48(thread->random_state);
+ ZipfCell *cell = zipfFindOrCreateCacheCell(zipf_cache, n, s);
+ double uniform = pg_erand48(random_state->xseed);
double uz = uniform * cell->harmonicn;
if (uz < 1.0)
/* random number generator: zipfian distribution from min to max inclusive */
static int64
-getZipfianRand(TState *thread, int64 min, int64 max, double s)
+getZipfianRand(ZipfCache *zipf_cache, RandomState *random_state, int64 min,
+ int64 max, double s)
{
int64 n = max - min + 1;
/* abort if parameter is invalid */
Assert(s > 0.0 && s != 1.0 && s <= MAX_ZIPFIAN_PARAM);
-
return min - 1 + ((s > 1)
- ? computeIterativeZipfian(thread, n, s)
- : computeHarmonicZipfian(thread, n, s));
+ ? computeIterativeZipfian(random_state, n, s)
+ : computeHarmonicZipfian(zipf_cache, random_state, n, s));
}
/*
if (func == PGBENCH_RANDOM)
{
Assert(nargs == 2);
- setIntValue(retval, getrand(thread, imin, imax));
+ setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
}
else /* gaussian & exponential */
{
}
setIntValue(retval,
- getGaussianRand(thread, imin, imax, param));
+ getGaussianRand(&st->cs_func_rs,
+ imin, imax, param));
}
else if (func == PGBENCH_RANDOM_ZIPFIAN)
{
return false;
}
setIntValue(retval,
- getZipfianRand(thread, imin, imax, param));
+ getZipfianRand(&thread->zipf_cache,
+ &st->cs_func_rs,
+ imin, imax, param));
}
else /* exponential */
{
}
setIntValue(retval,
- getExponentialRand(thread, imin, imax, param));
+ getExponentialRand(&st->cs_func_rs,
+ imin, imax, param));
}
}
if (num_scripts == 1)
return 0;
- w = getrand(thread, 0, total_weight - 1);
+ w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
do
{
w -= sql_script[i++].weight;
* away.
*/
Assert(throttle_delay > 0);
- wait = getPoissonRand(thread, throttle_delay);
+ wait = getPoissonRand(&thread->ts_throttle_rs, throttle_delay);
thread->throttle_trigger += wait;
st->txn_scheduled = thread->throttle_trigger;
{
processXactStats(thread, st, &now, true, agg);
/* next rendez-vous */
- wait = getPoissonRand(thread, throttle_delay);
+ wait = getPoissonRand(&thread->ts_throttle_rs,
+ throttle_delay);
thread->throttle_trigger += wait;
st->txn_scheduled = thread->throttle_trigger;
}
* to the random sample.
*/
if (sample_rate != 0.0 &&
- pg_erand48(thread->random_state) > sample_rate)
+ pg_erand48(thread->ts_sample_rs.xseed) > sample_rate)
return;
/* should we aggregate the results or not? */
return true;
}
-
int
main(int argc, char **argv)
{
for (i = 0; i < nclients; i++)
{
state[i].cstack = conditional_stack_create();
+ initRandomState(&state[i].cs_func_rs);
}
if (debug)
thread->state = &state[nclients_dealt];
thread->nstate =
(nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
- thread->random_state[0] = random();
- thread->random_state[1] = random();
- thread->random_state[2] = random();
+ initRandomState(&thread->ts_choose_rs);
+ initRandomState(&thread->ts_throttle_rs);
+ initRandomState(&thread->ts_sample_rs);
thread->logfile = NULL; /* filled in later */
thread->latency_late = 0;
thread->zipf_cache.nb_cells = 0;