@@ -279,6 +279,14 @@ typedef struct StatsData
279
279
SimpleStats lag ;
280
280
} StatsData ;
281
281
282
+ /*
283
+ * Struct to keep random state.
284
+ */
285
+ typedef struct RandomState
286
+ {
287
+ unsigned short xseed [3 ];
288
+ } RandomState ;
289
+
282
290
/*
283
291
* Connection state machine states.
284
292
*/
@@ -360,6 +368,12 @@ typedef struct
360
368
ConnectionStateEnum state ; /* state machine's current state. */
361
369
ConditionalStack cstack ; /* enclosing conditionals state */
362
370
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
+
363
377
int use_file ; /* index in sql_script for this client */
364
378
int command ; /* command number in script */
365
379
@@ -419,7 +433,16 @@ typedef struct
419
433
pthread_t thread ; /* thread handle */
420
434
CState * state ; /* array of CState */
421
435
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
+
423
446
int64 throttle_trigger ; /* previous/next throttling (us) */
424
447
FILE * logfile ; /* where to log, or NULL */
425
448
ZipfCache zipf_cache ; /* for thread-safe zipfian random number
@@ -769,9 +792,20 @@ strtodouble(const char *str, bool errorOK, double *dv)
769
792
return true;
770
793
}
771
794
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
+
772
806
/* random number generator: uniform distribution from min to max inclusive */
773
807
static int64
774
- getrand (TState * thread , int64 min , int64 max )
808
+ getrand (RandomState * random_state , int64 min , int64 max )
775
809
{
776
810
/*
777
811
* 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)
782
816
* protected by a mutex, and therefore a bottleneck on machines with many
783
817
* CPUs.
784
818
*/
785
- return min + (int64 ) ((max - min + 1 ) * pg_erand48 (thread -> random_state ));
819
+ return min + (int64 ) ((max - min + 1 ) * pg_erand48 (random_state -> xseed ));
786
820
}
787
821
788
822
/*
@@ -791,7 +825,8 @@ getrand(TState *thread, int64 min, int64 max)
791
825
* value is exp(-parameter).
792
826
*/
793
827
static int64
794
- getExponentialRand (TState * thread , int64 min , int64 max , double parameter )
828
+ getExponentialRand (RandomState * random_state , int64 min , int64 max ,
829
+ double parameter )
795
830
{
796
831
double cut ,
797
832
uniform ,
@@ -801,7 +836,7 @@ getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
801
836
Assert (parameter > 0.0 );
802
837
cut = exp (- parameter );
803
838
/* 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 );
805
840
806
841
/*
807
842
* 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)
814
849
815
850
/* random number generator: gaussian distribution from min to max inclusive */
816
851
static int64
817
- getGaussianRand (TState * thread , int64 min , int64 max , double parameter )
852
+ getGaussianRand (RandomState * random_state , int64 min , int64 max ,
853
+ double parameter )
818
854
{
819
855
double stdev ;
820
856
double rand ;
@@ -842,8 +878,8 @@ getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
842
878
* are expected in (0, 1] (see
843
879
* https://en.wikipedia.org/wiki/Box-Muller_transform)
844
880
*/
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 );
847
883
848
884
/* Box-Muller basic form transform */
849
885
double var_sqrt = sqrt (-2.0 * log (rand1 ));
@@ -873,7 +909,7 @@ getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
873
909
* not be one.
874
910
*/
875
911
static int64
876
- getPoissonRand (TState * thread , double center )
912
+ getPoissonRand (RandomState * random_state , double center )
877
913
{
878
914
/*
879
915
* Use inverse transform sampling to generate a value > 0, such that the
@@ -882,7 +918,7 @@ getPoissonRand(TState *thread, double center)
882
918
double uniform ;
883
919
884
920
/* 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 );
886
922
887
923
return (int64 ) (- log (uniform ) * center + 0.5 );
888
924
}
@@ -960,7 +996,7 @@ zipfFindOrCreateCacheCell(ZipfCache *cache, int64 n, double s)
960
996
* Luc Devroye, p. 550-551, Springer 1986.
961
997
*/
962
998
static int64
963
- computeIterativeZipfian (TState * thread , int64 n , double s )
999
+ computeIterativeZipfian (RandomState * random_state , int64 n , double s )
964
1000
{
965
1001
double b = pow (2.0 , s - 1.0 );
966
1002
double x ,
@@ -971,8 +1007,8 @@ computeIterativeZipfian(TState *thread, int64 n, double s)
971
1007
while (true)
972
1008
{
973
1009
/* 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 );
976
1012
977
1013
x = floor (pow (u , -1.0 / (s - 1.0 )));
978
1014
@@ -990,10 +1026,11 @@ computeIterativeZipfian(TState *thread, int64 n, double s)
990
1026
* Jim Gray et al, SIGMOD 1994
991
1027
*/
992
1028
static int64
993
- computeHarmonicZipfian (TState * thread , int64 n , double s )
1029
+ computeHarmonicZipfian (ZipfCache * zipf_cache , RandomState * random_state ,
1030
+ int64 n , double s )
994
1031
{
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 );
997
1034
double uz = uniform * cell -> harmonicn ;
998
1035
999
1036
if (uz < 1.0 )
@@ -1005,17 +1042,17 @@ computeHarmonicZipfian(TState *thread, int64 n, double s)
1005
1042
1006
1043
/* random number generator: zipfian distribution from min to max inclusive */
1007
1044
static 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 )
1009
1047
{
1010
1048
int64 n = max - min + 1 ;
1011
1049
1012
1050
/* abort if parameter is invalid */
1013
1051
Assert (s > 0.0 && s != 1.0 && s <= MAX_ZIPFIAN_PARAM );
1014
1052
1015
-
1016
1053
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 ));
1019
1056
}
1020
1057
1021
1058
/*
@@ -2310,7 +2347,7 @@ evalStandardFunc(TState *thread, CState *st,
2310
2347
if (func == PGBENCH_RANDOM )
2311
2348
{
2312
2349
Assert (nargs == 2 );
2313
- setIntValue (retval , getrand (thread , imin , imax ));
2350
+ setIntValue (retval , getrand (& st -> cs_func_rs , imin , imax ));
2314
2351
}
2315
2352
else /* gaussian & exponential */
2316
2353
{
@@ -2332,7 +2369,8 @@ evalStandardFunc(TState *thread, CState *st,
2332
2369
}
2333
2370
2334
2371
setIntValue (retval ,
2335
- getGaussianRand (thread , imin , imax , param ));
2372
+ getGaussianRand (& st -> cs_func_rs ,
2373
+ imin , imax , param ));
2336
2374
}
2337
2375
else if (func == PGBENCH_RANDOM_ZIPFIAN )
2338
2376
{
@@ -2344,7 +2382,9 @@ evalStandardFunc(TState *thread, CState *st,
2344
2382
return false;
2345
2383
}
2346
2384
setIntValue (retval ,
2347
- getZipfianRand (thread , imin , imax , param ));
2385
+ getZipfianRand (& thread -> zipf_cache ,
2386
+ & st -> cs_func_rs ,
2387
+ imin , imax , param ));
2348
2388
}
2349
2389
else /* exponential */
2350
2390
{
@@ -2357,7 +2397,8 @@ evalStandardFunc(TState *thread, CState *st,
2357
2397
}
2358
2398
2359
2399
setIntValue (retval ,
2360
- getExponentialRand (thread , imin , imax , param ));
2400
+ getExponentialRand (& st -> cs_func_rs ,
2401
+ imin , imax , param ));
2361
2402
}
2362
2403
}
2363
2404
@@ -2652,7 +2693,7 @@ chooseScript(TState *thread)
2652
2693
if (num_scripts == 1 )
2653
2694
return 0 ;
2654
2695
2655
- w = getrand (thread , 0 , total_weight - 1 );
2696
+ w = getrand (& thread -> ts_choose_rs , 0 , total_weight - 1 );
2656
2697
do
2657
2698
{
2658
2699
w -= sql_script [i ++ ].weight ;
@@ -2846,7 +2887,7 @@ doCustom(TState *thread, CState *st, StatsData *agg)
2846
2887
* away.
2847
2888
*/
2848
2889
Assert (throttle_delay > 0 );
2849
- wait = getPoissonRand (thread , throttle_delay );
2890
+ wait = getPoissonRand (& thread -> ts_throttle_rs , throttle_delay );
2850
2891
2851
2892
thread -> throttle_trigger += wait ;
2852
2893
st -> txn_scheduled = thread -> throttle_trigger ;
@@ -2880,7 +2921,8 @@ doCustom(TState *thread, CState *st, StatsData *agg)
2880
2921
{
2881
2922
processXactStats (thread , st , & now , true, agg );
2882
2923
/* next rendez-vous */
2883
- wait = getPoissonRand (thread , throttle_delay );
2924
+ wait = getPoissonRand (& thread -> ts_throttle_rs ,
2925
+ throttle_delay );
2884
2926
thread -> throttle_trigger += wait ;
2885
2927
st -> txn_scheduled = thread -> throttle_trigger ;
2886
2928
}
@@ -3423,7 +3465,7 @@ doLog(TState *thread, CState *st,
3423
3465
* to the random sample.
3424
3466
*/
3425
3467
if (sample_rate != 0.0 &&
3426
- pg_erand48 (thread -> random_state ) > sample_rate )
3468
+ pg_erand48 (thread -> ts_sample_rs . xseed ) > sample_rate )
3427
3469
return ;
3428
3470
3429
3471
/* should we aggregate the results or not? */
@@ -4851,7 +4893,6 @@ set_random_seed(const char *seed)
4851
4893
return true;
4852
4894
}
4853
4895
4854
-
4855
4896
int
4856
4897
main (int argc , char * * argv )
4857
4898
{
@@ -5465,6 +5506,7 @@ main(int argc, char **argv)
5465
5506
for (i = 0 ; i < nclients ; i ++ )
5466
5507
{
5467
5508
state [i ].cstack = conditional_stack_create ();
5509
+ initRandomState (& state [i ].cs_func_rs );
5468
5510
}
5469
5511
5470
5512
if (debug )
@@ -5598,9 +5640,9 @@ main(int argc, char **argv)
5598
5640
thread -> state = & state [nclients_dealt ];
5599
5641
thread -> nstate =
5600
5642
(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 );
5604
5646
thread -> logfile = NULL ; /* filled in later */
5605
5647
thread -> latency_late = 0 ;
5606
5648
thread -> zipf_cache .nb_cells = 0 ;
0 commit comments