Refactor pgbench log-writing code to a separate function.
authorHeikki Linnakangas <[email protected]>
Thu, 2 Oct 2014 09:58:14 +0000 (12:58 +0300)
committerHeikki Linnakangas <[email protected]>
Thu, 2 Oct 2014 11:01:19 +0000 (14:01 +0300)
The doCustom function was incredibly long, this makes it a little bit more
readable.

contrib/pgbench/pgbench.c

index 087e0d37fb62f09b16a2881dc8484c72ac08184d..c14a577ca0647923d829ba07bd86d0051b6fcffb 100644 (file)
@@ -347,6 +347,9 @@ static char *select_only = {
 static void setalarm(int seconds);
 static void *threadRun(void *arg);
 
+static void doLog(TState *thread, CState *st, FILE *logfile, instr_time *now,
+         AggVals *agg);
+
 static void
 usage(void)
 {
@@ -1016,6 +1019,16 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
        PGresult   *res;
        Command   **commands;
        bool            trans_needs_throttle = false;
+       instr_time      now;
+
+       /*
+        * gettimeofday() isn't free, so we get the current timestamp lazily the
+        * first time it's needed, and reuse the same value throughout this
+        * function after that. This also ensures that e.g. the calculated latency
+        * reported in the log file and in the totals are the same. Zero means
+        * "not set yet".
+        */
+       INSTR_TIME_SET_ZERO(now);
 
 top:
        commands = sql_files[st->use_file];
@@ -1049,10 +1062,10 @@ top:
 
        if (st->sleeping)
        {                                                       /* are we sleeping? */
-               instr_time      now;
                int64           now_us;
 
-               INSTR_TIME_SET_CURRENT(now);
+               if (INSTR_TIME_IS_ZERO(now))
+                       INSTR_TIME_SET_CURRENT(now);
                now_us = INSTR_TIME_GET_MICROSEC(now);
                if (st->txn_scheduled <= now_us)
                {
@@ -1074,11 +1087,6 @@ top:
 
        if (st->listen)
        {                                                       /* are we receiver? */
-               instr_time      now;
-               bool            now_valid = false;
-
-               INSTR_TIME_SET_ZERO(now); /* initialize to keep compiler quiet */
-
                if (commands[st->state]->type == SQL_COMMAND)
                {
                        if (debug)
@@ -1100,181 +1108,40 @@ top:
                {
                        int                     cnum = commands[st->state]->command_num;
 
-                       if (!now_valid)
-                       {
+                       if (INSTR_TIME_IS_ZERO(now))
                                INSTR_TIME_SET_CURRENT(now);
-                               now_valid = true;
-                       }
                        INSTR_TIME_ACCUM_DIFF(thread->exec_elapsed[cnum],
                                                                  now, st->stmt_begin);
                        thread->exec_count[cnum]++;
                }
 
-               /* transaction finished: record latency under progress or throttling */
-               if ((progress || throttle_delay) && commands[st->state + 1] == NULL)
+               /* transaction finished: calculate latency and log the transaction */
+               if (commands[st->state + 1] == NULL)
                {
-                       int64           latency;
-
-                       if (!now_valid)
+                       /* only calculate latency if an option is used that needs it */
+                       if (progress || throttle_delay)
                        {
-                               INSTR_TIME_SET_CURRENT(now);
-                               now_valid = true;
-                       }
-
-                       latency = INSTR_TIME_GET_MICROSEC(now) - st->txn_scheduled;
+                               int64           latency;
 
-                       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
-                */
-               if (logfile && commands[st->state + 1] == NULL)
-               {
-                       double          lag;
-                       double          latency;
-
-                       /*
-                        * write the log entry if this row belongs to the random sample,
-                        * or no sampling rate was given which means log everything.
-                        */
-                       if (sample_rate == 0.0 ||
-                               pg_erand48(thread->random_state) <= sample_rate)
-                       {
-                               if (!now_valid)
-                               {
+                               if (INSTR_TIME_IS_ZERO(now))
                                        INSTR_TIME_SET_CURRENT(now);
-                                       now_valid = true;
-                               }
-                               latency = (double) (INSTR_TIME_GET_MICROSEC(now) - st->txn_scheduled);
-                               lag = (double) (INSTR_TIME_GET_MICROSEC(st->txn_begin) - st->txn_scheduled);
-
-                               /* should we aggregate the results or not? */
-                               if (agg_interval > 0)
-                               {
-                                       /*
-                                        * are we still in the same interval? if yes, accumulate
-                                        * the values (print them otherwise)
-                                        */
-                                       if (agg->start_time + agg_interval >= INSTR_TIME_GET_DOUBLE(now))
-                                       {
-                                               agg->cnt += 1;
-                                               agg->sum_latency += latency;
-                                               agg->sum2_latency += latency * latency;
-
-                                               /* first in this aggregation interval */
-                                               if ((agg->cnt == 1) || (latency < agg->min_latency))
-                                                       agg->min_latency = latency;
-
-                                               if ((agg->cnt == 1) || (latency > agg->max_latency))
-                                                       agg->max_latency = latency;
-
-                                               /* and the same for schedule lag */
-                                               if (throttle_delay)
-                                               {
-                                                       agg->sum_lag += lag;
-                                                       agg->sum2_lag += lag * lag;
-
-                                                       if ((agg->cnt == 1) || (lag < agg->min_lag))
-                                                               agg->min_lag = lag;
-                                                       if ((agg->cnt == 1) || (lag > agg->max_lag))
-                                                               agg->max_lag = lag;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               /*
-                                                * Loop until we reach the interval of the current
-                                                * transaction (and print all the empty intervals in
-                                                * between).
-                                                */
-                                               while (agg->start_time + agg_interval < INSTR_TIME_GET_DOUBLE(now))
-                                               {
-                                                       /*
-                                                        * This is a non-Windows branch (thanks to the
-                                                        * ifdef in usage), so we don't need to handle
-                                                        * this in a special way (see below).
-                                                        */
-                                                       fprintf(logfile, "%ld %d %.0f %.0f %.0f %.0f",
-                                                                       agg->start_time,
-                                                                       agg->cnt,
-                                                                       agg->sum_latency,
-                                                                       agg->sum2_latency,
-                                                                       agg->min_latency,
-                                                                       agg->max_latency);
-                                                       if (throttle_delay)
-                                                               fprintf(logfile, " %.0f %.0f %.0f %.0f",
-                                                                               agg->sum_lag,
-                                                                               agg->sum2_lag,
-                                                                               agg->min_lag,
-                                                                               agg->max_lag);
-                                                       fputc('\n', logfile);
-
-                                                       /* move to the next inteval */
-                                                       agg->start_time = agg->start_time + agg_interval;
-
-                                                       /* reset for "no transaction" intervals */
-                                                       agg->cnt = 0;
-                                                       agg->min_latency = 0;
-                                                       agg->max_latency = 0;
-                                                       agg->sum_latency = 0;
-                                                       agg->sum2_latency = 0;
-                                                       agg->min_lag = 0;
-                                                       agg->max_lag = 0;
-                                                       agg->sum_lag = 0;
-                                                       agg->sum2_lag = 0;
-                                               }
-
-                                               /*
-                                                * and now update the reset values (include the
-                                                * current)
-                                                */
-                                               agg->cnt = 1;
-                                               agg->min_latency = latency;
-                                               agg->max_latency = latency;
-                                               agg->sum_latency = latency;
-                                               agg->sum2_latency = latency * latency;
-                                               agg->min_lag = lag;
-                                               agg->max_lag = lag;
-                                               agg->sum_lag = lag;
-                                               agg->sum2_lag = lag * lag;
-                                       }
-                               }
-                               else
-                               {
-                                       /* no, print raw transactions */
-#ifndef WIN32
-
-                                       /*
-                                        * This is more than we really ought to know about
-                                        * instr_time
-                                        */
-                                       fprintf(logfile, "%d %d %.0f %d %ld %ld",
-                                                       st->id, st->cnt, latency, st->use_file,
-                                                       (long) now.tv_sec, (long) now.tv_usec);
-#else
-
-                                       /*
-                                        * On Windows, instr_time doesn't provide a timestamp
-                                        * anyway
-                                        */
-                                       fprintf(logfile, "%d %d %.0f %d 0 0",
-                                                       st->id, st->cnt, latency, st->use_file);
-#endif
-                                       if (throttle_delay)
-                                               fprintf(logfile, " %.0f", lag);
-                                       fputc('\n', logfile);
-                               }
+                               latency = INSTR_TIME_GET_MICROSEC(now) - st->txn_scheduled;
+
+                               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;
                        }
+
+                       /* record the time it took in the log */
+                       if (logfile)
+                               doLog(thread, st, logfile, &now, agg);
                }
 
                if (commands[st->state]->type == SQL_COMMAND)
@@ -1734,6 +1601,137 @@ top:
        return true;
 }
 
+/*
+ * print log entry after completing one transaction.
+ */
+static void
+doLog(TState *thread, CState *st, FILE *logfile, instr_time *now, AggVals *agg)
+{
+       double          lag;
+       double          latency;
+
+       /*
+        * Skip the log entry if sampling is enabled and this row doesn't belong
+        * to the random sample.
+        */
+       if (sample_rate != 0.0 &&
+               pg_erand48(thread->random_state) > sample_rate)
+               return;
+
+       if (INSTR_TIME_IS_ZERO(*now))
+               INSTR_TIME_SET_CURRENT(*now);
+
+       latency = (double) (INSTR_TIME_GET_MICROSEC(*now) - st->txn_scheduled);
+       lag = (double) (INSTR_TIME_GET_MICROSEC(st->txn_begin) - st->txn_scheduled);
+
+       /* should we aggregate the results or not? */
+       if (agg_interval > 0)
+       {
+               /*
+                * Are we still in the same interval? If yes, accumulate the values
+                * (print them otherwise)
+                */
+               if (agg->start_time + agg_interval >= INSTR_TIME_GET_DOUBLE(*now))
+               {
+                       agg->cnt += 1;
+                       agg->sum_latency += latency;
+                       agg->sum2_latency += latency * latency;
+
+                       /* first in this aggregation interval */
+                       if ((agg->cnt == 1) || (latency < agg->min_latency))
+                               agg->min_latency = latency;
+
+                       if ((agg->cnt == 1) || (latency > agg->max_latency))
+                               agg->max_latency = latency;
+
+                       /* and the same for schedule lag */
+                       if (throttle_delay)
+                       {
+                               agg->sum_lag += lag;
+                               agg->sum2_lag += lag * lag;
+
+                               if ((agg->cnt == 1) || (lag < agg->min_lag))
+                                       agg->min_lag = lag;
+                               if ((agg->cnt == 1) || (lag > agg->max_lag))
+                                       agg->max_lag = lag;
+                       }
+               }
+               else
+               {
+                       /*
+                        * Loop until we reach the interval of the current transaction
+                        * (and print all the empty intervals in between).
+                        */
+                       while (agg->start_time + agg_interval < INSTR_TIME_GET_DOUBLE(*now))
+                       {
+                               /*
+                                * This is a non-Windows branch (thanks to the
+                                * ifdef in usage), so we don't need to handle
+                                * this in a special way (see below).
+                                */
+                               fprintf(logfile, "%ld %d %.0f %.0f %.0f %.0f",
+                                               agg->start_time,
+                                               agg->cnt,
+                                               agg->sum_latency,
+                                               agg->sum2_latency,
+                                               agg->min_latency,
+                                               agg->max_latency);
+                               if (throttle_delay)
+                                       fprintf(logfile, " %.0f %.0f %.0f %.0f",
+                                                       agg->sum_lag,
+                                                       agg->sum2_lag,
+                                                       agg->min_lag,
+                                                       agg->max_lag);
+                               fputc('\n', logfile);
+
+                               /* move to the next inteval */
+                               agg->start_time = agg->start_time + agg_interval;
+
+                               /* reset for "no transaction" intervals */
+                               agg->cnt = 0;
+                               agg->min_latency = 0;
+                               agg->max_latency = 0;
+                               agg->sum_latency = 0;
+                               agg->sum2_latency = 0;
+                               agg->min_lag = 0;
+                               agg->max_lag = 0;
+                               agg->sum_lag = 0;
+                               agg->sum2_lag = 0;
+                       }
+
+                       /* reset the values to include only the current transaction. */
+                       agg->cnt = 1;
+                       agg->min_latency = latency;
+                       agg->max_latency = latency;
+                       agg->sum_latency = latency;
+                       agg->sum2_latency = latency * latency;
+                       agg->min_lag = lag;
+                       agg->max_lag = lag;
+                       agg->sum_lag = lag;
+                       agg->sum2_lag = lag * lag;
+               }
+       }
+       else
+       {
+               /* no, print raw transactions */
+#ifndef WIN32
+
+               /* This is more than we really ought to know about instr_time */
+               fprintf(logfile, "%d %d %.0f %d %ld %ld",
+                               st->id, st->cnt, latency, st->use_file,
+                               (long) now->tv_sec, (long) now->tv_usec);
+#else
+
+               /* On Windows, instr_time doesn't provide a timestamp anyway */
+               fprintf(logfile, "%d %d %.0f %d 0 0",
+                               st->id, st->cnt, latency, st->use_file);
+#endif
+               if (throttle_delay)
+                       fprintf(logfile, " %.0f", lag);
+               fputc('\n', logfile);
+       }
+}
+
 /* discard connections */
 static void
 disconnect_all(CState *state, int length)