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

Commit4af43ee

Browse files
committed
Make pgbench use erand48() rather than random().
glibc renders random() thread-safe by wrapping a futex lock around it;testing reveals that this limits the performance of pgbench on machineswith many CPU cores. Rather than switching to random_r(), which isonly available on GNU systems and crashes unless you use undocumentedalchemy to initialize the random state properly, switch to our built-inimplementation of erand48(), which is both thread-safe and concurrent.Since the list of reasons not to use the operating system's erand48()is getting rather long, rename ours to pg_erand48() (and similarlyfor our implementations of lrand48() and srand48()) and just alwaysuse those. We were already doing this on Cygwin anyway, and theglibc implementation is not quite thread-safe, so pgbench wouldn'tbe able to use that either.Per discussion with Tom Lane.
1 parentac36e6f commit4af43ee

File tree

12 files changed

+40
-62
lines changed

12 files changed

+40
-62
lines changed

‎configure

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20493,8 +20493,7 @@ LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
2049320493

2049420494

2049520495

20496-
20497-
for ac_func in crypt erand48 getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
20496+
for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
2049820497
do
2049920498
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
2050020499
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -21010,17 +21009,6 @@ esac
2101021009

2101121010
fi
2101221011

21013-
# Cygwin's erand48() is broken (always returns zero) in some releases,
21014-
# so force use of ours.
21015-
if test "$PORTNAME" = "cygwin"; then
21016-
case " $LIBOBJS " in
21017-
*" erand48.$ac_objext "* ) ;;
21018-
*) LIBOBJS="$LIBOBJS erand48.$ac_objext"
21019-
;;
21020-
esac
21021-
21022-
fi
21023-
2102421012
# Win32 support
2102521013
if test "$PORTNAME" = "win32"; then
2102621014

‎configure.in

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,7 @@ fi
13111311
pgac_save_LIBS="$LIBS"
13121312
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
13131313

1314-
AC_REPLACE_FUNCS([crypterand48getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul])
1314+
AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul])
13151315

13161316
case $host_os in
13171317

@@ -1362,12 +1362,6 @@ if test "$PORTNAME" = "win32"; then
13621362
AC_LIBOBJ(getopt_long)
13631363
fi
13641364

1365-
# Cygwin's erand48() is broken (always returns zero) in some releases,
1366-
# so force use of ours.
1367-
if test "$PORTNAME" = "cygwin"; then
1368-
AC_LIBOBJ(erand48)
1369-
fi
1370-
13711365
# Win32 support
13721366
if test "$PORTNAME" = "win32"; then
13731367
AC_REPLACE_FUNCS(gettimeofday)

‎contrib/pgbench/pgbench.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ typedef struct
198198
instr_timestart_time;/* thread start time */
199199
instr_time*exec_elapsed;/* time spent executing cmds (per Command) */
200200
int*exec_count;/* number of cmd executions (per Command) */
201+
unsigned shortrandom_state[3];/* separate randomness for each thread */
201202
}TState;
202203

203204
#defineINVALID_THREAD((pthread_t) 0)
@@ -380,13 +381,18 @@ usage(const char *progname)
380381

381382
/* random number generator: uniform distribution from min to max inclusive */
382383
staticint
383-
getrand(intmin,intmax)
384+
getrand(TState*thread,intmin,intmax)
384385
{
385386
/*
386387
* Odd coding is so that min and max have approximately the same chance of
387388
* being selected as do numbers between them.
389+
*
390+
* pg_erand48() is thread-safe and concurrent, which is why we use it
391+
* rather than random(), which in glibc is non-reentrant, and therefore
392+
* protected by a mutex, and therefore a bottleneck on machines with many
393+
* CPUs.
388394
*/
389-
returnmin+ (int) (((max-min+1)*(double)random()) / (MAX_RANDOM_VALUE+1.0));
395+
returnmin+ (int) ((max-min+1)*pg_erand48(thread->random_state));
390396
}
391397

392398
/* call PQexec() and exit() on failure */
@@ -901,7 +907,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
901907
if (commands[st->state]==NULL)
902908
{
903909
st->state=0;
904-
st->use_file=getrand(0,num_files-1);
910+
st->use_file=getrand(thread,0,num_files-1);
905911
commands=sql_files[st->use_file];
906912
}
907913
}
@@ -1068,9 +1074,9 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
10681074
}
10691075

10701076
#ifdefDEBUG
1071-
printf("min: %d max: %d random: %d\n",min,max,getrand(min,max));
1077+
printf("min: %d max: %d random: %d\n",min,max,getrand(thread,min,max));
10721078
#endif
1073-
snprintf(res,sizeof(res),"%d",getrand(min,max));
1079+
snprintf(res,sizeof(res),"%d",getrand(thread,min,max));
10741080

10751081
if (!putVariable(st,argv[0],argv[1],res))
10761082
{
@@ -2242,6 +2248,9 @@ main(int argc, char **argv)
22422248
thread->tid=i;
22432249
thread->state=&state[nclients /nthreads*i];
22442250
thread->nstate=nclients /nthreads;
2251+
thread->random_state[0]=random();
2252+
thread->random_state[1]=random();
2253+
thread->random_state[2]=random();
22452254

22462255
if (is_latencies)
22472256
{
@@ -2384,7 +2393,7 @@ threadRun(void *arg)
23842393
Command**commands=sql_files[st->use_file];
23852394
intprev_ecnt=st->ecnt;
23862395

2387-
st->use_file=getrand(0,num_files-1);
2396+
st->use_file=getrand(thread,0,num_files-1);
23882397
if (!doCustom(thread,st,&result->conn_time,logfile))
23892398
remains--;/* I've aborted */
23902399

@@ -2583,17 +2592,6 @@ pthread_create(pthread_t *thread,
25832592
if (duration>0)
25842593
setalarm(duration);
25852594

2586-
/*
2587-
* Set a different random seed in each child process. Otherwise they all
2588-
* inherit the parent's state and generate the same "random" sequence. (In
2589-
* the threaded case, the different threads will obtain subsets of the
2590-
* output of a single random() sequence, which should be okay for our
2591-
* purposes.)
2592-
*/
2593-
INSTR_TIME_SET_CURRENT(start_time);
2594-
srandom(((unsignedint)INSTR_TIME_GET_MICROSEC(start_time))+
2595-
((unsignedint)getpid()));
2596-
25972595
ret=start_routine(arg);
25982596
write(th->pipes[1],ret,sizeof(TResult));
25992597
close(th->pipes[1]);

‎src/backend/optimizer/geqo/geqo_random.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ geqo_rand(PlannerInfo *root)
3636
{
3737
GeqoPrivateData*private= (GeqoPrivateData*)root->join_search_private;
3838

39-
returnerand48(private->random_state);
39+
returnpg_erand48(private->random_state);
4040
}

‎src/backend/optimizer/geqo/geqo_selection.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
6464
* Ensure we have selected different genes, except if pool size is only
6565
* one, when we can't.
6666
*
67-
* This codehas been observed to hang up in an infinite loop when the
68-
* platform's implementation of erand48()is broken. Weconsider that a
69-
*feature: it lets you know you'd better fix the random-number generator.
67+
* This codewas observed to hang up in an infinite loop when the
68+
* platform's implementation of erand48()was broken. Wenow always
69+
*use our own version.
7070
*/
7171
if (pool->size>1)
7272
{

‎src/include/optimizer/geqo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ extern double Geqo_seed;/* 0 .. 1 */
7373
typedefstruct
7474
{
7575
List*initial_rels;/* the base relations we are joining */
76-
unsigned shortrandom_state[3];/* state forerand48() */
76+
unsigned shortrandom_state[3];/* state forpg_erand48() */
7777
}GeqoPrivateData;
7878

7979

‎src/include/pg_config.h.in

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,6 @@
149149
/* Define to 1 if you have the <editline/readline.h> header file. */
150150
#undef HAVE_EDITLINE_READLINE_H
151151

152-
/* Define to 1 if you have the `erand48' function. */
153-
#undef HAVE_ERAND48
154-
155152
/* Define to 1 if you have the `ERR_set_mark' function. */
156153
#undef HAVE_ERR_SET_MARK
157154

‎src/include/port.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,9 @@ extern off_t ftello(FILE *stream);
380380
#endif
381381
#endif
382382

383-
#ifndefHAVE_ERAND48
384-
/* we assume all of these are present or missing together */
385-
externdoubleerand48(unsigned shortxseed[3]);
386-
externlonglrand48(void);
387-
externvoidsrand48(longseed);
388-
#endif
383+
externdoublepg_erand48(unsigned shortxseed[3]);
384+
externlongpg_lrand48(void);
385+
externvoidpg_srand48(longseed);
389386

390387
#ifndefHAVE_FSEEKO
391388
#definefseeko(a,b,c) fseek(a, b, c)

‎src/port/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ include $(top_builddir)/src/Makefile.global
3030
overrideCPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND$(CPPFLAGS)
3131
LIBS +=$(PTHREAD_LIBS)
3232

33-
OBJS =$(LIBOBJS) chklocale.o dirmod.oexec.oinet_net_ntop.onoblock.o\
34-
path.o pgcheckdir.o pgmkdirp.o pgsleep.o pgstrcasecmp.o\
33+
OBJS =$(LIBOBJS) chklocale.o dirmod.oerand48.oexec.oinet_net_ntop.o\
34+
noblock.opath.o pgcheckdir.o pgmkdirp.o pgsleep.o pgstrcasecmp.o\
3535
qsort.o qsort_arg.o sprompt.o thread.o
3636

3737
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND

‎src/port/erand48.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
*
33
* erand48.c
44
*
5-
* This file supplies versions of erand48(), lrand48(), and srand48()
6-
* for machines that lack them. (These are all the members of the drand48
7-
* family that Postgres currently requires. We name the file after erand48
8-
* because that is the one that configure tests for.)
5+
* This file supplies pg_erand48(), pg_lrand48(), and pg_srand48(), which
6+
* are just like erand48(), lrand48(), and srand48() except that we use
7+
* our own implementation rather than the one provided by the operating
8+
* system. We used to test for an operating system version rather than
9+
* unconditionally using our own, but (1) some versions of Cygwin have a
10+
* buggy erand48() that always returns zero and (2) as of 2011, glibc's
11+
* erand48() is strangely coded to be almost-but-not-quite thread-safe,
12+
* which doesn't matter for the backend but is important for pgbench.
913
*
1014
*
1115
* Copyright (c) 1993 Martin Birgmeier
@@ -72,7 +76,7 @@ _dorand48(unsigned short xseed[3])
7276

7377

7478
double
75-
erand48(unsigned shortxseed[3])
79+
pg_erand48(unsigned shortxseed[3])
7680
{
7781
_dorand48(xseed);
7882
returnldexp((double)xseed[0],-48)+
@@ -81,14 +85,14 @@ erand48(unsigned short xseed[3])
8185
}
8286

8387
long
84-
lrand48(void)
88+
pg_lrand48(void)
8589
{
8690
_dorand48(_rand48_seed);
8791
return ((long)_rand48_seed[2] <<15)+ ((long)_rand48_seed[1] >>1);
8892
}
8993

9094
void
91-
srand48(longseed)
95+
pg_srand48(longseed)
9296
{
9397
_rand48_seed[0]=RAND48_SEED_0;
9498
_rand48_seed[1]= (unsigned short)seed;

‎src/port/random.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
long
2222
random()
2323
{
24-
returnlrand48();
24+
returnpg_lrand48();
2525
}

‎src/port/srandom.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
void
2222
srandom(unsignedintseed)
2323
{
24-
srand48((longint)seed);
24+
pg_srand48((longint)seed);
2525
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp