@@ -279,6 +279,14 @@ typedef struct StatsData
279279SimpleStats lag ;
280280}StatsData ;
281281
282+ /*
283+ * Struct to keep random state.
284+ */
285+ typedef struct RandomState
286+ {
287+ unsigned short xseed [3 ];
288+ }RandomState ;
289+
282290/*
283291 * Connection state machine states.
284292 */
@@ -360,6 +368,12 @@ typedef struct
360368ConnectionStateEnum state ;/* state machine's current state. */
361369ConditionalStack cstack ;/* enclosing conditionals state */
362370
371+ /*
372+ * Separate randomness for each client. This is used for random functions
373+ * PGBENCH_RANDOM_* during the execution of the script.
374+ */
375+ RandomState cs_func_rs ;
376+
363377int use_file ;/* index in sql_script for this client */
364378int command ;/* command number in script */
365379
@@ -419,7 +433,16 @@ typedef struct
419433pthread_t thread ;/* thread handle */
420434CState * state ;/* array of CState */
421435int nstate ;/* length of state[] */
422- unsigned short random_state [3 ];/* separate randomness for each thread */
436+
437+ /*
438+ * Separate randomness for each thread. Each thread option uses its own
439+ * random state to make all of them independent of each other and therefore
440+ * deterministic at the thread level.
441+ */
442+ RandomState ts_choose_rs ;/* random state for selecting a script */
443+ RandomState ts_throttle_rs ;/* random state for transaction throttling */
444+ RandomState ts_sample_rs ;/* random state for log sampling */
445+
423446int64 throttle_trigger ;/* previous/next throttling (us) */
424447FILE * logfile ;/* where to log, or NULL */
425448ZipfCache zipf_cache ;/* for thread-safe zipfian random number
@@ -769,9 +792,20 @@ strtodouble(const char *str, bool errorOK, double *dv)
769792return true;
770793}
771794
795+ /*
796+ * Initialize a random state struct.
797+ */
798+ static void
799+ initRandomState (RandomState * random_state )
800+ {
801+ random_state -> xseed [0 ]= random ();
802+ random_state -> xseed [1 ]= random ();
803+ random_state -> xseed [2 ]= random ();
804+ }
805+
772806/* random number generator: uniform distribution from min to max inclusive */
773807static int64
774- getrand (TState * thread ,int64 min ,int64 max )
808+ getrand (RandomState * random_state ,int64 min ,int64 max )
775809{
776810/*
777811 * Odd coding is so that min and max have approximately the same chance of
@@ -782,7 +816,7 @@ getrand(TState *thread, int64 min, int64 max)
782816 * protected by a mutex, and therefore a bottleneck on machines with many
783817 * CPUs.
784818 */
785- return min + (int64 ) ((max - min + 1 )* pg_erand48 (thread -> random_state ));
819+ return min + (int64 ) ((max - min + 1 )* pg_erand48 (random_state -> xseed ));
786820}
787821
788822/*
@@ -791,7 +825,8 @@ getrand(TState *thread, int64 min, int64 max)
791825 * value is exp(-parameter).
792826 */
793827static int64
794- getExponentialRand (TState * thread ,int64 min ,int64 max ,double parameter )
828+ getExponentialRand (RandomState * random_state ,int64 min ,int64 max ,
829+ double parameter )
795830{
796831double cut ,
797832uniform ,
@@ -801,7 +836,7 @@ getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
801836Assert (parameter > 0.0 );
802837cut = exp (- parameter );
803838/* erand in [0, 1), uniform in (0, 1] */
804- uniform = 1.0 - pg_erand48 (thread -> random_state );
839+ uniform = 1.0 - pg_erand48 (random_state -> xseed );
805840
806841/*
807842 * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
@@ -814,7 +849,8 @@ getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
814849
815850/* random number generator: gaussian distribution from min to max inclusive */
816851static int64
817- getGaussianRand (TState * thread ,int64 min ,int64 max ,double parameter )
852+ getGaussianRand (RandomState * random_state ,int64 min ,int64 max ,
853+ double parameter )
818854{
819855double stdev ;
820856double rand ;
@@ -842,8 +878,8 @@ getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
842878 * are expected in (0, 1] (see
843879 * https://en.wikipedia.org/wiki/Box-Muller_transform)
844880 */
845- double rand1 = 1.0 - pg_erand48 (thread -> random_state );
846- double rand2 = 1.0 - pg_erand48 (thread -> random_state );
881+ double rand1 = 1.0 - pg_erand48 (random_state -> xseed );
882+ double rand2 = 1.0 - pg_erand48 (random_state -> xseed );
847883
848884/* Box-Muller basic form transform */
849885double var_sqrt = sqrt (-2.0 * log (rand1 ));
@@ -873,7 +909,7 @@ getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
873909 * not be one.
874910 */
875911static int64
876- getPoissonRand (TState * thread ,double center )
912+ getPoissonRand (RandomState * random_state ,double center )
877913{
878914/*
879915 * Use inverse transform sampling to generate a value > 0, such that the
@@ -882,7 +918,7 @@ getPoissonRand(TState *thread, double center)
882918double uniform ;
883919
884920/* erand in [0, 1), uniform in (0, 1] */
885- uniform = 1.0 - pg_erand48 (thread -> random_state );
921+ uniform = 1.0 - pg_erand48 (random_state -> xseed );
886922
887923return (int64 ) (- log (uniform )* center + 0.5 );
888924}
@@ -960,7 +996,7 @@ zipfFindOrCreateCacheCell(ZipfCache *cache, int64 n, double s)
960996 * Luc Devroye, p. 550-551, Springer 1986.
961997 */
962998static int64
963- computeIterativeZipfian (TState * thread ,int64 n ,double s )
999+ computeIterativeZipfian (RandomState * random_state ,int64 n ,double s )
9641000{
9651001double b = pow (2.0 ,s - 1.0 );
9661002double x ,
@@ -971,8 +1007,8 @@ computeIterativeZipfian(TState *thread, int64 n, double s)
9711007while (true)
9721008{
9731009/* random variates */
974- u = pg_erand48 (thread -> random_state );
975- v = pg_erand48 (thread -> random_state );
1010+ u = pg_erand48 (random_state -> xseed );
1011+ v = pg_erand48 (random_state -> xseed );
9761012
9771013x = floor (pow (u ,-1.0 / (s - 1.0 )));
9781014
@@ -990,10 +1026,11 @@ computeIterativeZipfian(TState *thread, int64 n, double s)
9901026 * Jim Gray et al, SIGMOD 1994
9911027 */
9921028static int64
993- computeHarmonicZipfian (TState * thread ,int64 n ,double s )
1029+ computeHarmonicZipfian (ZipfCache * zipf_cache ,RandomState * random_state ,
1030+ int64 n ,double s )
9941031{
995- ZipfCell * cell = zipfFindOrCreateCacheCell (& thread -> zipf_cache ,n ,s );
996- double uniform = pg_erand48 (thread -> random_state );
1032+ ZipfCell * cell = zipfFindOrCreateCacheCell (zipf_cache ,n ,s );
1033+ double uniform = pg_erand48 (random_state -> xseed );
9971034double uz = uniform * cell -> harmonicn ;
9981035
9991036if (uz < 1.0 )
@@ -1005,17 +1042,17 @@ computeHarmonicZipfian(TState *thread, int64 n, double s)
10051042
10061043/* random number generator: zipfian distribution from min to max inclusive */
10071044static int64
1008- getZipfianRand (TState * thread ,int64 min ,int64 max ,double s )
1045+ getZipfianRand (ZipfCache * zipf_cache ,RandomState * random_state ,int64 min ,
1046+ int64 max ,double s )
10091047{
10101048int64 n = max - min + 1 ;
10111049
10121050/* abort if parameter is invalid */
10131051Assert (s > 0.0 && s != 1.0 && s <=MAX_ZIPFIAN_PARAM );
10141052
1015-
10161053return min - 1 + ((s > 1 )
1017- ?computeIterativeZipfian (thread ,n ,s )
1018- :computeHarmonicZipfian (thread ,n ,s ));
1054+ ?computeIterativeZipfian (random_state ,n ,s )
1055+ :computeHarmonicZipfian (zipf_cache , random_state ,n ,s ));
10191056}
10201057
10211058/*
@@ -2310,7 +2347,7 @@ evalStandardFunc(TState *thread, CState *st,
23102347if (func == PGBENCH_RANDOM )
23112348{
23122349Assert (nargs == 2 );
2313- setIntValue (retval ,getrand (thread ,imin ,imax ));
2350+ setIntValue (retval ,getrand (& st -> cs_func_rs ,imin ,imax ));
23142351}
23152352else /* gaussian & exponential */
23162353{
@@ -2332,7 +2369,8 @@ evalStandardFunc(TState *thread, CState *st,
23322369}
23332370
23342371setIntValue (retval ,
2335- getGaussianRand (thread ,imin ,imax ,param ));
2372+ getGaussianRand (& st -> cs_func_rs ,
2373+ imin ,imax ,param ));
23362374}
23372375else if (func == PGBENCH_RANDOM_ZIPFIAN )
23382376{
@@ -2344,7 +2382,9 @@ evalStandardFunc(TState *thread, CState *st,
23442382return false;
23452383}
23462384setIntValue (retval ,
2347- getZipfianRand (thread ,imin ,imax ,param ));
2385+ getZipfianRand (& thread -> zipf_cache ,
2386+ & st -> cs_func_rs ,
2387+ imin ,imax ,param ));
23482388}
23492389else /* exponential */
23502390{
@@ -2357,7 +2397,8 @@ evalStandardFunc(TState *thread, CState *st,
23572397}
23582398
23592399setIntValue (retval ,
2360- getExponentialRand (thread ,imin ,imax ,param ));
2400+ getExponentialRand (& st -> cs_func_rs ,
2401+ imin ,imax ,param ));
23612402}
23622403}
23632404
@@ -2652,7 +2693,7 @@ chooseScript(TState *thread)
26522693if (num_scripts == 1 )
26532694return 0 ;
26542695
2655- w = getrand (thread ,0 ,total_weight - 1 );
2696+ w = getrand (& thread -> ts_choose_rs ,0 ,total_weight - 1 );
26562697do
26572698{
26582699w -= sql_script [i ++ ].weight ;
@@ -2846,7 +2887,7 @@ doCustom(TState *thread, CState *st, StatsData *agg)
28462887 * away.
28472888 */
28482889Assert (throttle_delay > 0 );
2849- wait = getPoissonRand (thread ,throttle_delay );
2890+ wait = getPoissonRand (& thread -> ts_throttle_rs ,throttle_delay );
28502891
28512892thread -> throttle_trigger += wait ;
28522893st -> txn_scheduled = thread -> throttle_trigger ;
@@ -2880,7 +2921,8 @@ doCustom(TState *thread, CState *st, StatsData *agg)
28802921{
28812922processXactStats (thread ,st ,& now , true,agg );
28822923/* next rendez-vous */
2883- wait = getPoissonRand (thread ,throttle_delay );
2924+ wait = getPoissonRand (& thread -> ts_throttle_rs ,
2925+ throttle_delay );
28842926thread -> throttle_trigger += wait ;
28852927st -> txn_scheduled = thread -> throttle_trigger ;
28862928}
@@ -3423,7 +3465,7 @@ doLog(TState *thread, CState *st,
34233465 * to the random sample.
34243466 */
34253467if (sample_rate != 0.0 &&
3426- pg_erand48 (thread -> random_state )> sample_rate )
3468+ pg_erand48 (thread -> ts_sample_rs . xseed )> sample_rate )
34273469return ;
34283470
34293471/* should we aggregate the results or not? */
@@ -4851,7 +4893,6 @@ set_random_seed(const char *seed)
48514893return true;
48524894}
48534895
4854-
48554896int
48564897main (int argc ,char * * argv )
48574898{
@@ -5465,6 +5506,7 @@ main(int argc, char **argv)
54655506for (i = 0 ;i < nclients ;i ++ )
54665507{
54675508state [i ].cstack = conditional_stack_create ();
5509+ initRandomState (& state [i ].cs_func_rs );
54685510}
54695511
54705512if (debug )
@@ -5598,9 +5640,9 @@ main(int argc, char **argv)
55985640thread -> state = & state [nclients_dealt ];
55995641thread -> nstate =
56005642(nclients - nclients_dealt + nthreads - i - 1 ) / (nthreads - i );
5601- thread -> random_state [ 0 ] = random ( );
5602- thread -> random_state [ 1 ] = random ( );
5603- thread -> random_state [ 2 ] = random ( );
5643+ initRandomState ( & thread -> ts_choose_rs );
5644+ initRandomState ( & thread -> ts_throttle_rs );
5645+ initRandomState ( & thread -> ts_sample_rs );
56045646thread -> logfile = NULL ;/* filled in later */
56055647thread -> latency_late = 0 ;
56065648thread -> zipf_cache .nb_cells = 0 ;