]> granicus.if.org Git - postgresql/commitdiff
Simplify calculation of Poisson distributed delays in pgbench --rate mode.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 11 Sep 2014 10:00:48 +0000 (13:00 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 11 Sep 2014 10:12:43 +0000 (13:12 +0300)
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.

contrib/pgbench/pgbench.c

index e4b75b266e6a8120cbe556210f21cfc2712429e4..d7fdfd9e0271ad7ac4f959d4189e13e0f0306043 100644 (file)
@@ -476,6 +476,25 @@ getrand(TState *thread, int64 min, int64 max)
        return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
 }
 
+/*
+ * random number generator: generate a value, such that the series of values
+ * will approximate a Poisson distribution centered on the given value.
+ */
+static int64
+getPoissonRand(TState *thread, int64 center)
+{
+       /*
+        * Use inverse transform sampling to generate a value > 0, such that the
+        * expected (i.e. average) value is the given argument.
+        */
+       double uniform;
+
+       /* erand in [0, 1), uniform in (0, 1] */
+       uniform = 1.0 - pg_erand48(thread->random_state);
+
+       return (int64) (-log(uniform) * ((double) center) + 0.5);
+}
+
 /* call PQexec() and exit() on failure */
 static void
 executeStatement(PGconn *con, const char *sql)
@@ -933,21 +952,13 @@ top:
        if (throttle_delay && !st->is_throttled)
        {
                /*
-                * Use inverse transform sampling to randomly generate a delay, such
-                * that the series of delays will approximate a Poisson distribution
-                * centered on the throttle_delay time.
-                *
-                * 10000 implies a 9.2 (-log(1/10000)) to 0.0 (log 1) delay
-                * multiplier, and results in a 0.055 % target underestimation bias:
-                *
-                * SELECT 1.0/AVG(-LN(i/10000.0)) FROM generate_series(1,10000) AS i;
-                * = 1.000552717032611116335474
+                * Generate a delay such that the series of delays will approximate a
+                * Poisson distribution centered on the throttle_delay time.
                 *
                 * If transactions are too slow or a given wait is shorter than a
                 * transaction, the next transaction will start right away.
                 */
-               int64           wait = (int64) (throttle_delay *
-                                 1.00055271703 * -log(getrand(thread, 1, 10000) / 10000.0));
+               int64           wait = getPoissonRand(thread, throttle_delay);
 
                thread->throttle_trigger += wait;