diff --git a/configure b/configure index 2821a8f7e4..c1ba3c1477 100755 --- a/configure +++ b/configure @@ -9053,6 +9053,62 @@ if test "$ac_res" != no; then : fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ppoll" >&5 +$as_echo_n "checking for library containing ppoll... " >&6; } +if ${ac_cv_search_ppoll+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ppoll (); +int +main () +{ +return ppoll (); + ; + return 0; +} +_ACEOF +for ac_lib in '' c; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_ppoll=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_ppoll+:} false; then : + break +fi +done +if ${ac_cv_search_ppoll+:} false; then : + +else + ac_cv_search_ppoll=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ppoll" >&5 +$as_echo "$ac_cv_search_ppoll" >&6; } +ac_res=$ac_cv_search_ppoll +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + # Solaris: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 $as_echo_n "checking for library containing fdatasync... " >&6; } @@ -12517,7 +12573,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l +for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll ppoll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index a1696db921..b0b24867a6 100644 --- a/configure.in +++ b/configure.in @@ -1058,6 +1058,7 @@ AC_SEARCH_LIBS(getopt_long, [getopt gnugetopt]) AC_SEARCH_LIBS(crypt, crypt) AC_SEARCH_LIBS(shm_open, rt) AC_SEARCH_LIBS(shm_unlink, rt) +AC_SEARCH_LIBS(ppoll, c) # Solaris: AC_SEARCH_LIBS(fdatasync, [rt posix4]) # Required for thread_test.c on Solaris @@ -1457,7 +1458,7 @@ PGAC_FUNC_WCSTOMBS_L LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) +AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll ppoll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) AC_REPLACE_FUNCS(fseeko) case $host_os in diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 163dcad137..9a6b95d05b 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -46,6 +46,9 @@ #ifdef HAVE_SYS_SELECT_H #include #endif +#ifdef HAVE_POLL_H +#include +#endif #ifdef HAVE_SYS_RESOURCE_H #include /* for getrlimit */ @@ -55,6 +58,10 @@ #define M_PI 3.14159265358979323846 #endif +#ifdef HAVE_PPOLL +#define USE_PPOLL 1 +#endif + #include "pgbench.h" #define ERRCODE_UNDEFINED_TABLE "42P01" @@ -89,6 +96,27 @@ static int pthread_join(pthread_t th, void **thread_return); #define MAXCLIENTS 1024 #endif +#ifdef USE_PPOLL +#define SCKTWTMTHD "ppoll" +#undef MAXCLIENTS +#define POLL_EVENTS (POLLIN|POLLPRI|POLLRDHUP) +#define POLL_FAIL (POLLERR|POLLHUP|POLLNVAL|POLLRDHUP) +#define PFD_CLREV(s) { do { if ((s)->pfdp) { ((s)->pfdp)->revents = 0; } } while(0); } +#define PFD_ZERO(s) { do { if ((s)->pfdp) { memset((s)->pfdp, 0, sizeof(struct pollfd)); } } while(0); } +#define PFD_SETFD(s) { do { ((s)->pfdp)->fd = PQsocket((s)->con); } while(0); } +#define PFD_STRUCT_POLLFD(p) struct pollfd (p); +#define PFD_THREAD_FREE(t) { do { if ((t)->pfds) { pg_free((t)->pfds); (t)->pfds = NULL; } } while (0); } +#define PFD_THREAD_INIT(t,s,n) { do { int _i; (t)->pfds = (struct pollfd *) pg_malloc0(sizeof(struct pollfd) * (n)); for (_i = 0; _i < (n); _i++) { (s)[_i].pfdp = &(t)->pfds[_i]; } } while (0); } +#else +#define SCKTWTMTHD "select" +#define PFD_CLREV(s) +#define PFD_ZERO(s) +#define PFD_SETFD(s) +#define PFD_STRUCT_POLLFD(p) +#define PFD_THREAD_FREE(t) +#define PFD_THREAD_INIT(t,s,n) +#endif + #define LOG_STEP_SECONDS 5 /* seconds between log messages */ #define DEFAULT_NXACTS 10 /* default nxacts */ @@ -259,6 +287,7 @@ typedef struct /* per client collected stats */ int64 cnt; /* transaction count */ int ecnt; /* error count */ + PFD_STRUCT_POLLFD(*pfdp) } CState; /* @@ -273,6 +302,7 @@ typedef struct unsigned short random_state[3]; /* separate randomness for each thread */ int64 throttle_trigger; /* previous/next throttling (us) */ FILE *logfile; /* where to log, or NULL */ + PFD_STRUCT_POLLFD(*pfds) /* per thread collected stats */ instr_time start_time; /* thread start time */ @@ -386,6 +416,7 @@ static void pgbench_error(const char *fmt,...) pg_attribute_printf(1, 2); static void addScript(ParsedScript script); static void *threadRun(void *arg); static void setalarm(int seconds); +static void finishCon(CState *st); /* callback functions for our flex lexer */ @@ -1734,11 +1765,7 @@ preparedStatementName(char *buffer, int file, int state) static bool clientDone(CState *st) { - if (st->con != NULL) - { - PQfinish(st->con); - st->con = NULL; - } + finishCon(st); return false; /* always false */ } @@ -1914,10 +1941,7 @@ top: if (commands[st->state + 1] == NULL) { if (is_connect) - { - PQfinish(st->con); - st->con = NULL; - } + finishCon(st); ++st->cnt; if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded) @@ -1968,6 +1992,7 @@ top: st->sleeping = false; st->throttling = false; memset(st->prepared, 0, sizeof(st->prepared)); + PFD_SETFD(st); } /* @@ -2315,13 +2340,7 @@ disconnect_all(CState *state, int length) int i; for (i = 0; i < length; i++) - { - if (state[i].con) - { - PQfinish(state[i].con); - state[i].con = NULL; - } - } + finishCon(&state[i]); } /* create tables and setup data */ @@ -3495,7 +3514,11 @@ main(int argc, char **argv) case 'c': benchmarking_option_set = true; nclients = atoi(optarg); +#ifdef USE_PPOLL + if (nclients <= 0 ) +#else if (nclients <= 0 || nclients > MAXCLIENTS) +#endif { fprintf(stderr, "invalid number of clients: \"%s\"\n", optarg); @@ -3756,6 +3779,14 @@ main(int argc, char **argv) } } + /* + * Don't need more threads than there are clients. (This is not merely an + * optimization; throttle_delay is calculated incorrectly below if some + * threads have no clients assigned to them.) + */ + if (nthreads > nclients) + nthreads = nclients; + /* set default script if none */ if (num_scripts == 0 && !is_init_mode) { @@ -3779,14 +3810,6 @@ main(int argc, char **argv) if (num_scripts > 1) per_script_stats = true; - /* - * Don't need more threads than there are clients. (This is not merely an - * optimization; throttle_delay is calculated incorrectly below if some - * threads have no clients assigned to them.) - */ - if (nthreads > nclients) - nthreads = nclients; - /* compute a per thread delay */ throttle_delay *= nthreads; @@ -4162,6 +4185,8 @@ threadRun(void *arg) } } + PFD_THREAD_INIT(thread, state, nstate); + if (!is_connect) { /* make connections to the database */ @@ -4169,6 +4194,7 @@ threadRun(void *arg) { if ((state[i].con = doConnect()) == NULL) goto done; + PFD_SETFD(&state[i]); } } @@ -4192,28 +4218,32 @@ threadRun(void *arg) fprintf(stderr, "client %d executing script \"%s\"\n", st->id, sql_script[st->use_file].desc); if (!doCustom(thread, st, &aggs)) + { remains--; /* I've aborted */ + PFD_ZERO(st); + } if (st->ecnt > prev_ecnt && commands[st->state]->type == META_COMMAND) { fprintf(stderr, "client %d aborted in state %d; execution of meta-command failed\n", i, st->state); remains--; /* I've aborted */ - PQfinish(st->con); - st->con = NULL; + finishCon(st); } } while (remains > 0) { - fd_set input_mask; int maxsock; /* max socket number to be waited */ int64 now_usec = 0; int64 min_usec; +#ifndef USE_PPOLL + fd_set input_mask; FD_ZERO(&input_mask); - maxsock = -1; +#endif + min_usec = PG_INT64_MAX; for (i = 0; i < nstate; i++) { @@ -4233,8 +4263,7 @@ threadRun(void *arg) remains--; st->sleeping = false; st->throttling = false; - PQfinish(st->con); - st->con = NULL; + finishCon(st); continue; } else /* just a nap from the script */ @@ -4267,10 +4296,16 @@ threadRun(void *arg) goto done; } +#ifdef USE_PPOLL + maxsock = 0; + (st->pfdp)->events = POLL_EVENTS; + (st->pfdp)->revents = 0; +#else FD_SET(sock, &input_mask); if (maxsock < sock) maxsock = sock; +#endif } /* also wake up to print the next progress report on time */ @@ -4302,20 +4337,32 @@ threadRun(void *arg) if (min_usec != PG_INT64_MAX) { +#ifdef USE_PPOLL + struct timespec timeout; + + timeout.tv_sec = min_usec / 1000000; + timeout.tv_nsec = min_usec % 1000000000; + nsocks = ppoll(thread->pfds, nstate, &timeout, NULL); +#else struct timeval timeout; timeout.tv_sec = min_usec / 1000000; timeout.tv_usec = min_usec % 1000000; nsocks = select(maxsock + 1, &input_mask, NULL, NULL, &timeout); +#endif } else +#ifdef USE_PPOLL + nsocks = ppoll(thread->pfds, nstate, NULL, NULL); +#else nsocks = select(maxsock + 1, &input_mask, NULL, NULL, NULL); +#endif if (nsocks < 0) { if (errno == EINTR) continue; /* must be something wrong */ - fprintf(stderr, "select() failed: %s\n", strerror(errno)); + fprintf(stderr, "%s() failed: %s\n", SCKTWTMTHD, strerror(errno)); goto done; } } @@ -4337,18 +4384,36 @@ threadRun(void *arg) PQerrorMessage(st->con)); goto done; } +#ifdef USE_PPOLL + if ((st->pfdp)->revents & POLL_FAIL) + { + fprintf(stderr, + "ppoll() fail - errno: %d, i: %d, events: %x\n", + errno, i, ((st->pfdp)->revents & POLL_FAIL)); + } + + if (((st->pfdp)->revents) || +#else if (FD_ISSET(sock, &input_mask) || +#endif commands[st->state]->type == META_COMMAND) { if (!doCustom(thread, st, &aggs)) + { remains--; /* I've aborted */ + PFD_ZERO(st); + } } + PFD_CLREV(st); } else if (is_connect && st->sleeping) { /* it is sleeping for throttling, maybe it is done, let us try */ if (!doCustom(thread, st, &aggs)) + { remains--; + PFD_ZERO(st); + } } if (st->ecnt > prev_ecnt && commands[st->state]->type == META_COMMAND) @@ -4356,8 +4421,7 @@ threadRun(void *arg) fprintf(stderr, "client %d aborted in state %d; execution of meta-command failed\n", i, st->state); remains--; /* I've aborted */ - PQfinish(st->con); - st->con = NULL; + finishCon(st); } } @@ -4460,9 +4524,21 @@ done: } fclose(thread->logfile); } + PFD_THREAD_FREE(thread); return NULL; } +static void +finishCon(CState *st) +{ + if (st->con) + { + PQfinish(st->con); + st->con = NULL; + } + PFD_ZERO(st); +} + /* * Support for duration option: set timer_exceeded after so many seconds. */ diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index a152371e61..83bfbfac47 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -393,6 +393,9 @@ /* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */ #undef HAVE_PPC_LWARX_MUTEX_HINT +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + /* Define to 1 if you have the `pstat' function. */ #undef HAVE_PSTAT