Skip to content

Commit cff4aa6

Browse files
committed
Add a duration option to pgbench, so that test length can be specified in seconds
instead of by number of transactions to run. Takahiro Itagaki
1 parent 06edce4 commit cff4aa6

File tree

2 files changed

+128
-18
lines changed

2 files changed

+128
-18
lines changed

contrib/pgbench/pgbench.c

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* A simple benchmark program for PostgreSQL
55
* Originally written by Tatsuo Ishii and enhanced by many contributors.
66
*
7-
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.81 2008/08/22 17:57:34 momjian Exp $
7+
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.82 2008/09/11 23:52:48 tgl Exp $
88
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
99
* ALL RIGHTS RESERVED;
1010
*
@@ -29,6 +29,7 @@
2929
#include "postgres_fe.h"
3030

3131
#include "libpq-fe.h"
32+
#include "pqsignal.h"
3233

3334
#include <ctype.h>
3435

@@ -37,6 +38,7 @@
3738
#define FD_SETSIZE 1024
3839
#include <win32.h>
3940
#else
41+
#include <signal.h>
4042
#include <sys/time.h>
4143
#include <unistd.h>
4244
#endif /* ! WIN32 */
@@ -67,8 +69,11 @@ extern int optind;
6769
#define MAXCLIENTS 1024
6870
#endif
6971

72+
#define DEFAULT_NXACTS 10 /* default nxacts */
73+
7074
int nclients = 1; /* default number of simulated clients */
71-
int nxacts = 10; /* default number of transactions per clients */
75+
int nxacts = 0; /* number of transactions per client */
76+
int duration = 0; /* duration in seconds */
7277

7378
/*
7479
* scaling factor. for example, scale = 10 will make 1000000 tuples of
@@ -105,6 +110,8 @@ char *pgtty = NULL;
105110
char *login = NULL;
106111
char *dbName;
107112

113+
volatile bool timer_exceeded = false; /* flag from signal handler */
114+
108115
/* variable definitions */
109116
typedef struct
110117
{
@@ -162,7 +169,7 @@ typedef struct
162169
} Command;
163170

164171
Command **sql_files[MAX_FILES]; /* SQL script files */
165-
int num_files; /* its number */
172+
int num_files; /* number of script files */
166173

167174
/* default scenario */
168175
static char *tpc_b = {
@@ -208,6 +215,10 @@ static char *select_only = {
208215
/* Connection overhead time */
209216
static struct timeval conn_total_time = {0, 0};
210217

218+
/* Function prototypes */
219+
static void setalarm(int seconds);
220+
221+
211222
/* Calculate total time */
212223
static void
213224
addTime(struct timeval *t1, struct timeval *t2, struct timeval *result)
@@ -241,7 +252,7 @@ diffTime(struct timeval *t1, struct timeval *t2, struct timeval *result)
241252
static void
242253
usage(void)
243254
{
244-
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");
255+
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");
245256
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor] [-F fillfactor] [-U login][-d][dbname]\n");
246257
}
247258

@@ -630,7 +641,8 @@ doCustom(CState * state, int n, int debug)
630641
st->con = NULL;
631642
}
632643

633-
if (++st->cnt >= nxacts)
644+
++st->cnt;
645+
if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
634646
{
635647
remains--; /* I've done */
636648
if (st->con != NULL)
@@ -1434,8 +1446,18 @@ printResults(
14341446
printf("scaling factor: %d\n", scale);
14351447
printf("query mode: %s\n", QUERYMODE[querymode]);
14361448
printf("number of clients: %d\n", nclients);
1437-
printf("number of transactions per client: %d\n", nxacts);
1438-
printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
1449+
if (duration <= 0)
1450+
{
1451+
printf("number of transactions per client: %d\n", nxacts);
1452+
printf("number of transactions actually processed: %d/%d\n",
1453+
normal_xacts, nxacts * nclients);
1454+
}
1455+
else
1456+
{
1457+
printf("duration: %d s\n", duration);
1458+
printf("number of transactions actually processed: %d\n",
1459+
normal_xacts);
1460+
}
14391461
printf("tps = %f (including connections establishing)\n", t1);
14401462
printf("tps = %f (excluding connections establishing)\n", t2);
14411463
}
@@ -1499,7 +1521,7 @@ main(int argc, char **argv)
14991521

15001522
memset(state, 0, sizeof(*state));
15011523

1502-
while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:CNSlf:D:F:M:")) != -1)
1524+
while ((c = getopt(argc, argv, "ih:nvp:dSNc:Cs:t:T:U:lf:D:F:M:")) != -1)
15031525
{
15041526
switch (c)
15051527
{
@@ -1565,13 +1587,31 @@ main(int argc, char **argv)
15651587
}
15661588
break;
15671589
case 't':
1590+
if (duration > 0)
1591+
{
1592+
fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both.\n");
1593+
exit(1);
1594+
}
15681595
nxacts = atoi(optarg);
15691596
if (nxacts <= 0)
15701597
{
15711598
fprintf(stderr, "invalid number of transactions: %d\n", nxacts);
15721599
exit(1);
15731600
}
15741601
break;
1602+
case 'T':
1603+
if (nxacts > 0)
1604+
{
1605+
fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both.\n");
1606+
exit(1);
1607+
}
1608+
duration = atoi(optarg);
1609+
if (duration <= 0)
1610+
{
1611+
fprintf(stderr, "invalid duration: %d\n", duration);
1612+
exit(1);
1613+
}
1614+
break;
15751615
case 'U':
15761616
login = optarg;
15771617
break;
@@ -1650,6 +1690,10 @@ main(int argc, char **argv)
16501690
exit(0);
16511691
}
16521692

1693+
/* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
1694+
if (nxacts <= 0 && duration <= 0)
1695+
nxacts = DEFAULT_NXACTS;
1696+
16531697
remains = nclients;
16541698

16551699
if (nclients > 1)
@@ -1695,8 +1739,12 @@ main(int argc, char **argv)
16951739

16961740
if (debug)
16971741
{
1698-
printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
1742+
if (duration <= 0)
1743+
printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
16991744
pghost, pgport, nclients, nxacts, dbName);
1745+
else
1746+
printf("pghost: %s pgport: %s nclients: %d duration: %d dbName: %s\n",
1747+
pghost, pgport, nclients, duration, dbName);
17001748
}
17011749

17021750
/* opening connection... */
@@ -1779,6 +1827,10 @@ main(int argc, char **argv)
17791827
/* get start up time */
17801828
gettimeofday(&start_time, NULL);
17811829

1830+
/* set alarm if duration is specified. */
1831+
if (duration > 0)
1832+
setalarm(duration);
1833+
17821834
if (is_connect == 0)
17831835
{
17841836
struct timeval t, now;
@@ -1951,3 +2003,51 @@ main(int argc, char **argv)
19512003
}
19522004
}
19532005
}
2006+
2007+
2008+
/*
2009+
* Support for duration option: set timer_exceeded after so many seconds.
2010+
*/
2011+
2012+
#ifndef WIN32
2013+
2014+
static void
2015+
handle_sig_alarm(SIGNAL_ARGS)
2016+
{
2017+
timer_exceeded = true;
2018+
}
2019+
2020+
static void
2021+
setalarm(int seconds)
2022+
{
2023+
pqsignal(SIGALRM, handle_sig_alarm);
2024+
alarm(seconds);
2025+
}
2026+
2027+
#else /* WIN32 */
2028+
2029+
static VOID CALLBACK
2030+
win32_timer_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
2031+
{
2032+
timer_exceeded = true;
2033+
}
2034+
2035+
static void
2036+
setalarm(int seconds)
2037+
{
2038+
HANDLE queue;
2039+
HANDLE timer;
2040+
2041+
/* This function will be called at most once, so we can cheat a bit. */
2042+
queue = CreateTimerQueue();
2043+
if (seconds > ((DWORD)-1) / 1000 ||
2044+
!CreateTimerQueueTimer(&timer, queue,
2045+
win32_timer_callback, NULL, seconds * 1000, 0,
2046+
WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE))
2047+
{
2048+
fprintf(stderr, "Failed to set timer\n");
2049+
exit(1);
2050+
}
2051+
}
2052+
2053+
#endif /* WIN32 */

doc/src/sgml/pgbench.sgml

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.6 2008/03/19 03:33:21 ishii Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.7 2008/09/11 23:52:48 tgl Exp $ -->
22

33
<sect1 id="pgbench">
44
<title>pgbench</title>
@@ -35,7 +35,7 @@ tps = 85.296346 (excluding connections establishing)
3535
The first four lines just report some of the most important parameter
3636
settings. The next line reports the number of transactions completed
3737
and intended (the latter being just the product of number of clients
38-
and number of transactions); these will be equal unless the run
38+
and number of transactions per client); these will be equal unless the run
3939
failed before completion. The last two lines report the TPS rate,
4040
figured with and without counting the time to start database sessions.
4141
</para>
@@ -99,8 +99,9 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
9999

100100
In nearly all cases, you'll need some options to make a useful test.
101101
The most important options are <literal>-c</> (number of clients),
102-
<literal>-t</> (number of transactions), and <literal>-f</> (specify
103-
a custom script file). See below for a full list.
102+
<literal>-t</> (number of transactions), <literal>-T</> (time limit),
103+
and <literal>-f</> (specify a custom script file).
104+
See below for a full list.
104105
</para>
105106

106107
<para>
@@ -173,21 +174,30 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
173174
Number of transactions each client runs. Default is 10.
174175
</entry>
175176
</row>
177+
<row>
178+
<entry><literal>-T</literal> <replaceable>seconds</></entry>
179+
<entry>
180+
Duration of benchmark test in seconds. <literal>-t</literal> and
181+
<literal>-T</literal> are mutually exclusive.
182+
</entry>
183+
</row>
176184
<row>
177185
<entry><literal>-M</literal> <replaceable>querymode</></entry>
178186
<entry>
179-
Choose the query mode from the follows. default is simple.
187+
Protocol to use for submitting queries for the server:
180188
<itemizedlist>
181189
<listitem>
182-
<para>simple: using simple query protocol.</para>
190+
<para><literal>simple</>: use simple query protocol.</para>
183191
</listitem>
184192
<listitem>
185-
<para>extended: using extended protocol.</para>
193+
<para><literal>extended</>: use extended query protocol.</para>
186194
</listitem>
187195
<listitem>
188-
<para>prepared: using extended protocol with prepared statements.</para>
196+
<para><literal>prepared</>: use extended query protocol with prepared statements.</para>
189197
</listitem>
190198
</itemizedlist>
199+
The default is simple query protocol. (See <xref linkend="protocol">
200+
for more information.)
191201
</entry>
192202
</row>
193203
<row>
@@ -515,7 +525,7 @@ END;
515525

516526
<para>
517527
In the first place, <emphasis>never</> believe any test that runs
518-
for only a few seconds. Increase the <literal>-t</> setting enough
528+
for only a few seconds. Use the <literal>-t</> or <literal>-T</> option
519529
to make the run last at least a few minutes, so as to average out noise.
520530
In some cases you could need hours to get numbers that are reproducible.
521531
It's a good idea to try the test run a few times, to find out if your

0 commit comments

Comments
 (0)