]> granicus.if.org Git - postgresql/commitdiff
Add a duration option to pgbench, so that test length can be specified in seconds
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 11 Sep 2008 23:52:48 +0000 (23:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 11 Sep 2008 23:52:48 +0000 (23:52 +0000)
instead of by number of transactions to run.  Takahiro Itagaki

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

index bbe97b929feeaa948dda08264d9bfe9109a77c5d..7b16cfda941ffbc9b5147a619190a8d3bb13d68c 100644 (file)
@@ -4,7 +4,7 @@
  * A simple benchmark program for PostgreSQL
  * Originally written by Tatsuo Ishii and enhanced by many contributors.
  *
- * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.81 2008/08/22 17:57:34 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.82 2008/09/11 23:52:48 tgl Exp $
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  * ALL RIGHTS RESERVED;
  *
@@ -29,6 +29,7 @@
 #include "postgres_fe.h"
 
 #include "libpq-fe.h"
+#include "pqsignal.h"
 
 #include <ctype.h>
 
@@ -37,6 +38,7 @@
 #define FD_SETSIZE 1024
 #include <win32.h>
 #else
+#include <signal.h>
 #include <sys/time.h>
 #include <unistd.h>
 #endif   /* ! WIN32 */
@@ -67,8 +69,11 @@ extern int   optind;
 #define MAXCLIENTS     1024
 #endif
 
+#define DEFAULT_NXACTS 10              /* default nxacts */
+
 int                    nclients = 1;           /* default number of simulated clients */
-int                    nxacts = 10;            /* default number of transactions per clients */
+int                    nxacts = 0;                     /* number of transactions per client */
+int                    duration = 0;           /* duration in seconds */
 
 /*
  * scaling factor. for example, scale = 10 will make 1000000 tuples of
@@ -105,6 +110,8 @@ char           *pgtty = NULL;
 char      *login = NULL;
 char      *dbName;
 
+volatile bool timer_exceeded = false;          /* flag from signal handler */
+
 /* variable definitions */
 typedef struct
 {
@@ -162,7 +169,7 @@ typedef struct
 }      Command;
 
 Command   **sql_files[MAX_FILES];              /* SQL script files */
-int                    num_files;                      /* its number */
+int                    num_files;                      /* number of script files */
 
 /* default scenario */
 static char *tpc_b = {
@@ -208,6 +215,10 @@ static char *select_only = {
 /* Connection overhead time */
 static struct timeval conn_total_time = {0, 0};
 
+/* Function prototypes */
+static void setalarm(int seconds);
+
+
 /* Calculate total time */
 static void
 addTime(struct timeval *t1, struct timeval *t2, struct timeval *result)
@@ -241,7 +252,7 @@ diffTime(struct timeval *t1, struct timeval *t2, struct timeval *result)
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-D varname=value][-n][-C][-v][-S][-N][-M querymode][-f filename][-l][-U login][-d][dbname]\n");
+       fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions | -T duration][-s scaling_factor][-D varname=value][-n][-C][-v][-S][-N][-M querymode][-f filename][-l][-U login][-d][dbname]\n");
        fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor] [-F fillfactor] [-U login][-d][dbname]\n");
 }
 
@@ -630,7 +641,8 @@ top:
                                st->con = NULL;
                        }
 
-                       if (++st->cnt >= nxacts)
+                       ++st->cnt;
+                       if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
                        {
                                remains--;              /* I've done */
                                if (st->con != NULL)
@@ -1434,8 +1446,18 @@ printResults(
        printf("scaling factor: %d\n", scale);
        printf("query mode: %s\n", QUERYMODE[querymode]);
        printf("number of clients: %d\n", nclients);
-       printf("number of transactions per client: %d\n", nxacts);
-       printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
+       if (duration <= 0)
+       {
+               printf("number of transactions per client: %d\n", nxacts);
+               printf("number of transactions actually processed: %d/%d\n",
+                          normal_xacts, nxacts * nclients);
+       }
+       else
+       {
+               printf("duration: %d s\n", duration);
+               printf("number of transactions actually processed: %d\n",
+                          normal_xacts);
+       }
        printf("tps = %f (including connections establishing)\n", t1);
        printf("tps = %f (excluding connections establishing)\n", t2);
 }
@@ -1499,7 +1521,7 @@ main(int argc, char **argv)
 
        memset(state, 0, sizeof(*state));
 
-       while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:CNSlf:D:F:M:")) != -1)
+       while ((c = getopt(argc, argv, "ih:nvp:dSNc:Cs:t:T:U:lf:D:F:M:")) != -1)
        {
                switch (c)
                {
@@ -1565,6 +1587,11 @@ main(int argc, char **argv)
                                }
                                break;
                        case 't':
+                               if (duration > 0)
+                               {
+                                       fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both.\n");
+                                       exit(1);
+                               }
                                nxacts = atoi(optarg);
                                if (nxacts <= 0)
                                {
@@ -1572,6 +1599,19 @@ main(int argc, char **argv)
                                        exit(1);
                                }
                                break;
+                       case 'T':
+                               if (nxacts > 0)
+                               {
+                                       fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both.\n");
+                                       exit(1);
+                               }
+                               duration = atoi(optarg);
+                               if (duration <= 0)
+                               {
+                                       fprintf(stderr, "invalid duration: %d\n", duration);
+                                       exit(1);
+                               }
+                               break;
                        case 'U':
                                login = optarg;
                                break;
@@ -1650,6 +1690,10 @@ main(int argc, char **argv)
                exit(0);
        }
 
+       /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
+       if (nxacts <= 0 && duration <= 0)
+               nxacts = DEFAULT_NXACTS;
+
        remains = nclients;
 
        if (nclients > 1)
@@ -1695,8 +1739,12 @@ main(int argc, char **argv)
 
        if (debug)
        {
-               printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
+               if (duration <= 0)
+                       printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
                           pghost, pgport, nclients, nxacts, dbName);
+               else
+                       printf("pghost: %s pgport: %s nclients: %d duration: %d dbName: %s\n",
+                          pghost, pgport, nclients, duration, dbName);
        }
 
        /* opening connection... */
@@ -1779,6 +1827,10 @@ main(int argc, char **argv)
        /* get start up time */
        gettimeofday(&start_time, NULL);
 
+       /* set alarm if duration is specified. */
+       if (duration > 0)
+               setalarm(duration);
+
        if (is_connect == 0)
        {
                struct timeval t, now;
@@ -1951,3 +2003,51 @@ main(int argc, char **argv)
                }
        }
 }
+
+
+/*
+ * Support for duration option: set timer_exceeded after so many seconds.
+ */
+
+#ifndef WIN32
+
+static void
+handle_sig_alarm(SIGNAL_ARGS)
+{
+       timer_exceeded = true;
+}
+
+static void
+setalarm(int seconds)
+{
+       pqsignal(SIGALRM, handle_sig_alarm);
+       alarm(seconds);
+}
+
+#else  /* WIN32 */
+
+static VOID CALLBACK
+win32_timer_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
+{
+       timer_exceeded = true;
+}
+
+static void
+setalarm(int seconds)
+{
+       HANDLE  queue;
+       HANDLE  timer;
+
+       /* This function will be called at most once, so we can cheat a bit. */
+       queue = CreateTimerQueue();
+       if (seconds > ((DWORD)-1) / 1000 ||
+               !CreateTimerQueueTimer(&timer, queue,
+                                                          win32_timer_callback, NULL, seconds * 1000, 0,
+                                                          WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE))
+       {
+               fprintf(stderr, "Failed to set timer\n");
+               exit(1);
+       }
+}
+
+#endif  /* WIN32 */
index 02f9afee8908f16d93327ef436f9bed5458edd2b..795f17fcdabbb0f698ecd093e1e833825c89fd73 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.6 2008/03/19 03:33:21 ishii Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.7 2008/09/11 23:52:48 tgl Exp $ -->
 
 <sect1 id="pgbench">
  <title>pgbench</title>
@@ -35,7 +35,7 @@ tps = 85.296346 (excluding connections establishing)
   The first four lines just report some of the most important parameter
   settings.  The next line reports the number of transactions completed
   and intended (the latter being just the product of number of clients
-  and number of transactions); these will be equal unless the run
+  and number of transactions per client); these will be equal unless the run
   failed before completion.  The last two lines report the TPS rate,
   figured with and without counting the time to start database sessions.
  </para>
@@ -99,8 +99,9 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
 
    In nearly all cases, you'll need some options to make a useful test.
    The most important options are <literal>-c</> (number of clients),
-   <literal>-t</> (number of transactions), and <literal>-f</> (specify
-   a custom script file).  See below for a full list.
+   <literal>-t</> (number of transactions), <literal>-T</> (time limit),
+   and <literal>-f</> (specify a custom script file).
+   See below for a full list.
   </para>
 
   <para>
@@ -173,21 +174,30 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
        Number of transactions each client runs.  Default is 10.
       </entry>
      </row>
+     <row>
+      <entry><literal>-T</literal> <replaceable>seconds</></entry>
+      <entry>
+       Duration of benchmark test in seconds. <literal>-t</literal> and
+       <literal>-T</literal> are mutually exclusive.
+      </entry>
+     </row>
      <row>
       <entry><literal>-M</literal> <replaceable>querymode</></entry>
       <entry>
-       Choose the query mode from the follows. default is simple.
+       Protocol to use for submitting queries for the server:
          <itemizedlist>
           <listitem>
-           <para>simple: using simple query protocol.</para>
+           <para><literal>simple</>: use simple query protocol.</para>
           </listitem>
           <listitem>
-           <para>extended: using extended protocol.</para>
+           <para><literal>extended</>: use extended query protocol.</para>
           </listitem>
           <listitem>
-           <para>prepared: using extended protocol with prepared statements.</para>
+           <para><literal>prepared</>: use extended query protocol with prepared statements.</para>
           </listitem>
          </itemizedlist>
+       The default is simple query protocol.  (See <xref linkend="protocol">
+       for more information.)
       </entry>
      </row>
      <row>
@@ -515,7 +525,7 @@ END;
 
   <para>
    In the first place, <emphasis>never</> believe any test that runs
-   for only a few seconds.  Increase the <literal>-t</> setting enough
+   for only a few seconds.  Use the <literal>-t</> or <literal>-T</> option
    to make the run last at least a few minutes, so as to average out noise.
    In some cases you could need hours to get numbers that are reproducible.
    It's a good idea to try the test run a few times, to find out if your