diff --git a/contrib/pgbench/README.pgbench b/contrib/pgbench/README.pgbench index 599dc3b6c5..2afd4db25e 100644 --- a/contrib/pgbench/README.pgbench +++ b/contrib/pgbench/README.pgbench @@ -1,4 +1,4 @@ -$PostgreSQL: pgsql/contrib/pgbench/README.pgbench,v 1.18 2007/04/08 01:15:07 ishii Exp $ +$PostgreSQL: pgsql/contrib/pgbench/README.pgbench,v 1.19 2007/07/06 13:36:55 wieck Exp $ pgbench README @@ -231,6 +231,16 @@ o -f option Variables can also be defined by using -D option. + \usleep usec + + causes script execution to sleep for the specified duration in + microseconds. + + example: + + \setrandom usec 1000000 3000000 + \usleep :usec + Example, TPC-B like benchmark can be defined as follows(scaling factor = 1): diff --git a/contrib/pgbench/pgbench.c b/contrib/pgbench/pgbench.c index 2de6a51b05..77d3a735d0 100644 --- a/contrib/pgbench/pgbench.c +++ b/contrib/pgbench/pgbench.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.66 2007/05/24 18:54:10 tgl Exp $ + * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.67 2007/07/06 13:36:55 wieck Exp $ * * pgbench: a simple benchmark program for PostgreSQL * written by Tatsuo Ishii @@ -114,6 +114,8 @@ typedef struct int ecnt; /* error count */ int listen; /* 0 indicates that an async query has been * sent */ + int sleeping; /* 1 indicates that the client is napping */ + struct timeval until; /* napping until */ Variable *variables; /* array of variable definitions */ int nvariables; struct timeval txn_begin; /* used for measuring latencies */ @@ -445,6 +447,20 @@ doCustom(CState * state, int n, int debug) top: commands = sql_files[st->use_file]; + if (st->sleeping) + { /* are we sleeping? */ + int usec; + struct timeval now; + + gettimeofday(&now, NULL); + usec = (st->until.tv_sec - now.tv_sec) * 1000000 + + st->until.tv_usec - now.tv_usec; + if (usec <= 0) + st->sleeping = 0; /* Done sleeping, go ahead with next command */ + else + return; /* Still sleeping, nothing to do here */ + } + if (st->listen) { /* are we receiver? */ if (commands[st->state]->type == SQL_COMMAND) @@ -711,6 +727,32 @@ top: st->listen = 1; } + else if (pg_strcasecmp(argv[0], "usleep") == 0) + { + char *var; + int usec; + struct timeval now; + + if (*argv[1] == ':') + { + if ((var = getVariable(st, argv[1] + 1)) == NULL) + { + fprintf(stderr, "%s: undefined variable %s\n", argv[0], argv[1]); + st->ecnt++; + return; + } + usec = atoi(var); + } + else + usec = atoi(argv[1]); + + gettimeofday(&now, NULL); + st->until.tv_sec = now.tv_sec + (now.tv_usec + usec) / 1000000; + st->until.tv_usec = (now.tv_usec + usec) % 1000000; + st->sleeping = 1; + + st->listen = 1; + } goto top; } @@ -921,9 +963,21 @@ process_commands(char *buf) fprintf(stderr, "%s: extra argument \"%s\" ignored\n", my_commands->argv[0], my_commands->argv[j]); } + else if (pg_strcasecmp(my_commands->argv[0], "usleep") == 0) + { + if (my_commands->argc < 2) + { + fprintf(stderr, "%s: missing argument\n", my_commands->argv[0]); + return NULL; + } + + for (j = 2; j < my_commands->argc; j++) + fprintf(stderr, "%s: extra argument \"%s\" ignored\n", + my_commands->argv[0], my_commands->argv[j]); + } else { - fprintf(stderr, "invalid command %s\n", my_commands->argv[0]); + fprintf(stderr, "Invalid command %s\n", my_commands->argv[0]); return NULL; } } @@ -1143,6 +1197,9 @@ main(int argc, char **argv) fd_set input_mask; int nsocks; /* return from select(2) */ int maxsock; /* max socket number to be waited */ + struct timeval now; + struct timeval timeout; + int min_usec; #ifdef HAVE_GETRLIMIT struct rlimit rlim; @@ -1526,11 +1583,33 @@ main(int argc, char **argv) FD_ZERO(&input_mask); maxsock = -1; + min_usec = -1; for (i = 0; i < nclients; i++) { Command **commands = sql_files[state[i].use_file]; - if (state[i].con && commands[state[i].state]->type != META_COMMAND) + if (state[i].sleeping) + { + int this_usec; + int sock = PQsocket(state[i].con); + + if (min_usec < 0) + { + gettimeofday(&now, NULL); + min_usec = 0; + } + + this_usec = (state[i].until.tv_sec - now.tv_sec) * 1000000 + + state[i].until.tv_usec - now.tv_usec; + + if (this_usec > 0 && (min_usec == 0 || this_usec < min_usec)) + min_usec = this_usec; + + FD_SET(sock, &input_mask); + if (maxsock < sock) + maxsock = sock; + } + else if (state[i].con && commands[state[i].state]->type != META_COMMAND) { int sock = PQsocket(state[i].con); @@ -1547,8 +1626,18 @@ main(int argc, char **argv) if (maxsock != -1) { - if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL, - (fd_set *) NULL, (struct timeval *) NULL)) < 0) + if (min_usec >= 0) + { + timeout.tv_sec = min_usec / 1000000; + timeout.tv_usec = min_usec % 1000000; + + nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL, + (fd_set *) NULL, &timeout); + } + else + nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL, + (fd_set *) NULL, (struct timeval *) NULL); + if (nsocks < 0) { if (errno == EINTR) continue; @@ -1557,6 +1646,7 @@ main(int argc, char **argv) fprintf(stderr, "select failed: %s\n", strerror(errno)); exit(1); } +#ifdef NOT_USED else if (nsocks == 0) { /* timeout */ fprintf(stderr, "select timeout\n"); @@ -1567,6 +1657,7 @@ main(int argc, char **argv) } exit(0); } +#endif } /* ok, backend returns reply */