Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4092319

Browse files
committed
pgbench: introduce a RandomState struct
This becomes useful when used to retry a transaction after aserialization error or deadlock abort. (We don't yet have that feature,but this is preparation for it.)While at it, use separate random state for thread administratrivia suchas deciding which script to run, how long to delay for throttling, orwhether to log a message when sampling; this not only makes these tasksindependent of each other, but makes the actual thread rundeterministic.Author: Marina PolyakovaReviewed-by: Fabien CoelhoDiscussion:https://postgr.es/m/72a0d590d6ba06f242d75c2e641820ec@postgrespro.ru
1 parenta7aa608 commit4092319

File tree

1 file changed

+74
-32
lines changed

1 file changed

+74
-32
lines changed

‎src/bin/pgbench/pgbench.c

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ typedef struct StatsData
279279
SimpleStatslag;
280280
}StatsData;
281281

282+
/*
283+
* Struct to keep random state.
284+
*/
285+
typedefstructRandomState
286+
{
287+
unsigned shortxseed[3];
288+
}RandomState;
289+
282290
/*
283291
* Connection state machine states.
284292
*/
@@ -360,6 +368,12 @@ typedef struct
360368
ConnectionStateEnumstate;/* state machine's current state. */
361369
ConditionalStackcstack;/* 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+
RandomStatecs_func_rs;
376+
363377
intuse_file;/* index in sql_script for this client */
364378
intcommand;/* command number in script */
365379

@@ -419,7 +433,16 @@ typedef struct
419433
pthread_tthread;/* thread handle */
420434
CState*state;/* array of CState */
421435
intnstate;/* length of state[] */
422-
unsigned shortrandom_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+
RandomStatets_choose_rs;/* random state for selecting a script */
443+
RandomStatets_throttle_rs;/* random state for transaction throttling */
444+
RandomStatets_sample_rs;/* random state for log sampling */
445+
423446
int64throttle_trigger;/* previous/next throttling (us) */
424447
FILE*logfile;/* where to log, or NULL */
425448
ZipfCachezipf_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+
staticvoid
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 */
773807
staticint64
774-
getrand(TState*thread,int64min,int64max)
808+
getrand(RandomState*random_state,int64min,int64max)
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-
returnmin+ (int64) ((max-min+1)*pg_erand48(thread->random_state));
819+
returnmin+ (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
*/
793827
staticint64
794-
getExponentialRand(TState*thread,int64min,int64max,doubleparameter)
828+
getExponentialRand(RandomState*random_state,int64min,int64max,
829+
doubleparameter)
795830
{
796831
doublecut,
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 */
816851
staticint64
817-
getGaussianRand(TState*thread,int64min,int64max,doubleparameter)
852+
getGaussianRand(RandomState*random_state,int64min,int64max,
853+
doubleparameter)
818854
{
819855
doublestdev;
820856
doublerand;
@@ -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-
doublerand1=1.0-pg_erand48(thread->random_state);
846-
doublerand2=1.0-pg_erand48(thread->random_state);
881+
doublerand1=1.0-pg_erand48(random_state->xseed);
882+
doublerand2=1.0-pg_erand48(random_state->xseed);
847883

848884
/* Box-Muller basic form transform */
849885
doublevar_sqrt=sqrt(-2.0*log(rand1));
@@ -873,7 +909,7 @@ getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
873909
* not be one.
874910
*/
875911
staticint64
876-
getPoissonRand(TState*thread,doublecenter)
912+
getPoissonRand(RandomState*random_state,doublecenter)
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
doubleuniform;
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
*/
962998
staticint64
963-
computeIterativeZipfian(TState*thread,int64n,doubles)
999+
computeIterativeZipfian(RandomState*random_state,int64n,doubles)
9641000
{
9651001
doubleb=pow(2.0,s-1.0);
9661002
doublex,
@@ -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
*/
9921028
staticint64
993-
computeHarmonicZipfian(TState*thread,int64n,doubles)
1029+
computeHarmonicZipfian(ZipfCache*zipf_cache,RandomState*random_state,
1030+
int64n,doubles)
9941031
{
995-
ZipfCell*cell=zipfFindOrCreateCacheCell(&thread->zipf_cache,n,s);
996-
doubleuniform=pg_erand48(thread->random_state);
1032+
ZipfCell*cell=zipfFindOrCreateCacheCell(zipf_cache,n,s);
1033+
doubleuniform=pg_erand48(random_state->xseed);
9971034
doubleuz=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 */
10071044
staticint64
1008-
getZipfianRand(TState*thread,int64min,int64max,doubles)
1045+
getZipfianRand(ZipfCache*zipf_cache,RandomState*random_state,int64min,
1046+
int64max,doubles)
10091047
{
10101048
int64n=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
returnmin-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
elseif (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
return0;
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-
48554896
int
48564897
main(intargc,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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp