Index: README.pgbench =================================================================== RCS file: /projects/cvsroot/pgsql/contrib/pgbench/README.pgbench,v retrieving revision 1.12 diff -c -r1.12 README.pgbench *** README.pgbench 4 Oct 2005 13:40:45 -0000 1.12 --- README.pgbench 25 Jan 2006 06:14:17 -0000 *************** *** 86,91 **** --- 86,95 ---- -t number_of_transactions Number of transactions each client runs. default is 10. + -x number_of_runs + Number of runs performed. default is 1. Computes mean + and standard deviation at end of series. + -s scaling_factor this should be used with -i (initialize) option. number of tuples generated will be multiple of the *************** *** 209,214 **** --- 213,221 ---- o History + 2006/01/26 + * add -x option. contributed by Thomas F. O'Connell . + 2005/09/29 * add -f option. contributed by Tomoaki Sato. Index: pgbench.c =================================================================== RCS file: /projects/cvsroot/pgsql/contrib/pgbench/pgbench.c,v retrieving revision 1.49 diff -c -r1.49 pgbench.c *** pgbench.c 10 Dec 2005 01:09:07 -0000 1.49 --- pgbench.c 25 Jan 2006 06:14:17 -0000 *************** *** 22,27 **** --- 22,28 ---- #include "libpq-fe.h" #include + #include #ifdef WIN32 #include "win32.h" *************** *** 53,58 **** --- 54,60 ---- * some configurable parameters */ #define MAXCLIENTS 1024 /* max number of clients allowed */ + #define MAXRUNS 1024 /* max number of runs allowed */ int nclients = 1; /* default number of simulated clients */ int nxacts = 10; /* default number of transactions per clients */ *************** *** 62,67 **** --- 64,70 ---- * accounts table. */ int tps = 1; + int nruns = 1; /* default number of runs */ /* * end of configurable parameters *************** *** 169,175 **** static void usage(void) { ! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-N][-f filename][-l][-U login][-P password][-d][dbname]\n"); fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n"); } --- 172,178 ---- static void usage(void) { ! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-x nruns][-s scaling_factor][-n][-C][-v][-S][-N][-f filename][-l][-U login][-P password][-d][dbname]\n"); fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n"); } *************** *** 990,1013 **** static void printResults( int ttype, CState * state, ! struct timeval * tv1, struct timeval * tv2, ! struct timeval * tv3) { - double t1, - t2; - int i; - int normal_xacts = 0; char *s; - for (i = 0; i < nclients; i++) - normal_xacts += state[i].cnt; - - t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec); - t1 = normal_xacts * 1000000.0 / t1; - - t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec); - t2 = normal_xacts * 1000000.0 / t2; - if (ttype == 0) s = "TPC-B (sort of)"; else if (ttype == 2) --- 993,1003 ---- static void printResults( int ttype, CState * state, ! double t1, double t2, ! int normal_xacts, int curr_iter) { char *s; if (ttype == 0) s = "TPC-B (sort of)"; else if (ttype == 2) *************** *** 1017,1029 **** else s = "Custom query"; ! printf("transaction type: %s\n", s); ! printf("scaling factor: %d\n", tps); ! 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); printf("tps = %f (including connections establishing)\n", t1); printf("tps = %f (excluding connections establishing)\n", t2); } --- 1007,1025 ---- else s = "Custom query"; ! if(curr_iter == 0) ! { ! printf("transaction type: %s\n", s); ! printf("scaling factor: %d\n", tps); ! printf("number of clients: %d\n", nclients); ! printf("number of transactions per client: %d\n", nxacts); ! printf("\n"); ! } printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients); printf("tps = %f (including connections establishing)\n", t1); printf("tps = %f (excluding connections establishing)\n", t2); + if( curr_iter < nruns - 1 ) + printf("\n"); } *************** *** 1039,1052 **** * 2: skip update of branches and tellers */ char *filename = NULL; ! CState *state; /* status of clients */ ! struct timeval tv1; /* start up time */ ! struct timeval tv2; /* after establishing all connections to the ! * backend */ ! struct timeval tv3; /* end time */ ! int i; fd_set input_mask; int nsocks; /* return from select(2) */ --- 1035,1055 ---- * 2: skip update of branches and tellers */ char *filename = NULL; ! int i; ! double t1_total = 0; ! double t2_total = 0; ! double t1s[MAXRUNS]; ! double t2s[MAXRUNS]; ! double t1_mean = 0; ! double t2_mean = 0; ! ! double t1_variance = 0; ! double t2_variance = 0; ! ! double t1_stddev = 0; ! double t2_stddev = 0; fd_set input_mask; int nsocks; /* return from select(2) */ *************** *** 1056,1063 **** struct rlimit rlim; #endif - PGconn *con; - PGresult *res; char *env; if ((env = getenv("PGHOST")) != NULL && *env != '\0') --- 1059,1064 ---- *************** *** 1067,1073 **** else if ((env = getenv("PGUSER")) != NULL && *env != '\0') login = env; ! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:")) != -1) { switch (c) { --- 1068,1074 ---- else if ((env = getenv("PGUSER")) != NULL && *env != '\0') login = env; ! while ((c = getopt(argc, argv, "ih:nvp:dc:x:t:s:U:P:CNSlf:")) != -1) { switch (c) { *************** *** 1139,1144 **** --- 1140,1153 ---- exit(1); } break; + case 'x': + nruns = atoi(optarg); + if(nruns <= 0 || nruns > MAXRUNS) + { + fprintf(stderr, "invalid number of runs: %d\n", nruns); + exit(1); + } + break; case 'U': login = optarg; break; *************** *** 1179,1195 **** exit(0); } - remains = nclients; - - state = (CState *) malloc(sizeof(CState) * nclients); - if (state == NULL) - { - fprintf(stderr, "Couldn't allocate memory for state\n"); - exit(1); - } - - memset(state, 0, sizeof(*state) * nclients); - if (use_log) { char logpath[64]; --- 1188,1193 ---- *************** *** 1210,1435 **** pghost, pgport, nclients, nxacts, dbName); } ! /* opening connection... */ ! con = doConnect(); ! if (con == NULL) ! exit(1); ! ! if (PQstatus(con) == CONNECTION_BAD) { ! fprintf(stderr, "Connection to database '%s' failed.\n", dbName); ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); ! } ! if (ttype != 3) ! { ! /* ! * get the scaling factor that should be same as count(*) from ! * branches if this is not a custom query ! */ ! res = PQexec(con, "select count(*) from branches"); ! if (PQresultStatus(res) != PGRES_TUPLES_OK) ! { ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); ! } ! tps = atoi(PQgetvalue(res, 0, 0)); ! if (tps < 0) ! { ! fprintf(stderr, "count(*) from branches invalid (%d)\n", tps); ! exit(1); ! } ! PQclear(res); ! } ! if (!is_no_vacuum) ! { ! fprintf(stderr, "starting vacuum..."); ! res = PQexec(con, "vacuum branches"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! { ! fprintf(stderr, "%s", PQerrorMessage(con)); exit(1); - } - PQclear(res); ! res = PQexec(con, "vacuum tellers"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "%s", PQerrorMessage(con)); exit(1); } - PQclear(res); ! res = PQexec(con, "delete from history"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); } ! PQclear(res); ! res = PQexec(con, "vacuum history"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); ! } ! PQclear(res); ! ! fprintf(stderr, "end.\n"); ! ! if (is_full_vacuum) ! { ! fprintf(stderr, "starting full vacuum..."); ! res = PQexec(con, "vacuum analyze accounts"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "%s", PQerrorMessage(con)); exit(1); } PQclear(res); fprintf(stderr, "end.\n"); } ! } ! PQfinish(con); ! ! /* set random seed */ ! gettimeofday(&tv1, NULL); ! srand((unsigned int) tv1.tv_usec); ! /* get start up time */ ! gettimeofday(&tv1, NULL); ! if (is_connect == 0) ! { ! /* make connections to the database */ ! for (i = 0; i < nclients; i++) { ! state[i].id = i; ! if ((state[i].con = doConnect()) == NULL) ! exit(1); } - } ! /* time after connections set up */ ! gettimeofday(&tv2, NULL); ! /* process bultin SQL scripts */ ! switch (ttype) ! { char buf[128]; ! case 0: ! sql_files[0] = process_builtin(tpc_b); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 1 * tps); ! sql_files[0][1]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10 * tps); ! sql_files[0][2]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10000 * tps); ! sql_files[0][3]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! case 1: ! sql_files[0] = process_builtin(select_only); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! case 2: ! sql_files[0] = process_builtin(simple_update); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 1 * tps); ! sql_files[0][1]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10 * tps); ! sql_files[0][2]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10000 * tps); ! sql_files[0][3]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! default: ! break; ! } ! ! /* send start up queries in async manner */ ! for (i = 0; i < nclients; i++) ! { ! state[i].use_file = getrand(0, num_files - 1); ! doCustom(state, i, debug); ! } ! ! for (;;) ! { ! if (remains <= 0) ! { /* all done ? */ ! disconnect_all(state); ! /* get end time */ ! gettimeofday(&tv3, NULL); ! printResults(ttype, state, &tv1, &tv2, &tv3); ! if (LOGFILE) ! fclose(LOGFILE); ! exit(0); } ! FD_ZERO(&input_mask); ! maxsock = -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) { ! int sock = PQsocket(state[i].con); ! ! if (sock < 0) { disconnect_all(state); exit(1); } ! FD_SET(sock, &input_mask); ! if (maxsock < sock) ! maxsock = sock; } - } ! if (maxsock != -1) ! { ! if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL, ! (fd_set *) NULL, (struct timeval *) NULL)) < 0) { ! if (errno == EINTR) ! continue; ! /* must be something wrong */ ! disconnect_all(state); ! fprintf(stderr, "select failed: %s\n", strerror(errno)); ! exit(1); ! } ! else if (nsocks == 0) ! { /* timeout */ ! fprintf(stderr, "select timeout\n"); ! for (i = 0; i < nclients; i++) { ! fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n", ! i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen); } - exit(0); } } ! /* ok, backend returns reply */ ! for (i = 0; i < nclients; i++) ! { ! Command **commands = sql_files[state[i].use_file]; ! if (state[i].con && (FD_ISSET(PQsocket(state[i].con), &input_mask) ! || commands[state[i].state]->type == META_COMMAND)) ! { ! doCustom(state, i, debug); ! } } } } --- 1208,1493 ---- pghost, pgport, nclients, nxacts, dbName); } ! for (i = 0; i < nruns; i++) { ! int j; ! PGconn *con; ! PGresult *res; ! static CState *state; /* status of clients */ ! ! struct timeval tv1; /* start up time */ ! struct timeval tv2; /* after establishing all connections to the backend */ ! struct timeval tv3; /* end time */ ! ! remains = nclients; ! ! state = (CState *) malloc(sizeof(*state) * nclients); ! memset(state, 0, sizeof(*state) * nclients); ! ! /* opening connection... */ ! con = doConnect(); ! if (con == NULL) exit(1); ! if (PQstatus(con) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database '%s' failed.\n", dbName); fprintf(stderr, "%s", PQerrorMessage(con)); exit(1); } ! if (ttype != 3) { ! /* ! * get the scaling factor that should be same as count(*) from ! * branches if this is not a custom query ! */ ! res = PQexec(con, "select count(*) from branches"); ! if (PQresultStatus(res) != PGRES_TUPLES_OK) ! { ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); ! } ! tps = atoi(PQgetvalue(res, 0, 0)); ! if (tps < 0) ! { ! fprintf(stderr, "count(*) from branches invalid (%d)\n", tps); ! exit(1); ! } ! PQclear(res); } ! ! if (!is_no_vacuum) { ! fprintf(stderr, "starting vacuum..."); ! res = PQexec(con, "vacuum branches"); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) ! { ! fprintf(stderr, "%s", PQerrorMessage(con)); ! exit(1); ! } ! PQclear(res); ! ! res = PQexec(con, "vacuum tellers"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "%s", PQerrorMessage(con)); exit(1); } PQclear(res); + + res = PQexec(con, "delete from history"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "%s", PQerrorMessage(con)); + exit(1); + } + PQclear(res); + res = PQexec(con, "vacuum history"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "%s", PQerrorMessage(con)); + exit(1); + } + PQclear(res); + fprintf(stderr, "end.\n"); + + if (is_full_vacuum) + { + fprintf(stderr, "starting full vacuum..."); + res = PQexec(con, "vacuum analyze accounts"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "%s", PQerrorMessage(con)); + exit(1); + } + PQclear(res); + fprintf(stderr, "end.\n"); + } } ! PQfinish(con); ! ! /* set random seed */ ! gettimeofday(&tv1, NULL); ! srand((unsigned int) tv1.tv_usec); ! /* get start up time */ ! gettimeofday(&tv1, NULL); ! if (is_connect == 0) { ! /* make connections to the database */ ! for (j = 0; j < nclients; j++) ! { ! state[j].id = j; ! if ((state[j].con = doConnect()) == NULL) ! exit(1); ! } } ! /* time after connections set up */ ! gettimeofday(&tv2, NULL); ! /* process bultin SQL scripts */ ! switch (ttype) ! { char buf[128]; ! case 0: ! sql_files[0] = process_builtin(tpc_b); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 1 * tps); ! sql_files[0][1]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10 * tps); ! sql_files[0][2]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10000 * tps); ! sql_files[0][3]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! case 1: ! sql_files[0] = process_builtin(select_only); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! case 2: ! sql_files[0] = process_builtin(simple_update); ! snprintf(buf, sizeof(buf), "%d", 100000 * tps); ! sql_files[0][0]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 1 * tps); ! sql_files[0][1]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10 * tps); ! sql_files[0][2]->argv[3] = strdup(buf); ! snprintf(buf, sizeof(buf), "%d", 10000 * tps); ! sql_files[0][3]->argv[3] = strdup(buf); ! num_files = 1; ! break; ! default: ! break; } + + /* send start up queries in async manner */ + for (j = 0; j < nclients; j++) + { + state[j].use_file = getrand(0, num_files - 1); + doCustom(state, j, debug); + } + + for (;;) + { + if (remains <= 0) + { /* all done ? */ + int k; + double t1; + double t2; + int normal_xacts = 0; ! disconnect_all(state); ! /* get end time */ ! gettimeofday(&tv3, NULL); ! for (k = 0; k < nclients; k++) ! normal_xacts += state[k].cnt; ! t1 = (tv3.tv_sec - tv1.tv_sec) * 1000000.0 + (tv3.tv_usec - tv1.tv_usec); ! t1 = normal_xacts * 1000000.0 / t1; ! t1s[i] = t1; ! t1_total += t1; ! ! t2 = (tv3.tv_sec - tv2.tv_sec) * 1000000.0 + (tv3.tv_usec - tv2.tv_usec); ! t2 = normal_xacts * 1000000.0 / t2; ! t2s[i] = t2; ! t2_total += t2; ! ! printResults(ttype, state, t1, t2, normal_xacts, i); ! if (LOGFILE) ! fclose(LOGFILE); ! break; ! } ! ! FD_ZERO(&input_mask); ! ! maxsock = -1; ! for (j = 0; j < nclients; j++) ! { ! Command **commands = sql_files[state[j].use_file]; ! ! if (state[j].con && commands[state[j].state]->type != META_COMMAND) ! { ! int sock = PQsocket(state[j].con); ! ! if (sock < 0) ! { ! disconnect_all(state); ! exit(1); ! } ! FD_SET(sock, &input_mask); ! if (maxsock < sock) ! maxsock = sock; ! } ! } ! if (maxsock != -1) { ! if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL, ! (fd_set *) NULL, (struct timeval *) NULL)) < 0) { + if (errno == EINTR) + continue; + /* must be something wrong */ disconnect_all(state); + fprintf(stderr, "select failed: %s\n", strerror(errno)); exit(1); } ! else if (nsocks == 0) ! { /* timeout */ ! fprintf(stderr, "select timeout\n"); ! for (j = 0; j < nclients; j++) ! { ! fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n", ! j, state[j].state, state[j].cnt, state[j].ecnt, state[j].listen); ! } ! exit(0); ! } } ! /* ok, backend returns reply */ ! for (j = 0; j < nclients; j++) { ! Command **commands = sql_files[state[j].use_file]; ! ! if (state[j].con && (FD_ISSET(PQsocket(state[j].con), &input_mask) ! || commands[state[j].state]->type == META_COMMAND)) { ! doCustom(state, j, debug); } } } + } ! if( nruns > 1 ) { ! t1_mean = t1_total / nruns; ! for (i = 0; i < nruns; i++) { ! t1_variance += (t1s[i] - t1_mean) * (t1s[i] - t1_mean); ! } ! t1_stddev = sqrt(t1_variance/nruns); ! t2_mean = t2_total /nruns; ! for (i = 0; i < nruns; i++) { ! t2_variance += (t2s[i] - t2_mean) * (t2s[i] - t2_mean); } + t2_stddev = sqrt(t2_variance/nruns); + + printf("\n"); + printf("mean tps = %f (including connections establishing)\n", t1_mean); + printf("standard deviation = %f\n", t1_stddev); + printf("\n"); + printf("mean tps = %f (excluding connections establishing)\n", t2_mean); + printf("standard deviation = %f\n", t2_stddev); } + + exit(0); }