@@ -279,6 +279,14 @@ typedef struct StatsData
279279 SimpleStats 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
360368 ConnectionStateEnum state ; /* state machine's current state. */
361369 ConditionalStack 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+
363377 int use_file ; /* index in sql_script for this client */
364378 int command ; /* command number in script */
365379
@@ -419,7 +433,16 @@ typedef struct
419433 pthread_t thread ; /* thread handle */
420434 CState * state ; /* array of CState */
421435 int 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+
423446 int64 throttle_trigger ; /* previous/next throttling (us) */
424447 FILE * logfile ; /* where to log, or NULL */
425448 ZipfCache zipf_cache ; /* for thread-safe zipfian random number
@@ -769,9 +792,20 @@ strtodouble(const char *str, bool errorOK, double *dv)
769792 return 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{
796831 double cut ,
797832 uniform ,
@@ -801,7 +836,7 @@ getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
801836 Assert (parameter > 0.0 );
802837 cut = 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{
819855 double stdev ;
820856 double 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 */
849885 double 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)
882918 double 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
887923 return (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{
9651001 double b = pow (2.0 , s - 1.0 );
9661002 double x ,
@@ -971,8 +1007,8 @@ computeIterativeZipfian(TState *thread, int64 n, double s)
9711007 while (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
9771013 x = 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 );
9971034 double uz = uniform * cell -> harmonicn ;
9981035
9991036 if (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{
10101048 int64 n = max - min + 1 ;
10111049
10121050 /* abort if parameter is invalid */
10131051 Assert (s > 0.0 && s != 1.0 && s <= MAX_ZIPFIAN_PARAM );
10141052
1015-
10161053 return 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,
23102347 if (func == PGBENCH_RANDOM )
23112348 {
23122349 Assert (nargs == 2 );
2313- setIntValue (retval , getrand (thread , imin , imax ));
2350+ setIntValue (retval , getrand (& st -> cs_func_rs , imin , imax ));
23142351 }
23152352 else /* gaussian & exponential */
23162353 {
@@ -2332,7 +2369,8 @@ evalStandardFunc(TState *thread, CState *st,
23322369 }
23332370
23342371 setIntValue (retval ,
2335- getGaussianRand (thread , imin , imax , param ));
2372+ getGaussianRand (& st -> cs_func_rs ,
2373+ imin , imax , param ));
23362374 }
23372375 else if (func == PGBENCH_RANDOM_ZIPFIAN )
23382376 {
@@ -2344,7 +2382,9 @@ evalStandardFunc(TState *thread, CState *st,
23442382 return false;
23452383 }
23462384 setIntValue (retval ,
2347- getZipfianRand (thread , imin , imax , param ));
2385+ getZipfianRand (& thread -> zipf_cache ,
2386+ & st -> cs_func_rs ,
2387+ imin , imax , param ));
23482388 }
23492389 else /* exponential */
23502390 {
@@ -2357,7 +2397,8 @@ evalStandardFunc(TState *thread, CState *st,
23572397 }
23582398
23592399 setIntValue (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)
26522693 if (num_scripts == 1 )
26532694 return 0 ;
26542695
2655- w = getrand (thread , 0 , total_weight - 1 );
2696+ w = getrand (& thread -> ts_choose_rs , 0 , total_weight - 1 );
26562697 do
26572698 {
26582699 w -= sql_script [i ++ ].weight ;
@@ -2846,7 +2887,7 @@ doCustom(TState *thread, CState *st, StatsData *agg)
28462887 * away.
28472888 */
28482889 Assert (throttle_delay > 0 );
2849- wait = getPoissonRand (thread , throttle_delay );
2890+ wait = getPoissonRand (& thread -> ts_throttle_rs , throttle_delay );
28502891
28512892 thread -> throttle_trigger += wait ;
28522893 st -> txn_scheduled = thread -> throttle_trigger ;
@@ -2880,7 +2921,8 @@ doCustom(TState *thread, CState *st, StatsData *agg)
28802921 {
28812922 processXactStats (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 );
28842926 thread -> throttle_trigger += wait ;
28852927 st -> txn_scheduled = thread -> throttle_trigger ;
28862928 }
@@ -3423,7 +3465,7 @@ doLog(TState *thread, CState *st,
34233465 * to the random sample.
34243466 */
34253467 if (sample_rate != 0.0 &&
3426- pg_erand48 (thread -> random_state ) > sample_rate )
3468+ pg_erand48 (thread -> ts_sample_rs . xseed ) > sample_rate )
34273469 return ;
34283470
34293471 /* should we aggregate the results or not? */
@@ -4851,7 +4893,6 @@ set_random_seed(const char *seed)
48514893 return true;
48524894}
48534895
4854-
48554896int
48564897main (int argc , char * * argv )
48574898{
@@ -5465,6 +5506,7 @@ main(int argc, char **argv)
54655506 for (i = 0 ; i < nclients ; i ++ )
54665507 {
54675508 state [i ].cstack = conditional_stack_create ();
5509+ initRandomState (& state [i ].cs_func_rs );
54685510 }
54695511
54705512 if (debug )
@@ -5598,9 +5640,9 @@ main(int argc, char **argv)
55985640 thread -> state = & state [nclients_dealt ];
55995641 thread -> 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 );
56045646 thread -> logfile = NULL ; /* filled in later */
56055647 thread -> latency_late = 0 ;
56065648 thread -> zipf_cache .nb_cells = 0 ;
0 commit comments