Skip to content

Commit c8b2499

Browse files
committed
Simplify calculation of Poisson distributed delays in pgbench --rate mode.
The previous coding first generated a uniform random value between 0.0 and 1.0, then converted that to an integer between 1 and 10000, and divided that again by 10000. Those conversions are unnecessary; we can use the double value that pg_erand48() returns directly. While we're at it, put the logic into a helper function, getPoissonRand(). The largest delay generated by the old coding was about 9.2 times the average, because of the way the uniformly distributed value used for the calculation was truncated to 1/10000 granularity. The new coding doesn't have such clamping. With my laptop's DBL_MIN value, the maximum delay with the new coding is about 700x the average. That seems acceptable - any reasonable pgbench session should last long enough to average that out. Backpatch to 9.4.
1 parent 8c9dd69 commit c8b2499

File tree

1 file changed

+22
-11
lines changed

1 file changed

+22
-11
lines changed

contrib/pgbench/pgbench.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,25 @@ getrand(TState *thread, int64 min, int64 max)
476476
return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
477477
}
478478

479+
/*
480+
* random number generator: generate a value, such that the series of values
481+
* will approximate a Poisson distribution centered on the given value.
482+
*/
483+
static int64
484+
getPoissonRand(TState *thread, int64 center)
485+
{
486+
/*
487+
* Use inverse transform sampling to generate a value > 0, such that the
488+
* expected (i.e. average) value is the given argument.
489+
*/
490+
double uniform;
491+
492+
/* erand in [0, 1), uniform in (0, 1] */
493+
uniform = 1.0 - pg_erand48(thread->random_state);
494+
495+
return (int64) (-log(uniform) * ((double) center) + 0.5);
496+
}
497+
479498
/* call PQexec() and exit() on failure */
480499
static void
481500
executeStatement(PGconn *con, const char *sql)
@@ -933,21 +952,13 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
933952
if (throttle_delay && !st->is_throttled)
934953
{
935954
/*
936-
* Use inverse transform sampling to randomly generate a delay, such
937-
* that the series of delays will approximate a Poisson distribution
938-
* centered on the throttle_delay time.
939-
*
940-
* 10000 implies a 9.2 (-log(1/10000)) to 0.0 (log 1) delay
941-
* multiplier, and results in a 0.055 % target underestimation bias:
942-
*
943-
* SELECT 1.0/AVG(-LN(i/10000.0)) FROM generate_series(1,10000) AS i;
944-
* = 1.000552717032611116335474
955+
* Generate a delay such that the series of delays will approximate a
956+
* Poisson distribution centered on the throttle_delay time.
945957
*
946958
* If transactions are too slow or a given wait is shorter than a
947959
* transaction, the next transaction will start right away.
948960
*/
949-
int64 wait = (int64) (throttle_delay *
950-
1.00055271703 * -log(getrand(thread, 1, 10000) / 10000.0));
961+
int64 wait = getPoissonRand(thread, throttle_delay);
951962

952963
thread->throttle_trigger += wait;
953964

0 commit comments

Comments
 (0)