|
4 | 4 | * A simple benchmark program for PostgreSQL
|
5 | 5 | * Originally written by Tatsuo Ishii and enhanced by many contributors.
|
6 | 6 | *
|
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 $ |
8 | 8 | * Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
9 | 9 | * ALL RIGHTS RESERVED;
|
10 | 10 | *
|
|
29 | 29 | #include"postgres_fe.h"
|
30 | 30 |
|
31 | 31 | #include"libpq-fe.h"
|
| 32 | +#include"pqsignal.h" |
32 | 33 |
|
33 | 34 | #include<ctype.h>
|
34 | 35 |
|
|
37 | 38 | #defineFD_SETSIZE 1024
|
38 | 39 | #include<win32.h>
|
39 | 40 | #else
|
| 41 | +#include<signal.h> |
40 | 42 | #include<sys/time.h>
|
41 | 43 | #include<unistd.h>
|
42 | 44 | #endif/* ! WIN32 */
|
@@ -67,8 +69,11 @@ extern intoptind;
|
67 | 69 | #defineMAXCLIENTS1024
|
68 | 70 | #endif
|
69 | 71 |
|
| 72 | +#defineDEFAULT_NXACTS10/* default nxacts */ |
| 73 | + |
70 | 74 | intnclients=1;/* default number of simulated clients */
|
71 |
| -intnxacts=10;/* default number of transactions per clients */ |
| 75 | +intnxacts=0;/* number of transactions per client */ |
| 76 | +intduration=0;/* duration in seconds */ |
72 | 77 |
|
73 | 78 | /*
|
74 | 79 | * scaling factor. for example, scale = 10 will make 1000000 tuples of
|
@@ -105,6 +110,8 @@ char *pgtty = NULL;
|
105 | 110 | char*login=NULL;
|
106 | 111 | char*dbName;
|
107 | 112 |
|
| 113 | +volatilebooltimer_exceeded= false;/* flag from signal handler */ |
| 114 | + |
108 | 115 | /* variable definitions */
|
109 | 116 | typedefstruct
|
110 | 117 | {
|
@@ -162,7 +169,7 @@ typedef struct
|
162 | 169 | }Command;
|
163 | 170 |
|
164 | 171 | Command**sql_files[MAX_FILES];/* SQL script files */
|
165 |
| -intnum_files;/*itsnumber */ |
| 172 | +intnum_files;/* number of script files */ |
166 | 173 |
|
167 | 174 | /* default scenario */
|
168 | 175 | staticchar*tpc_b= {
|
@@ -208,6 +215,10 @@ static char *select_only = {
|
208 | 215 | /* Connection overhead time */
|
209 | 216 | staticstructtimevalconn_total_time= {0,0};
|
210 | 217 |
|
| 218 | +/* Function prototypes */ |
| 219 | +staticvoidsetalarm(intseconds); |
| 220 | + |
| 221 | + |
211 | 222 | /* Calculate total time */
|
212 | 223 | staticvoid
|
213 | 224 | addTime(structtimeval*t1,structtimeval*t2,structtimeval*result)
|
@@ -241,7 +252,7 @@ diffTime(struct timeval *t1, struct timeval *t2, struct timeval *result)
|
241 | 252 | staticvoid
|
242 | 253 | usage(void)
|
243 | 254 | {
|
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"); |
245 | 256 | fprintf(stderr,"(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor] [-F fillfactor] [-U login][-d][dbname]\n");
|
246 | 257 | }
|
247 | 258 |
|
@@ -630,7 +641,8 @@ doCustom(CState * state, int n, int debug)
|
630 | 641 | st->con=NULL;
|
631 | 642 | }
|
632 | 643 |
|
633 |
| -if (++st->cnt >=nxacts) |
| 644 | +++st->cnt; |
| 645 | +if ((st->cnt >=nxacts&&duration <=0)||timer_exceeded) |
634 | 646 | {
|
635 | 647 | remains--;/* I've done */
|
636 | 648 | if (st->con!=NULL)
|
@@ -1434,8 +1446,18 @@ printResults(
|
1434 | 1446 | printf("scaling factor: %d\n",scale);
|
1435 | 1447 | printf("query mode: %s\n",QUERYMODE[querymode]);
|
1436 | 1448 | 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 | +} |
1439 | 1461 | printf("tps = %f (including connections establishing)\n",t1);
|
1440 | 1462 | printf("tps = %f (excluding connections establishing)\n",t2);
|
1441 | 1463 | }
|
@@ -1499,7 +1521,7 @@ main(int argc, char **argv)
|
1499 | 1521 |
|
1500 | 1522 | memset(state,0,sizeof(*state));
|
1501 | 1523 |
|
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) |
1503 | 1525 | {
|
1504 | 1526 | switch (c)
|
1505 | 1527 | {
|
@@ -1565,13 +1587,31 @@ main(int argc, char **argv)
|
1565 | 1587 | }
|
1566 | 1588 | break;
|
1567 | 1589 | 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 | +} |
1568 | 1595 | nxacts=atoi(optarg);
|
1569 | 1596 | if (nxacts <=0)
|
1570 | 1597 | {
|
1571 | 1598 | fprintf(stderr,"invalid number of transactions: %d\n",nxacts);
|
1572 | 1599 | exit(1);
|
1573 | 1600 | }
|
1574 | 1601 | 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; |
1575 | 1615 | case'U':
|
1576 | 1616 | login=optarg;
|
1577 | 1617 | break;
|
@@ -1650,6 +1690,10 @@ main(int argc, char **argv)
|
1650 | 1690 | exit(0);
|
1651 | 1691 | }
|
1652 | 1692 |
|
| 1693 | +/* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */ |
| 1694 | +if (nxacts <=0&&duration <=0) |
| 1695 | +nxacts=DEFAULT_NXACTS; |
| 1696 | + |
1653 | 1697 | remains=nclients;
|
1654 | 1698 |
|
1655 | 1699 | if (nclients>1)
|
@@ -1695,8 +1739,12 @@ main(int argc, char **argv)
|
1695 | 1739 |
|
1696 | 1740 | if (debug)
|
1697 | 1741 | {
|
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", |
1699 | 1744 | 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); |
1700 | 1748 | }
|
1701 | 1749 |
|
1702 | 1750 | /* opening connection... */
|
@@ -1779,6 +1827,10 @@ main(int argc, char **argv)
|
1779 | 1827 | /* get start up time */
|
1780 | 1828 | gettimeofday(&start_time,NULL);
|
1781 | 1829 |
|
| 1830 | +/* set alarm if duration is specified. */ |
| 1831 | +if (duration>0) |
| 1832 | +setalarm(duration); |
| 1833 | + |
1782 | 1834 | if (is_connect==0)
|
1783 | 1835 | {
|
1784 | 1836 | structtimevalt,now;
|
@@ -1951,3 +2003,51 @@ main(int argc, char **argv)
|
1951 | 2003 | }
|
1952 | 2004 | }
|
1953 | 2005 | }
|
| 2006 | + |
| 2007 | + |
| 2008 | +/* |
| 2009 | + * Support for duration option: set timer_exceeded after so many seconds. |
| 2010 | + */ |
| 2011 | + |
| 2012 | +#ifndefWIN32 |
| 2013 | + |
| 2014 | +staticvoid |
| 2015 | +handle_sig_alarm(SIGNAL_ARGS) |
| 2016 | +{ |
| 2017 | +timer_exceeded= true; |
| 2018 | +} |
| 2019 | + |
| 2020 | +staticvoid |
| 2021 | +setalarm(intseconds) |
| 2022 | +{ |
| 2023 | +pqsignal(SIGALRM,handle_sig_alarm); |
| 2024 | +alarm(seconds); |
| 2025 | +} |
| 2026 | + |
| 2027 | +#else/* WIN32 */ |
| 2028 | + |
| 2029 | +staticVOIDCALLBACK |
| 2030 | +win32_timer_callback(PVOIDlpParameter,BOOLEANTimerOrWaitFired) |
| 2031 | +{ |
| 2032 | +timer_exceeded= true; |
| 2033 | +} |
| 2034 | + |
| 2035 | +staticvoid |
| 2036 | +setalarm(intseconds) |
| 2037 | +{ |
| 2038 | +HANDLEqueue; |
| 2039 | +HANDLEtimer; |
| 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 */ |