]> granicus.if.org Git - postgresql/commitdiff
pgbench: Elaborate latency reporting.
authorNoah Misch <noah@leadboat.com>
Sat, 5 Oct 2013 21:33:38 +0000 (17:33 -0400)
committerNoah Misch <noah@leadboat.com>
Sat, 5 Oct 2013 21:33:38 +0000 (17:33 -0400)
Isolate transaction latency (elapsed time between submitting first
command and receiving response to last command) from client-side delays
pertaining to the --rate schedule.  Under --rate, report schedule lag as
defined in the documentation.  Report latency standard deviation
whenever we collect the measurements to do so.  All of these changes
affect --progress messages and the final report.

Fabien COELHO, reviewed by Pavel Stehule.

contrib/pgbench/pgbench.c
doc/src/sgml/pgbench.sgml

index a3b37e9bdc126a6294e2d29da58851eda75ae1df..926246e67bacdbd498dee9bb295085e318178154 100644 (file)
@@ -172,6 +172,7 @@ int                 agg_interval;           /* log aggregates instead of individual
                                                                 * transactions */
 int                    progress = 0;       /* thread progress report every this seconds */
 int         progress_nclients = 0; /* number of clients for progress report */
+int                    progress_nthreads = 0; /* number of threads for progress report */
 bool           is_connect;                     /* establish connection for each transaction */
 bool           is_latencies;           /* report per-command latencies */
 int                    main_pid;                       /* main process id used in log filename */
@@ -214,6 +215,8 @@ typedef struct
        int                     nvariables;
        instr_time      txn_begin;              /* used for measuring transaction latencies */
        instr_time      stmt_begin;             /* used for measuring statement latencies */
+       int64           txn_latencies;  /* cumulated latencies */
+       int64           txn_sqlats;             /* cumulated square latencies */
        bool            is_throttled;   /* whether transaction throttling is done */
        int                     use_file;               /* index in sql_files for this client */
        bool            prepared[MAX_FILES];
@@ -243,6 +246,8 @@ typedef struct
 {
        instr_time      conn_time;
        int                     xacts;
+       int64           latencies;
+       int64           sqlats;
        int64       throttle_lag;
        int64       throttle_lag_max;
 } TResult;
@@ -1006,6 +1011,26 @@ top:
                        thread->exec_count[cnum]++;
                }
 
+               /* transaction finished: record latency under progress or throttling */
+               if ((progress || throttle_delay) && commands[st->state + 1] == NULL)
+               {
+                       instr_time      diff;
+                       int64           latency;
+
+                       INSTR_TIME_SET_CURRENT(diff);
+                       INSTR_TIME_SUBTRACT(diff, st->txn_begin);
+                       latency = INSTR_TIME_GET_MICROSEC(diff);
+                       st->txn_latencies += latency;
+                       /*
+                        * XXX In a long benchmark run of high-latency transactions, this
+                        * int64 addition eventually overflows.  For example, 100 threads
+                        * running 10s transactions will overflow it in 2.56 hours.  With
+                        * a more-typical OLTP workload of .1s transactions, overflow
+                        * would take 256 hours.
+                        */
+                       st->txn_sqlats += latency * latency;
+               }
+
                /*
                 * if transaction finished, record the time it took in the log
                 */
@@ -1195,8 +1220,8 @@ top:
                goto top;
        }
 
-       /* Record transaction start time if logging is enabled */
-       if (logfile && st->state == 0)
+       /* Record transaction start time under logging, progress or throttling */
+       if ((logfile || progress || throttle_delay) && st->state == 0)
                INSTR_TIME_SET_CURRENT(st->txn_begin);
 
        /* Record statement start time if per-command latencies are requested */
@@ -2105,6 +2130,7 @@ static void
 printResults(int ttype, int normal_xacts, int nclients,
                         TState *threads, int nthreads,
                         instr_time total_time, instr_time conn_total_time,
+                        int64 total_latencies, int64 total_sqlats,
                         int64 throttle_lag, int64 throttle_lag_max)
 {
        double          time_include,
@@ -2144,6 +2170,22 @@ printResults(int ttype, int normal_xacts, int nclients,
                           normal_xacts);
        }
 
+       if (throttle_delay || progress)
+       {
+               /* compute and show latency average and standard deviation */
+               double latency = 0.001 * total_latencies / normal_xacts;
+               double sqlat = (double) total_sqlats / normal_xacts;
+               printf("latency average: %.3f ms\n"
+                          "latency stddev: %.3f ms\n",
+                          latency, 0.001 * sqrt(sqlat - 1000000.0 * latency * latency));
+       }
+       else
+       {
+               /* only an average latency computed from the duration is available */
+               printf("latency average: %.3f ms\n",
+                          1000.0 * duration * nclients / normal_xacts);
+       }
+
        if (throttle_delay)
        {
                /*
@@ -2152,7 +2194,7 @@ printResults(int ttype, int normal_xacts, int nclients,
                 * transaction.  The measured lag may be caused by thread/client load,
                 * the database load, or the Poisson throttling process.
                 */
-               printf("average rate limit schedule lag: %.3f ms (max %.3f ms)\n",
+               printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
                           0.001 * throttle_lag / normal_xacts, 0.001 * throttle_lag_max);
        }
 
@@ -2263,7 +2305,9 @@ main(int argc, char **argv)
        instr_time      start_time;             /* start up time */
        instr_time      total_time;
        instr_time      conn_total_time;
-       int                     total_xacts;
+       int                     total_xacts = 0;
+       int64           total_latencies = 0;
+       int64           total_sqlats = 0;
        int64       throttle_lag = 0;
        int64       throttle_lag_max = 0;
 
@@ -2617,6 +2661,7 @@ main(int argc, char **argv)
         */
        main_pid = (int) getpid();
        progress_nclients = nclients;
+       progress_nthreads = nthreads;
 
        if (nclients > 1)
        {
@@ -2825,7 +2870,6 @@ main(int argc, char **argv)
        }
 
        /* wait for threads and accumulate results */
-       total_xacts = 0;
        INSTR_TIME_SET_ZERO(conn_total_time);
        for (i = 0; i < nthreads; i++)
        {
@@ -2841,6 +2885,8 @@ main(int argc, char **argv)
                        TResult    *r = (TResult *) ret;
 
                        total_xacts += r->xacts;
+                       total_latencies += r->latencies;
+                       total_sqlats += r->sqlats;
                        throttle_lag += r->throttle_lag;
                        if (r->throttle_lag_max > throttle_lag_max)
                                throttle_lag_max = r->throttle_lag_max;
@@ -2854,7 +2900,8 @@ main(int argc, char **argv)
        INSTR_TIME_SET_CURRENT(total_time);
        INSTR_TIME_SUBTRACT(total_time, start_time);
        printResults(ttype, total_xacts, nclients, threads, nthreads,
-                                total_time, conn_total_time, throttle_lag, throttle_lag_max);
+                                total_time, conn_total_time, total_latencies, total_sqlats,
+                                throttle_lag, throttle_lag_max);
 
        return 0;
 }
@@ -2875,7 +2922,7 @@ threadRun(void *arg)
        int64       thread_start = INSTR_TIME_GET_MICROSEC(thread->start_time);
        int64           last_report = thread_start;
        int64           next_report = last_report + progress * 1000000;
-       int64           last_count = 0;
+       int64           last_count = 0, last_lats = 0, last_sqlats = 0, last_lags = 0;
 
        AggVals         aggs;
 
@@ -3075,21 +3122,40 @@ threadRun(void *arg)
                        if (now >= next_report)
                        {
                                /* generate and show report */
-                               int64 count = 0;
+                               int64 count = 0, lats = 0, sqlats = 0;
+                               int64 lags = thread->throttle_lag;
                                int64 run = now - last_report;
-                               double tps, total_run, latency;
+                               double tps, total_run, latency, sqlat, stdev, lag;
 
                                for (i = 0 ; i < nstate ; i++)
+                               {
                                        count += state[i].cnt;
+                                       lats += state[i].txn_latencies;
+                                       sqlats += state[i].txn_sqlats;
+                               }
 
                                total_run = (now - thread_start) / 1000000.0;
                                tps = 1000000.0 * (count - last_count) / run;
-                               latency = 1000.0 * nstate / tps;
+                               latency = 0.001 * (lats - last_lats) / (count - last_count);
+                               sqlat = 1.0 * (sqlats - last_sqlats) / (count - last_count);
+                               stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
+                               lag = 0.001 * (lags - last_lags) / (count - last_count);
 
-                               fprintf(stderr, "progress %d: %.1f s, %.1f tps, %.3f ms lat\n",
-                                               thread->tid, total_run, tps, latency);
+                               if (throttle_delay)
+                                       fprintf(stderr,
+                                                       "progress %d: %.1f s, %.1f tps, "
+                                                       "lat %.3f ms stddev %.3f, lag %.3f ms\n",
+                                                       thread->tid, total_run, tps, latency, stdev, lag);
+                               else
+                                       fprintf(stderr,
+                                                       "progress %d: %.1f s, %.1f tps, "
+                                                       "lat %.3f ms stddev %.3f\n",
+                                                       thread->tid, total_run, tps, latency, stdev);
 
                                last_count = count;
+                               last_lats = lats;
+                               last_sqlats = sqlats;
+                               last_lags = lags;
                                last_report = now;
                                next_report += progress * 1000000;
                        }
@@ -3105,21 +3171,42 @@ threadRun(void *arg)
                        if (now >= next_report)
                        {
                                /* generate and show report */
-                               int64 count = 0;
+                               int64 count = 0, lats = 0, sqlats = 0, lags = 0;
                                int64 run = now - last_report;
-                               double tps, total_run, latency;
+                               double tps, total_run, latency, sqlat, lag, stdev;
 
                                for (i = 0 ; i < progress_nclients ; i++)
+                               {
                                        count += state[i].cnt;
+                                       lats   += state[i].txn_latencies;
+                                       sqlats += state[i].txn_sqlats;
+                               }
+
+                               for (i = 0 ; i < progress_nthreads ; i++)
+                                       lags += thread[i].throttle_lag;
 
                                total_run = (now - thread_start) / 1000000.0;
                                tps = 1000000.0 * (count - last_count) / run;
-                               latency = 1000.0 * progress_nclients / tps;
+                               latency = 0.001 * (lats - last_lats) / (count - last_count);
+                               sqlat = 1.0 * (sqlats - last_sqlats) / (count - last_count);
+                               stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
+                               lag = 0.001 * (lags - last_lags) / (count - last_count);
 
-                               fprintf(stderr, "progress: %.1f s, %.1f tps, %.3f ms lat\n",
-                                               total_run, tps, latency);
+                               if (throttle_delay)
+                                       fprintf(stderr,
+                                                       "progress: %.1f s, %.1f tps, "
+                                                       "lat %.3f ms stddev %.3f, lag %.3f ms\n",
+                                                       total_run, tps, latency, stdev, lag);
+                               else
+                                       fprintf(stderr,
+                                                       "progress: %.1f s, %.1f tps, "
+                                                       "lat %.3f ms stddev %.3f\n",
+                                                       total_run, tps, latency, stdev);
 
                                last_count = count;
+                               last_lats = lats;
+                               last_sqlats = sqlats;
+                               last_lags = lags;
                                last_report = now;
                                next_report += progress * 1000000;
                        }
@@ -3131,8 +3218,14 @@ done:
        INSTR_TIME_SET_CURRENT(start);
        disconnect_all(state, nstate);
        result->xacts = 0;
+       result->latencies = 0;
+       result->sqlats = 0;
        for (i = 0; i < nstate; i++)
+       {
                result->xacts += state[i].cnt;
+               result->latencies += state[i].txn_latencies;
+               result->sqlats += state[i].txn_sqlats;
+       }
        result->throttle_lag = thread->throttle_lag;
        result->throttle_lag_max = thread->throttle_lag_max;
        INSTR_TIME_SET_CURRENT(end);
index 5871b459e72eb0cdbbc46f43670342a91a8d24f0..8e1a05dde8a0174c2d975a2606f471e319b5e48e 100644 (file)
@@ -412,7 +412,11 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
       <term><option>--progress=</option><replaceable>sec</></term>
       <listitem>
        <para>
-        Show progress report every <literal>sec</> seconds.
+        Show progress report every <literal>sec</> seconds.  The report
+        includes the time since the beginning of the run, the tps since the
+        last report, and the transaction latency average and standard
+        deviation since the last report.  Under throttling (<option>-R</>), it
+        also includes the average schedule lag time since the last report.
        </para>
       </listitem>
      </varlistentry>